import fs from 'fs' import path from 'path' import { spawnSync } from 'child_process' import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const electronRoot = path.resolve(__dirname, '..') const backendRoot = path.resolve(electronRoot, '..') const pythonCandidates = [ path.join(backendRoot, 'python', 'python.exe'), path.join(backendRoot, 'python', 'Scripts', 'python.exe'), ] const web2Py = path.join(backendRoot, 'web2.py') const ffmpegCandidates = [ path.join(backendRoot, 'ffmpeg', 'ffmpeg.exe'), path.join(backendRoot, 'ffmpeg', 'bin', 'ffmpeg.exe'), path.join(backendRoot, 'tools', 'ffmpeg', 'ffmpeg.exe'), path.join(backendRoot, 'tools', 'ffmpeg', 'bin', 'ffmpeg.exe'), ] const errors = [] if (!fs.existsSync(web2Py)) { errors.push(`缺少后端入口文件: ${web2Py}`) } const pythonExe = pythonCandidates.find((p) => fs.existsSync(p)) ?? null if (!pythonExe) { errors.push(`缺少内置 Python(任一路径即可):\n- ${pythonCandidates[0]}\n- ${pythonCandidates[1]}`) } // venv 结构在跨机器分发时可能依赖构建机本地 Python,不可作为懒人包运行时。 if (fs.existsSync(path.join(backendRoot, 'python', 'pyvenv.cfg'))) { errors.push( `检测到 venv 运行时(${path.join( backendRoot, 'python', 'pyvenv.cfg', )})。该结构不保证跨机器可用,请改为可分发的独立 Python Runtime(嵌入式/便携式)。`, ) } const ffmpegExe = ffmpegCandidates.find((p) => fs.existsSync(p)) ?? null if (!ffmpegExe) { errors.push( `缺少 ffmpeg.exe(以下任一路径都可):\n${ffmpegCandidates.map((p) => `- ${p}`).join('\n')}`, ) } if (pythonExe) { const check = spawnSync( pythonExe, [ '-c', 'import importlib.util,fastapi,uvicorn,requests,psutil,src; assert importlib.util.find_spec("web2"); print("runtime_ok")', ], { cwd: backendRoot, encoding: 'utf8', windowsHide: true, timeout: 30000, }, ) if (check.status !== 0) { errors.push( `内置 Python 缺少运行依赖或无法导入后端模块(fastapi/uvicorn/requests/psutil/web2/src)。\n请先在 ${path.join( backendRoot, 'python', )} 环境安装 requirements.txt。\n\nstdout:\n${check.stdout || '(empty)'}\n\nstderr:\n${check.stderr || '(empty)'}`, ) } } if (errors.length) { console.error('[verify:runtime] 运行时检查失败:\n') for (const e of errors) console.error(`- ${e}\n`) process.exit(1) } const st = spawnSync('node', [path.join(__dirname, 'stage-offline-runtime.mjs')], { cwd: electronRoot, stdio: 'inherit', }) if (st.status !== 0) { console.error('[verify:runtime] 生成 offline-runtime 镜像失败') process.exit(1) } console.log('[verify:runtime] OK: 内置 Python/依赖/ffmpeg 已就绪,offline-runtime 已同步。')