95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
import { existsSync, readFileSync, renameSync, rmSync } from "node:fs"
|
|
import { join, dirname, basename } from "node:path"
|
|
|
|
import { log } from "./logger"
|
|
import { getSidecarPath } from "./migration/migrations-sidecar"
|
|
import { CONFIG_BASENAME, LEGACY_CONFIG_BASENAME } from "./plugin-identity"
|
|
import { writeFileAtomically } from "./write-file-atomically"
|
|
|
|
function buildCanonicalPath(legacyPath: string): string {
|
|
const dir = dirname(legacyPath)
|
|
const ext = basename(legacyPath).includes(".jsonc") ? ".jsonc" : ".json"
|
|
return join(dir, `${CONFIG_BASENAME}${ext}`)
|
|
}
|
|
|
|
function archiveLegacyConfigFile(legacyPath: string): boolean {
|
|
const backupPath = `${legacyPath}.bak`
|
|
|
|
try {
|
|
renameSync(legacyPath, backupPath)
|
|
log("[migrateLegacyConfigFile] Legacy config was migrated and renamed to backup. Update the canonical file only.", {
|
|
legacyPath,
|
|
backupPath,
|
|
})
|
|
return true
|
|
} catch (renameError) {
|
|
try {
|
|
rmSync(legacyPath)
|
|
log("[migrateLegacyConfigFile] Legacy config was migrated and removed after backup rename failed. Update the canonical file only.", {
|
|
legacyPath,
|
|
backupPath,
|
|
renameError,
|
|
})
|
|
return true
|
|
} catch (removeError) {
|
|
log("[migrateLegacyConfigFile] WARNING: canonical config was written but the legacy file still exists and will be ignored. Remove or rename it manually.", {
|
|
legacyPath,
|
|
backupPath,
|
|
renameError,
|
|
removeError,
|
|
})
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
function migrateLegacySidecarFile(legacyPath: string, canonicalPath: string): boolean {
|
|
const legacySidecarPath = getSidecarPath(legacyPath)
|
|
if (!existsSync(legacySidecarPath)) return true
|
|
|
|
const canonicalSidecarPath = getSidecarPath(canonicalPath)
|
|
if (existsSync(canonicalSidecarPath)) return true
|
|
|
|
try {
|
|
const content = readFileSync(legacySidecarPath, "utf-8")
|
|
writeFileAtomically(canonicalSidecarPath, content)
|
|
log("[migrateLegacyConfigFile] Migrated legacy migration sidecar to canonical path", {
|
|
from: legacySidecarPath,
|
|
to: canonicalSidecarPath,
|
|
})
|
|
return true
|
|
} catch (error) {
|
|
log("[migrateLegacyConfigFile] Failed to migrate legacy migration sidecar", {
|
|
legacySidecarPath,
|
|
canonicalSidecarPath,
|
|
error,
|
|
})
|
|
return false
|
|
}
|
|
}
|
|
|
|
export function migrateLegacyConfigFile(legacyPath: string): boolean {
|
|
if (!existsSync(legacyPath)) return false
|
|
if (!basename(legacyPath).startsWith(LEGACY_CONFIG_BASENAME)) return false
|
|
|
|
const canonicalPath = buildCanonicalPath(legacyPath)
|
|
if (existsSync(canonicalPath)) return false
|
|
|
|
try {
|
|
const content = readFileSync(legacyPath, "utf-8")
|
|
writeFileAtomically(canonicalPath, content)
|
|
const migratedSidecar = migrateLegacySidecarFile(legacyPath, canonicalPath)
|
|
const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath)
|
|
log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
|
|
from: legacyPath,
|
|
to: canonicalPath,
|
|
migratedSidecar,
|
|
archivedLegacyConfig,
|
|
})
|
|
return true
|
|
} catch (error) {
|
|
log("[migrateLegacyConfigFile] Failed to migrate legacy config file", { legacyPath, error })
|
|
return false
|
|
}
|
|
}
|