// SPDX-FileCopyrightText: 2021 Johannes Loher // // SPDX-License-Identifier: MIT import { notifications } from "../ui/notifications.js"; import { logger } from "../utils/logger.js"; import { getGame } from "../utils/utils.js"; import { migration as migration001 } from "./001.js"; import { migration as migration002 } from "./002.js"; import { migration as migration003 } from "./003.js"; import { migration as migration004 } from "./004.js"; import { migration as migration005 } from "./005.js"; import { migration as migration006 } from "./006.js"; import { migration as migration007 } from "./007.js"; import { migration as migration008 } from "./008.js"; import { migration as migration009 } from "./009.js"; /** * Perform migrations. * @returns {Promise} A promise that resolves once all migrations have completed */ async function migrate() { if (!getGame().user?.isGM) { return; } const oldMigrationVersion = getCurrentMigrationVersion(); const targetMigrationVersion = migrations.length; if (isFirstWorldStart(oldMigrationVersion)) { getGame().settings.set("ds4", "systemMigrationVersion", targetMigrationVersion); return; } return migrateFromTo(oldMigrationVersion, targetMigrationVersion); } /** * Migrate from a given version to another version. * @param {number} oldMigrationVersion The old migration version * @param {number} targetMigrationVersion The migration version to migrate to * @returns {Promise} A promise the resolves once the migration is complete */ async function migrateFromTo(oldMigrationVersion, targetMigrationVersion) { if (!getGame().user?.isGM) { return; } const migrationsToExecute = migrations.slice(oldMigrationVersion, targetMigrationVersion); if (migrationsToExecute.length > 0) { notifications.info( getGame().i18n.format("DS4.InfoSystemUpdateStart", { currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, }), { permanent: true }, ); /** @type {Result} */ let result = "success"; for (const [i, { migrate }] of migrationsToExecute.entries()) { const currentMigrationVersion = oldMigrationVersion + i + 1; logger.info("executing migration script", currentMigrationVersion); try { const r = await migrate(); getGame().settings.set("ds4", "systemMigrationVersion", currentMigrationVersion); if (r === "error") { result = "error"; } } catch (err) { notifications.error( getGame().i18n.format("DS4.ErrorDuringMigration", { currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, migrationVersion: currentMigrationVersion, }), { permanent: true }, ); logger.error("Failed ds4 system migration:", err); return; } } if (result === "success") { notifications.info( getGame().i18n.format("DS4.InfoSystemUpdateCompletedSuccessfully", { currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, }), { permanent: true }, ); } else { notifications.warn( getGame().i18n.format("DS4.WarningSystemUpdateCompletedWithErrors", { currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, }), { permanent: true }, ); } } } /** * Migrate a compendium pack from a given version to another version. * @param {CompendiumCollection} pack The compendium pack to migrate * @param {number} oldMigrationVersion The old version number * @param {number} targetMigrationVersion The target version number * @returns {Promise} A promise that resolves once the migration is complete */ async function migrateCompendiumFromTo(pack, oldMigrationVersion, targetMigrationVersion) { if (!getGame().user?.isGM) { return; } const migrationsToExecute = migrations.slice(oldMigrationVersion, targetMigrationVersion); if (migrationsToExecute.length > 0) { notifications.info( getGame().i18n.format("DS4.InfoCompendiumMigrationStart", { pack: pack.title, currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, }), { permanent: true }, ); for (const [i, { migrateCompendium }] of migrationsToExecute.entries()) { const currentMigrationVersion = oldMigrationVersion + i + 1; logger.info("executing compendium migration ", currentMigrationVersion); try { await migrateCompendium(pack); } catch (err) { notifications.error( getGame().i18n.format("DS4.ErrorDuringCompendiumMigration", { pack: pack.title, currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, migrationVersion: currentMigrationVersion, }), { permanent: true }, ); logger.error("Failed ds4 compendium migration:", err); return; } } notifications.info( getGame().i18n.format("DS4.InfoCompendiumMigrationCompleted", { pack: pack.title, currentVersion: oldMigrationVersion, targetVersion: targetMigrationVersion, }), { permanent: true }, ); } } /** * Get the current migration version. * @returns {number} The current migration version */ function getCurrentMigrationVersion() { return getGame().settings.get("ds4", "systemMigrationVersion"); } /** * Get the target migration version. * @returns {number} The target migration version */ function getTargetMigrationVersion() { return migrations.length; } /** @typedef {"success" | "error"} Result */ /** * @typedef {object} Migration * @property {() => Promise} migrate * @property {import("./migrationHelpers").CompendiumMigrator} migrateCompendium */ /** * @type {Migration[]} */ const migrations = [ migration001, migration002, migration003, migration004, migration005, migration006, migration007, migration008, migration009, ]; /** * DOes the migration version indicate the world is being started for the first time? * @param {number} migrationVersion A migration version * @returns {boolean} Whether the migration version indicates it is the first start of the world */ function isFirstWorldStart(migrationVersion) { return migrationVersion < 0; } export const migration = { migrate, migrateFromTo, getCurrentMigrationVersion, getTargetMigrationVersion, migrateCompendiumFromTo, };