managed-data-migration.mjs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { existsSync } from 'node:fs'
  2. import { homedir } from 'node:os'
  3. import { join } from 'node:path'
  4. import { LaunchAgentService } from './service-update.mjs'
  5. import { defaultDataHome, legacyDataHome } from './data-home.mjs'
  6. import { migrateDataHome, rebaseDataPath } from './data-migration.mjs'
  7. export async function migrateManagedDataHome({ home, port = 15300, onProgress = () => {}, beforeMove }) {
  8. if (home !== defaultDataHome()) return
  9. const old = legacyDataHome(), releaseRoot = join(homedir(), '.local', 'share', 'hermes-yaoyao')
  10. let previous, driver
  11. if (existsSync(old)) {
  12. driver = new LaunchAgentService({ home: old, port, releaseRoot })
  13. previous = driver.snapshot()
  14. if (previous) {
  15. onProgress('正在等待旧服务空闲,准备迁移数据到 ~/.yaoyao…')
  16. await driver.quiesce(onProgress, 0)
  17. await driver.stop()
  18. }
  19. }
  20. try {
  21. if (existsSync(old)) await beforeMove?.(old)
  22. migrateDataHome(home)
  23. } catch (error) {
  24. if (previous && existsSync(old)) await driver.restore(previous)
  25. throw error
  26. }
  27. // Also recover a crash between the atomic rename and the LaunchAgent rewrite.
  28. if (!existsSync(home)) return
  29. const currentDriver = new LaunchAgentService({ home, port, releaseRoot })
  30. if (!previous && existsSync(join(home, '.data-home-migration.json')) && existsSync(currentDriver.plistPath)) {
  31. const { execFileSync } = await import('node:child_process')
  32. const plist = JSON.parse(execFileSync('/usr/bin/plutil', ['-convert', 'json', '-o', '-', currentDriver.plistPath], { encoding: 'utf8' }))
  33. if (plist.EnvironmentVariables?.HERMES_YAOYAO_HOME === old) previous = { plist, wasRunning: true }
  34. }
  35. if (previous) {
  36. for (const [key, value] of Object.entries(previous.plist.EnvironmentVariables ?? {})) previous.plist.EnvironmentVariables[key] = rebaseDataPath(value, old, home)
  37. previous.plist.EnvironmentVariables.HERMES_YAOYAO_HOME = home
  38. previous.plist.EnvironmentVariables.YAOYAO_HOME = home
  39. for (const field of ['StandardOutPath', 'StandardErrorPath']) previous.plist[field] = rebaseDataPath(previous.plist[field], old, home)
  40. currentDriver.writePlist(previous.plist)
  41. if (previous.wasRunning) { await currentDriver.boot(); await currentDriver.verify(undefined) }
  42. onProgress('账号、会话、文件和配置已迁移到 ~/.yaoyao')
  43. }
  44. }