shipCodebase
uses node:fs
A codebase of its own holding only what roots use, everything it runs on pinned as here, named by name, written
to out/codebase.sqlite: what a package ships of the codebase (its apps, its libraries). Says how many definitions
it holds.
import { Codebase } from "#codebase/tcmts/cli/codebase"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; export function shipCodebase( cb: Codebase, roots: string[], out: string, name: (target: Codebase) => void, ): number { // every component it needs, what each uses before it (as a receiver checks them) const comps = [...cb.closureComponents(roots)]; const placed = new Set<string>(); const ordered: string[] = []; const place = (c: string) => { if (placed.has(c)) return; placed.add(c); for (const m of cb.store.componentMembers(c)) for (const d of m.deps) { const dep = d.ref.startsWith("#") ? cb.store.getDef(d.ref.slice(1))?.componentHash : undefined; if (dep && dep !== c) place(dep); } ordered.push(c); }; for (const c of comps) place(c); const membersOf = (c: string) => cb.store.componentMembers(c).map((m) => cb.store.defWithText(m.hash, undefined)!); const records = ordered.flatMap(membersOf); const work = fs.mkdtempSync(path.join(os.tmpdir(), "tcm-ship-")); // (the codebase made here is its own: not this process's session branch) const session = process.env.TCM_BRANCH; delete process.env.TCM_BRANCH; try { const target = Codebase.init(work); target.adoptPackages(cb.packagesUsedBy(records)); // (whole components at a time, as a receiver takes them) let batch: typeof records = []; for (const c of ordered) { batch.push(...membersOf(c)); if (batch.length >= 2000) (target.receive(batch), (batch = [])); } if (batch.length) target.receive(batch); name(target); target.store.close(); fs.mkdirSync(out, { recursive: true }); fs.copyFileSync(path.join(work, ".tcm", "codebase.sqlite"), path.join(out, "codebase.sqlite")); } finally { if (session !== undefined) process.env.TCM_BRANCH = session; fs.rmSync(work, { recursive: true, force: true }); } return records.length; }