45 lines
3.4 KiB
JavaScript
45 lines
3.4 KiB
JavaScript
import fs from 'node:fs/promises';
|
||
import path from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
import { createHash } from 'node:crypto';
|
||
import { execFileSync } from 'node:child_process';
|
||
import { assertPiNodeVersion } from '../src/runtime-policy.mjs';
|
||
|
||
// A local portable build. Never copy a profile, credential, project or request journal.
|
||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||
const [binaryArg, destinationArg, nodeArg = process.execPath, licenseArg] = process.argv.slice(2);
|
||
if (!binaryArg || !destinationArg) throw Error('指定已验证的原生程序与新的输出目录');
|
||
const destination = path.resolve(destinationArg), binary = path.resolve(binaryArg), node = path.resolve(nodeArg);
|
||
if (destination === root || destination.startsWith(root + path.sep) || !path.isAbsolute(binary)) throw Error('输出目录必须独立于源码');
|
||
const version = execFileSync(node, ['--version'], { encoding: 'utf8', windowsHide: true }).trim();
|
||
assertPiNodeVersion(version);
|
||
await fs.mkdir(path.dirname(destination), { recursive: true });
|
||
await fs.mkdir(destination); // Refuse to overwrite an existing client or user data.
|
||
await fs.copyFile(binary, path.join(destination, 'photocraft.exe'));
|
||
const agent = path.join(destination, 'agent');
|
||
await fs.mkdir(agent);
|
||
await fs.copyFile(node, path.join(agent, 'node.exe'));
|
||
const nodeLicense = licenseArg ? path.resolve(licenseArg) : path.join(path.dirname(node), 'LICENSE');
|
||
await fs.copyFile(nodeLicense, path.join(agent, 'LICENSE-Node.txt'));
|
||
for (const file of ['package.json', 'package-lock.json']) await fs.copyFile(path.join(root, file), path.join(agent, file));
|
||
for (const directory of ['src', 'node_modules']) await fs.cp(path.join(root, directory), path.join(agent, directory), { recursive: true, dereference: true });
|
||
const native = path.resolve(root, '../detail-photocraft');
|
||
for (const file of ['LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE', 'ATTRIBUTION.md']) await fs.copyFile(path.join(native, file), path.join(destination, file));
|
||
await fs.writeFile(path.join(destination, '启动客户端.cmd'), '@echo off\r\nstart "" "%~dp0photocraft.exe"\r\n', 'utf8');
|
||
await fs.writeFile(path.join(destination, '本地构建说明.txt'), `由壹点详情页本地开发构建\r\n双击“启动客户端.cmd”。Agent运行组件已随包提供,无需另装Node。\r\n账户、个人Key、项目与会话保存在当前Windows用户的独立配置和凭据库,不在本目录内。\r\n本包未签名,尚不是正式安装程序。Node ${version};Pi SDK 1.3.0。\r\n`, 'utf8');
|
||
const files = [];
|
||
async function inventory(dir) {
|
||
for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
|
||
const file = path.join(dir, entry.name);
|
||
if (entry.isDirectory()) await inventory(file);
|
||
else {
|
||
const bytes = await fs.readFile(file);
|
||
files.push({ path: path.relative(destination, file).replaceAll('\\', '/'), bytes: bytes.length, sha256: createHash('sha256').update(bytes).digest('hex') });
|
||
}
|
||
}
|
||
}
|
||
await inventory(destination);
|
||
const manifest = { at: new Date().toISOString(), kind: 'unsigned-local-development-portable', node: version, pi: '1.3.0', bytes: files.reduce((sum, file) => sum + file.bytes, 0), files };
|
||
await fs.writeFile(path.join(destination, 'build-manifest.json'), JSON.stringify(manifest, null, 2));
|
||
console.log(JSON.stringify({ destination, files: files.length, bytes: manifest.bytes, node: version, pi: manifest.pi }));
|