import { parseArgs } from "node:util"; import manifest from "./subtrees.json"; interface Subtree { readonly name: string; readonly prefix: string; readonly upstream: string; readonly ref: string; readonly squash: true; readonly role: string; readonly refreshPolicy: "allowed" | "pinned"; } interface CommandResult { readonly exitCode: number; readonly stdout: string; readonly stderr: string; } const cwd = process.cwd(); const subtrees = manifest.subtrees as readonly Subtree[]; const run = async ( command: readonly string[], options: { readonly inherit?: boolean } = {} ): Promise => { const process = Bun.spawn([...command], { cwd, stdin: options.inherit ? "inherit" : "ignore", stdout: options.inherit ? "inherit" : "pipe", stderr: options.inherit ? "inherit" : "pipe", }); const [exitCode, stdout, stderr] = await Promise.all([ process.exited, options.inherit ? Promise.resolve("") : new Response(process.stdout).text(), options.inherit ? Promise.resolve("") : new Response(process.stderr).text(), ]); return { exitCode, stdout, stderr }; }; const shellQuote = (value: string) => `'${value.replaceAll("'", `'\\''`)}'`; const formatCommand = (command: readonly string[]) => command.map(shellQuote).join(" "); const requireRepositoryRoot = async () => { const result = await run(["git", "rev-parse", "--show-toplevel"]); if (result.exitCode !== 0) { throw new Error("The current directory is not inside a Git checkout."); } if (result.stdout.trim() !== cwd) { throw new Error( `Run this script from the repository root: ${result.stdout.trim()}` ); } }; const requireCleanWorktree = async () => { const result = await run(["git", "status", "--porcelain"]); if (result.exitCode !== 0) { throw new Error(result.stderr.trim()); } if (result.stdout.trim() !== "") { throw new Error( "Subtree mutations require a clean worktree. Commit or stash changes first." ); } }; const getSubtree = (name: string | undefined) => { if (name === undefined) { throw new Error( `A subtree name is required. Available: ${subtrees.map((entry) => entry.name).join(", ")}` ); } const subtree = subtrees.find((entry) => entry.name === name); if (subtree === undefined) { throw new Error( `Unknown subtree ${shellQuote(name)}. Available: ${subtrees.map((entry) => entry.name).join(", ")}` ); } if ( !subtree.prefix.startsWith("repos/") || !subtree.upstream.startsWith("https://") ) { throw new Error( `Unsafe subtree manifest entry ${shellQuote(subtree.name)}.` ); } return subtree; }; const readSubtreeMetadata = async (subtree: Subtree) => { const merge = await run([ "git", "log", "--all", "-n", "1", "--format=%H%x09%ci%x09%s", "--", subtree.prefix, ]); if (merge.exitCode !== 0) { throw new Error(merge.stderr.trim()); } const mergeLine = merge.stdout.trim(); if (mergeLine === "") { return { mergeLine: "No subtree merge found", split: undefined }; } const mergeSha = mergeLine.split("\t")[0]; if (mergeSha === undefined) { return { mergeLine, split: undefined }; } const squash = await run([ "git", "show", "--no-patch", "--format=%b", `${mergeSha}^2`, ]); const split = squash.stdout .split("\n") .find((line) => line.startsWith("git-subtree-split: ")) ?.slice("git-subtree-split: ".length); return { mergeLine, split }; }; const readStatus = async (subtree: Subtree) => { const [dirty, metadata] = await Promise.all([ run(["git", "status", "--porcelain", "--", subtree.prefix]), readSubtreeMetadata(subtree), ]); if (dirty.exitCode !== 0) { throw new Error(dirty.stderr.trim()); } return { dirty: dirty.stdout.trim() !== "", latest: metadata.mergeLine, }; }; const updateCommand = (subtree: Subtree) => [ "git", "subtree", "pull", `--prefix=${subtree.prefix}`, subtree.upstream, subtree.ref, "--squash", ]; const addCommand = (subtree: Subtree) => [ "git", "subtree", "add", `--prefix=${subtree.prefix}`, subtree.upstream, subtree.ref, "--squash", ]; const { values, positionals } = parseArgs({ args: process.argv.slice(2), options: { "dry-run": { type: "boolean", default: false }, "force-pinned": { type: "boolean", default: false }, help: { type: "boolean", short: "h", default: false }, yes: { type: "boolean", short: "y", default: false }, }, allowPositionals: true, strict: true, }); const [operation = "list", name, ...extra] = positionals; if (values.help || extra.length > 0) { console.log(`Usage: bun run subtree [list|status|preview|add|update] [name] [options] Commands: list List configured vendored subtrees status [name] Show local subtree metadata and dirtiness preview Fetch the configured upstream and show incoming commits add Add an absent manifest entry with git subtree add --squash update Pull a configured subtree with git subtree pull --squash Options: --dry-run Print mutating/fetch commands without executing them --yes, -y Required for add and update --force-pinned Allow updating a pinned historical subtree together with --yes`); process.exit(extra.length > 0 ? 1 : 0); } try { await requireRepositoryRoot(); switch (operation) { case "list": { for (const subtree of subtrees) { console.log( `${subtree.name}\t${subtree.prefix}\t${subtree.upstream}#${subtree.ref}\t${subtree.refreshPolicy}` ); } break; } case "status": { const selected = name === undefined ? subtrees : [getSubtree(name)]; for (const subtree of selected) { const status = await readStatus(subtree); console.log(`${subtree.name}:`); console.log(` prefix: ${subtree.prefix}`); console.log(` upstream: ${subtree.upstream}#${subtree.ref}`); console.log(` policy: ${subtree.refreshPolicy}`); console.log(` prefix dirty: ${status.dirty ? "yes" : "no"}`); console.log(` latest metadata: ${status.latest}`); } break; } case "preview": { const subtree = getSubtree(name); const fetch = [ "git", "fetch", "--no-tags", subtree.upstream, subtree.ref, ]; if (values["dry-run"]) { console.log(formatCommand(fetch)); console.log( formatCommand([ "git", "log", "--oneline", "--decorate", "..FETCH_HEAD", ]) ); break; } const fetched = await run(fetch, { inherit: true }); if (fetched.exitCode !== 0) { process.exit(fetched.exitCode); } const metadata = await readSubtreeMetadata(subtree); if (metadata.split === undefined) { throw new Error( `No git-subtree-split metadata found for ${subtree.prefix}.` ); } const log = await run([ "git", "log", "--oneline", "--decorate", `${metadata.split}..FETCH_HEAD`, ]); if (log.exitCode !== 0) { throw new Error(log.stderr.trim()); } console.log(log.stdout.trim() || `${subtree.name} is up to date.`); break; } case "add": case "update": { const subtree = getSubtree(name); const prefixType = await run([ "git", "cat-file", "-t", `HEAD:${subtree.prefix}`, ]); const prefixExists = prefixType.exitCode === 0 && prefixType.stdout.trim() === "tree"; if ( operation === "update" && subtree.refreshPolicy === "pinned" && !values["force-pinned"] ) { throw new Error( `${subtree.name} is pinned historical reference material. Pass --force-pinned --yes only when historical synchronization is explicitly required.` ); } if (!values["dry-run"]) { await requireCleanWorktree(); } if (operation === "add" && prefixExists) { throw new Error( `Cannot add ${subtree.name}: ${subtree.prefix} already exists.` ); } if (operation === "update" && !prefixExists) { throw new Error( `Cannot update ${subtree.name}: ${subtree.prefix} does not exist.` ); } const command = operation === "add" ? addCommand(subtree) : updateCommand(subtree); console.log(formatCommand(command)); if (values["dry-run"]) { break; } if (!values.yes) { throw new Error( `Refusing to ${operation} without --yes. Re-run after reviewing the command above.` ); } const result = await run(command, { inherit: true }); if (result.exitCode !== 0) { process.exit(result.exitCode); } break; } default: throw new Error( `Unknown command ${shellQuote(operation)}. Use list, status, preview, add, or update.` ); } } catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exit(1); }