/** * 统一的数据来源解析。 * * 两种来源: * 默认 读取 mysqldump 导出的 .sql(适合本地,无需连旧库) * --from-db 直连旧库读取(适合服务器,旧库就在本机) * * check 与 migrate 共用,避免两边各写一遍参数解析。 */ import { existsSync } from 'node:fs'; import { DEFAULT_DUMP_PATH, loadLegacyDump, type LegacyRows } from './load'; import { loadLegacyDb } from './load-db'; /** * 载入 .env 到 process.env。 * * 工具脚本不像服务端那样会自己读 .env,必须显式加载, * 否则 LEGACY_DATABASE_URL / DATABASE_URL 读不到。 * Node 20.12+ 内置该方法,不需要 dotenv。 */ export function ensureEnvLoaded(): void { try { process.loadEnvFile('.env'); } catch { // 文件不存在时忽略:环境变量可能由外部注入(如 PM2 / Docker) } } export interface LoadedSource { rows: LegacyRows; /** 用于日志展示的数据来源描述(连接串中的密码已脱敏) */ label: string; } /** 连接串脱敏,避免把密码打进日志。 */ function maskUrl(url: string): string { return url.replace(/(:\/\/[^:]+):[^@]*@/, '$1:***@'); } export async function loadLegacyFromArgs(argv: string[]): Promise { if (argv.includes('--from-db')) { const url = process.env.LEGACY_DATABASE_URL ?? ''; if (!url) { throw new Error( '使用 --from-db 需要先配置 LEGACY_DATABASE_URL。\n' + '请在 yelaymaths_api/.env 中填写旧库连接串,例如:\n' + ' LEGACY_DATABASE_URL="mysql://用户:密码@127.0.0.1:3306/api_yeomai_site"', ); } return { rows: await loadLegacyDb(url), label: `旧库直连 ${maskUrl(url)}` }; } const dumpIndex = argv.indexOf('--dump'); const dumpPath = dumpIndex >= 0 ? (argv[dumpIndex + 1] ?? DEFAULT_DUMP_PATH) : DEFAULT_DUMP_PATH; if (!existsSync(dumpPath)) { throw new Error( `找不到旧库导出文件:${dumpPath}\n\n` + '两种解决办法,任选其一:\n' + ' 1) 直接连旧库读取(推荐,服务器上旧库就在本机):\n' + ' 在命令末尾加 --from-db,并确保 .env 里配好了 LEGACY_DATABASE_URL\n' + ' 2) 把旧库导出文件放到上面这个路径,或用 --dump <路径> 指定位置\n\n' + ' 导出命令示例:\n' + ' mysqldump -u 用户 -p api_yeomai_site > /tmp/api_yeomai_site.sql', ); } return { rows: loadLegacyDump(dumpPath), label: dumpPath }; }