import { cp, mkdir, rm, stat, writeFile } from 'node:fs/promises'; import { spawn } from 'node:child_process'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const scriptDir = dirname(fileURLToPath(import.meta.url)); const repoRoot = join(scriptDir, '..', '..'); const buildDir = join(scriptDir, 'build'); const publicDir = join(repoRoot, 'public', 'vendor', 'opencascade'); const image = process.env.OPENCASCADE_JS_DOCKER_IMAGE || 'donalffons/opencascade.js'; const yaml = 'opencascade.yml'; await mkdir(buildDir, { recursive: true }); await cp(join(scriptDir, yaml), join(buildDir, yaml)); const dockerArgs = [ 'run', '--rm', '-v', `${buildDir}:/src`, '-u', `${process.getuid?.() ?? 1000}:${process.getgid?.() ?? 1000}`, image, yaml, ]; console.log(`building ${yaml} with ${image}`); await run('docker', dockerArgs); await stageArtifacts(); async function stageArtifacts() { const js = join(buildDir, 'opencascade.js'); const wasm = join(buildDir, 'opencascade.wasm'); await assertFile(js); await assertFile(wasm); await mkdir(publicDir, { recursive: true }); await cp(js, join(publicDir, 'opencascade.js')); await cp(wasm, join(publicDir, 'opencascade.wasm')); await rm(join(publicDir, 'opencascade.step.js'), { force: true }); await rm(join(publicDir, 'opencascade.step.wasm'), { force: true }); await rm(join(publicDir, 'opencascade.step.worker.js'), { force: true }); await rm(join(publicDir, 'opencascade.worker.js'), { force: true }); await writeFile( join(publicDir, 'README.txt'), [ 'Local OpenCascade.js STEP conversion artifacts.', 'Generated by tools/renderer-step/build-and-stage-opencascade.mjs.', 'Single-threaded build: no pthread sidecar and no cross-origin isolation requirement.', 'Generated/ignored; do not commit.', '', ].join('\n'), ); console.log(`staged OpenCascade.js STEP artifacts into ${publicDir}`); } async function assertFile(path) { const info = await stat(path); if (!info.isFile() || info.size === 0) { throw new Error(`expected non-empty file at ${path}`); } } function run(command, args) { return new Promise((resolve, reject) => { const child = spawn(command, args, { stdio: 'inherit' }); child.on('error', reject); child.on('close', (code, signal) => { if (code === 0) { resolve(); } else { reject(new Error(`${command} exited with ${signal || code}`)); } }); }); }