86 lines
2.9 KiB
JavaScript
86 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const inventoryPath = path.join(root, "config", "imported-packages.json");
|
|
const inventory = JSON.parse(readFileSync(inventoryPath, "utf8"));
|
|
const [command, requestedName, ...rest] = process.argv.slice(2);
|
|
|
|
function usage(message) {
|
|
if (message) console.error(message);
|
|
console.error(
|
|
"Usage:\n" +
|
|
" bun scripts/import-package-snapshots.mjs check [name|all]\n" +
|
|
" bun scripts/import-package-snapshots.mjs stage <name|all> --output <empty-directory>",
|
|
);
|
|
process.exit(2);
|
|
}
|
|
|
|
if (!command || !["check", "stage"].includes(command)) usage();
|
|
const selection = requestedName ?? "all";
|
|
const packages =
|
|
selection === "all"
|
|
? inventory.packages
|
|
: inventory.packages.filter((entry) => entry.name === selection);
|
|
if (packages.length === 0) usage(`Unknown imported package: ${selection}`);
|
|
|
|
function remoteCommit(entry) {
|
|
const output = execFileSync(
|
|
"git",
|
|
["ls-remote", entry.source, `refs/heads/${entry.branch}`],
|
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] },
|
|
).trim();
|
|
const [commit] = output.split(/\s+/u);
|
|
if (!/^[0-9a-f]{40}$/u.test(commit ?? "")) {
|
|
throw new Error(`No ${entry.branch} branch returned for ${entry.name}`);
|
|
}
|
|
return commit;
|
|
}
|
|
|
|
if (command === "check") {
|
|
let stale = false;
|
|
for (const entry of packages) {
|
|
const current = remoteCommit(entry);
|
|
const status = current === entry.commit ? "current" : "update available";
|
|
console.log(`${entry.name}: ${status} (${entry.commit.slice(0, 7)} -> ${current.slice(0, 7)})`);
|
|
stale ||= current !== entry.commit;
|
|
}
|
|
process.exitCode = stale ? 1 : 0;
|
|
} else {
|
|
const outputIndex = rest.indexOf("--output");
|
|
const outputArg = outputIndex >= 0 ? rest[outputIndex + 1] : undefined;
|
|
if (!outputArg) usage("stage requires --output <empty-directory>");
|
|
const outputRoot = path.resolve(root, outputArg);
|
|
if (existsSync(outputRoot)) usage(`Output already exists: ${outputRoot}`);
|
|
mkdirSync(outputRoot, { recursive: true });
|
|
|
|
for (const entry of packages) {
|
|
const destination = path.join(outputRoot, entry.name);
|
|
execFileSync(
|
|
"git",
|
|
[
|
|
"clone",
|
|
"--quiet",
|
|
"--depth",
|
|
"1",
|
|
"--single-branch",
|
|
"--branch",
|
|
entry.branch,
|
|
entry.source,
|
|
destination,
|
|
],
|
|
{ stdio: "inherit" },
|
|
);
|
|
const commit = execFileSync("git", ["-C", destination, "rev-parse", "HEAD"], {
|
|
encoding: "utf8",
|
|
}).trim();
|
|
rmSync(path.join(destination, ".git"), { recursive: true, force: true });
|
|
rmSync(path.join(destination, "package-lock.json"), { force: true });
|
|
console.log(`${entry.name}: staged ${commit} at ${destination}`);
|
|
}
|
|
}
|