pruneCache

tcmts.cli.compact.pruneCache · #jok4lh44 · term · runs on the server

uses node:fs

Remove from .tcm/cache what no branch can use, all of it made again when it's needed: the modules of code no branch names nor uses (past versions), with what rendered.json says of them; tcm run's runners; and the apps suites packed, untouched for a day. Only what wasn't written in the last hour goes: a check in another process writes modules of code it hasn't saved, and imports them. How many files went, and their bytes.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import fs from "node:fs";
import path from "node:path";

export function pruneCache(cb: Codebase): { files: number; bytes: number } {
  const dir = cb.lay.cacheDir;
  const live = cb.store.liveComponents();
  const now = Date.now();
  let files = 0;
  let bytes = 0;
  const gone = (file: string, age: number): boolean => {
    const s = fs.statSync(file, { throwIfNoEntry: false });
    if (!s || now - s.mtimeMs < age) return false;
    if (s.isDirectory()) {
      for (const f of fs.readdirSync(file, { recursive: true, withFileTypes: true }))
        if (f.isFile()) {
          files++;
          bytes += fs.statSync(path.join(f.parentPath, f.name)).size;
        }
    } else {
      files++;
      bytes += s.size;
    }
    fs.rmSync(file, { recursive: true, force: true });
    return true;
  };
  const hour = 60 * 60 * 1000;
  for (const f of fs.existsSync(dir) ? fs.readdirSync(dir) : []) {
    const m = /^(run_)?([a-z2-7]{52})\.tsx?$/.exec(f);
    if (m && (m[1] || !live.has(m[2]!))) gone(path.join(dir, f), hour);
  }
  const apps = path.join(dir, "apps");
  for (const f of fs.existsSync(apps) ? fs.readdirSync(apps) : [])
    gone(path.join(apps, f), 24 * hour);
  // (what's left of a module is all rendered.json needs: one gone is rendered again whatever it says)
  const stamps = path.join(dir, "rendered.json");
  try {
    const rendered = JSON.parse(fs.readFileSync(stamps, "utf8")) as Record<string, string>;
    for (const c of Object.keys(rendered))
      if (
        !live.has(c) &&
        !fs.existsSync(path.join(dir, `${c}.ts`)) &&
        !fs.existsSync(path.join(dir, `${c}.tsx`))
      )
        delete rendered[c];
    const part = `${stamps}.${process.pid}`;
    fs.writeFileSync(part, JSON.stringify(rendered));
    fs.renameSync(part, stamps);
  } catch {
    // (none, or cut short: materialize renders what it doesn't know)
  }
  return { files, bytes };
}

uses

used by