// Brackets the Runner package's `build` so server's prepare:runner-vendor can // reuse this build instead of repeating it when nothing has changed. See // build-inputs.mjs for what counts as an input and an output. // // --begin first step of the build: forgets the previous stamp and records // the inputs the build is about to read // --finish last step of the build, after every check: writes the stamp if // the inputs are still the ones the build began with, with a // manifest of every file under dist; otherwise writes nothing, so // the next consumer rebuilds // // Each build chain has its own pending record, named after the shell that // runs the chain (the parent of both phases), so two Runner builds running at // once in one checkout do not consume each other's record. // // Usage: node scripts/record-build-inputs.mjs (--begin | --finish) [--package-root ] // The package root defaults to this package; the flag exists for tests that // build a throwaway package layout. import path from "node:path"; import { fileURLToPath } from "node:url"; import { beginRunnerBuild, recordRunnerBuild, repoRootFromRunnerPackage, runnerPackageRootFromScripts, } from "./build-inputs.mjs"; export function parseArguments(argv) { let packageRoot = null; let phase = null; for (let index = 0; index < argv.length; index += 1) { const argument = argv[index]; if (argument === "--begin" || argument === "--finish") { if (phase) throw new Error(`${argument} cannot be combined with --${phase}`); phase = argument.slice(2); continue; } if (argument === "--package-root") { packageRoot = argv[index + 1]; if (!packageRoot) throw new Error("--package-root needs a directory"); index += 1; continue; } throw new Error(`unknown argument ${argument}`); } if (!phase) throw new Error("one of --begin or --finish is required"); return { phase, packageRoot }; } export function main(argv = process.argv.slice(2), log = console.log) { const { phase, packageRoot: requested } = parseArguments(argv); const packageRoot = requested ? path.resolve(requested) : runnerPackageRootFromScripts(); const repoRoot = repoRootFromRunnerPackage(packageRoot); if (phase === "begin") { const pending = beginRunnerBuild({ repoRoot, packageRoot }); log( `${pending.schema} begin: digest=${pending.digest.slice(0, 12)} files=${pending.fileCount} ` + `bytes=${pending.byteCount}`, ); return pending; } const record = recordRunnerBuild({ repoRoot, packageRoot }); if (!record.recorded) { log(`${record.code === "inputs_changed_during_build" ? "paperclip.runner-build-inputs" : record.code} not recorded: ${record.detail}`); return record; } log( `${record.schema} recorded: digest=${record.digest.slice(0, 12)} files=${record.fileCount} ` + `bytes=${record.byteCount} outputs=${record.outputCount} stamp=${path.relative(packageRoot, record.stampPath)}`, ); return record; } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { main(); }