shipCodebase

tcmts.cli.pack.shipCodebase · #h67snwm2 · term · runs on the server

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;
}

uses

used by