Files
reverse-skills-max/vendor-new/xbsReverseSkill/web-js-env-patcher/scripts/install_ruyipage_runtime.js

188 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
function parseArgs(argv) {
const args = { python: 'python', installDir: '', install: false, installPackage: false, json: false, markdown: false };
for (let i = 2; i < argv.length; i++) {
const a = argv[i];
if (a === '--python') args.python = argv[++i] || 'python';
else if (a === '--install-dir') args.installDir = argv[++i] || '';
else if (a === '--install') args.install = true;
else if (a === '--install-package') args.installPackage = true;
else if (a === '--json') args.json = true;
else if (a === '--markdown') args.markdown = true;
else if (a === '--help' || a === '-h') args.help = true;
else throw new Error(`未知参数:${a}`);
}
if (!args.json && !args.markdown) args.markdown = true;
return args;
}
function usage() {
return `用法:
node scripts/install_ruyipage_runtime.js --python python --install-dir <ruyipage-browsers-dir> --markdown
node scripts/install_ruyipage_runtime.js --python python --install-dir <ruyipage-browsers-dir> --install --markdown
node scripts/install_ruyipage_runtime.js --python python --install-dir <ruyipage-browsers-dir> --install-package --install --markdown
说明:默认只输出安装计划,不执行下载 / 安装。只有用户明确确认并提供安装目录后,才添加 --install。
注意:--install-package 会修改当前 Python 环境,必须先获得用户确认。`;
}
function run(cmd, args, timeout = 120000) {
const ret = spawnSync(cmd, args, { encoding: 'utf8', timeout, windowsHide: true });
return {
ok: ret.status === 0,
status: ret.status,
stdout: (ret.stdout || '').trim(),
stderr: (ret.stderr || '').trim(),
error: ret.error ? ret.error.message : '',
command: [cmd].concat(args.map(quoteIfNeeded)).join(' '),
};
}
function quoteIfNeeded(s) {
s = String(s);
return /\s/.test(s) ? `"${s.replace(/"/g, '\\"')}"` : s;
}
function exists(p) {
try { return !!p && fs.existsSync(p); } catch { return false; }
}
function checkPackage(python) {
const code = 'import ruyipage, json; print(json.dumps({"ok": True, "version": getattr(ruyipage, "__version__", "")}, ensure_ascii=False))';
const ret = run(python, ['-c', code], 20000);
if (!ret.ok) return { ok: false, version: '', error: ret.stderr || ret.error || ret.stdout };
try {
const parsed = JSON.parse(ret.stdout.replace(/^\uFEFF/, ''));
return { ok: true, version: parsed.version || '', error: '' };
} catch (err) {
return { ok: false, version: '', error: err.message || String(err) };
}
}
function assertInstallDir(dir) {
if (!dir) throw new Error('必须提供 --install-dir;不要在未确认目录时安装 ruyiPage 定制 Firefox runtime。');
const resolved = path.resolve(dir);
const parsed = path.parse(resolved);
if (resolved === parsed.root) throw new Error('安装目录不能是磁盘根目录。请提供专用目录,例如 <工作目录>/tools/ruyipage-browsers。');
return resolved;
}
function verifyAfterInstall(python, installDir) {
const script = path.join(__dirname, 'check_external_tools.js');
const ret = run(process.execPath, [script, '--python', python, '--ruyipage-install-dir', installDir, '--json'], 60000);
let parsed = null;
try { parsed = JSON.parse(ret.stdout.replace(/^\uFEFF/, '')); } catch { parsed = null; }
return { command: ret.command, ok: ret.ok, stdout: ret.stdout, stderr: ret.stderr || ret.error, parsed };
}
function commandPlan(args, installDir, pkg) {
const commands = [];
if (!pkg.ok) commands.push(`${args.python} -m pip install ruyiPage requests --upgrade`);
else commands.push(`${args.python} -m pip install requests --upgrade`);
commands.push(`${args.python} -m ruyipage install --install-dir "${installDir}"`);
commands.push(`node scripts/check_external_tools.js --python ${args.python} --ruyipage-install-dir "${installDir}" --markdown`);
return commands;
}
function main() {
const args = parseArgs(process.argv);
if (args.help) return { help: usage() };
const installDir = assertInstallDir(args.installDir);
const pkgBefore = checkPackage(args.python);
const result = {
dryRun: !args.install,
python: args.python,
installDir,
packageBefore: pkgBefore,
packageInstallAttempted: false,
runtimeInstallAttempted: false,
commands: commandPlan(args, installDir, pkgBefore),
steps: [],
verify: null,
success: false,
};
if (!args.install) {
result.steps.push('当前为安装计划,不执行下载或安装。请用户确认后再添加 --install。');
result.success = true;
return result;
}
fs.mkdirSync(installDir, { recursive: true });
let pkg = pkgBefore;
if (!pkg.ok && args.installPackage) {
result.packageInstallAttempted = true;
const pip = run(args.python, ['-m', 'pip', 'install', 'ruyiPage', 'requests', '--upgrade'], 180000);
result.steps.push(`安装 ruyiPage Python 包与 requests 依赖:${pip.ok ? '成功' : '失败'}\n${pip.stdout || pip.stderr || pip.error}`.trim());
pkg = checkPackage(args.python);
} else if (pkg.ok && args.installPackage) {
result.packageInstallAttempted = true;
const pip = run(args.python, ['-m', 'pip', 'install', 'requests', '--upgrade'], 180000);
result.steps.push(`安装 / 更新 smart_fingerprint requests 依赖:${pip.ok ? '成功' : '失败'}\n${pip.stdout || pip.stderr || pip.error}`.trim());
}
if (!pkg.ok) {
result.steps.push('未安装 ruyiPage Python 包,已停止 runtime 安装。若用户确认允许修改 Python 环境,请重新添加 --install-package。');
result.verify = verifyAfterInstall(args.python, installDir);
result.success = false;
return result;
}
result.runtimeInstallAttempted = true;
const install = run(args.python, ['-m', 'ruyipage', 'install', '--install-dir', installDir], 900000);
result.steps.push(`安装 ruyiPage 定制 Firefox runtime:${install.ok ? '成功' : '失败'}\n${install.stdout || install.stderr || install.error}`.trim());
result.verify = verifyAfterInstall(args.python, installDir);
result.success = !!(result.verify && result.verify.parsed && result.verify.parsed.ruyiPage && result.verify.parsed.ruyiPage.managedRuntimeVerified);
return result;
}
function renderMarkdown(result) {
if (result.help) return result.help + '\n';
const lines = ['# ruyiPage 定制 Firefox runtime 安装流程', ''];
lines.push(`- dry-run:${result.dryRun ? '是' : '否'}`);
lines.push(`- Python:${result.python}`);
lines.push(`- 安装目录:${result.installDir}`);
lines.push(`- ruyiPage Python 包:${result.packageBefore.ok ? '已安装' : '未检测到'}`);
if (result.packageBefore.version) lines.push(`- ruyiPage 版本:${result.packageBefore.version}`);
lines.push('', '## 将执行 / 已执行的命令');
for (const cmd of result.commands) lines.push('- `' + cmd + '`');
if (result.steps.length) {
lines.push('', '## 执行记录');
for (const step of result.steps) lines.push(`- ${step.replace(/\n/g, '\n ')}`);
}
if (result.verify) {
lines.push('', '## 安装后验证');
lines.push('- 验证命令:`' + result.verify.command + '`');
lines.push(`- 验证命令是否成功:${result.verify.ok ? '是' : '否'}`);
const rp = result.verify.parsed && result.verify.parsed.ruyiPage;
if (rp) {
lines.push(`- 定制 Firefox runtime 是否通过验证:${rp.managedRuntimeVerified ? '是' : '否'}`);
if (rp.runtimeExecutable) lines.push(`- 已验证 Firefox:${rp.runtimeExecutable}`);
if (rp.conclusion) lines.push(`- 结论:${rp.conclusion}`);
} else if (result.verify.stderr) {
lines.push(`- 验证错误:${result.verify.stderr}`);
}
}
lines.push('', `## 结果:${result.success ? '通过' : '未通过 / 待用户确认'}`);
if (result.dryRun) lines.push('- 当前仅输出计划;若用户确认未安装并提供该目录,再运行带 --install 的命令。');
return lines.join('\n') + '\n';
}
try {
const args = parseArgs(process.argv);
const result = args.help ? { help: usage() } : main();
if (args.json) console.log(JSON.stringify(result, null, 2));
if (args.markdown) process.stdout.write(renderMarkdown(result));
} catch (err) {
console.error(err.message || String(err));
console.error(usage());
process.exit(1);
}