Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 605cd6e51a17989d0f968ce4e7eae5bec8d7a321
parent 9babe0ee3ff820042c1b64655f8e298ea1a60877
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  1 Oct 2026 16:41:19 -0400

umtool: MEDIA_ROOT beside REPORTS_ROOT; CACHE_DIR moves to the user cache

UMTOOL_MEDIA_DIR names where a project's render scratch (out/) lives; unset,
MEDIA_ROOT is REPORTS_ROOT and nothing changes. MEDIA_TIERED says they differ;
mediaMirror(abs) is a project's path under it. MEDIA_ROOT joins READ_ROOTS,
never WRITE_ROOTS. CACHE_DIR is UMTOOL_CACHE_DIR, else
$XDG_CACHE_HOME/archilyzer/umtool (~/.cache when unset), no longer under
SONG_DATA; OLD_CACHE_DIR names the old place for umtool doctor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mumtool/lib/paths.mjs | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mumtool/lib/paths.ts | 4++++
2 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/umtool/lib/paths.mjs b/umtool/lib/paths.mjs @@ -14,9 +14,25 @@ import { SONG_DATA, SONG_REPORTS } from "../song/paths.mjs"; // record paths relative to it (make-thumb, accept-thumb) import only siblings. export { SONG_DATA, SONG_REPORTS }; -// Derived output (sliced mp3s, waveform peaks, the project index). Lives with -// the data, not in the repo, and is safe to delete at any time. -export const CACHE_DIR = path.join(SONG_DATA, ".cache", "umtool"); +// Derived output (sliced mp3s, waveform peaks, the project index, posters, the +// mix bench's analyses). Not in the repo, and safe to delete at any time. +// +// It used to live under SONG_DATA (`<SONG_DIR>/.cache/umtool`), which tied +// every project's index and every report's derived files to wherever the song +// project's 39 GB happened to sit -- a report-only machine, or one whose song +// data is on a drive that is not mounted, had its cache follow it there +// (release 17). It is a cache, so it goes where caches go: +// `UMTOOL_CACHE_DIR`, else `$XDG_CACHE_HOME/archilyzer/umtool` (an empty +// XDG_CACHE_HOME is unset, as common/lib/paths.ts reads it), else +// `~/.cache/archilyzer/umtool`. Nothing is migrated: the first `umtool index` +// rebuilds the index there, and every other file is re-made on demand. +// OLD_CACHE_DIR is only for `umtool doctor`, which reports a leftover one. +const XDG_CACHE = process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache"); +export const CACHE_DIR = path.resolve( + /* turbopackIgnore: true */ + process.env.UMTOOL_CACHE_DIR || path.join(/* turbopackIgnore: true */ XDG_CACHE, "archilyzer", "umtool"), +); +export const OLD_CACHE_DIR = path.join(/* turbopackIgnore: true */ SONG_DATA, ".cache", "umtool"); /** * A file in CACHE_DIR, by name. A route names its cache files through this @@ -61,6 +77,51 @@ export const REPORTS_ROOT = path.resolve( const dedupe = (list) => [...new Set(list.map((p) => path.resolve(p)))]; // --------------------------------------------------------------------------- +// MEDIA_ROOT -- where a project's RENDER SCRATCH (`out/`) lives (release 17). +// +// A report project's manifest, revisions/, notes and sources are small text and +// stay under REPORTS_ROOT. Its `out/` -- fetched windows, segments, the +// deliverable, ~18 of the 20 GB in ~/reports -- is bulk that can be re-made, +// and belongs on a media drive. With UMTOOL_MEDIA_DIR set, a project's `out` is +// an absolute SYMLINK to the same project-relative path under it: +// +// <REPORTS_ROOT>/<folder>/<project>/out -> <MEDIA_ROOT>/<folder>/<project>/out +// +// made by the first writer (lib/report/storage.mjs ensureOutDir) or moved there +// by `umtool storage move-out`. Every reader keeps opening `<project>/out/...` +// by path; the link is the only place the media drive is named. +// +// UNSET, MEDIA_ROOT is REPORTS_ROOT, MEDIA_TIERED is false, and nothing changes: +// `out/` is a plain directory in the project, as it always was. +// +// MEDIA_ROOT is READABLE (a realpath taken through a project's `out` link lands +// under it -- the deck preview's confinement check is one) and never WRITABLE by +// a client-named path: what a render may write to is still WRITE_ROOTS. +// --------------------------------------------------------------------------- +export const MEDIA_ROOT = path.resolve( + /* turbopackIgnore: true */ + process.env.UMTOOL_MEDIA_DIR || REPORTS_ROOT, +); + +/** True when render scratch goes to a media root of its own. */ +export const MEDIA_TIERED = MEDIA_ROOT !== REPORTS_ROOT; + +/** + * Where `abs` (a path under REPORTS_ROOT) is mirrored under MEDIA_ROOT, or null + * when it is not under REPORTS_ROOT -- a project somewhere else is never tiered. + * Pure: it never touches the disk. The roots are parameters so a test can name + * its own; the defaults are the process's. + */ +export function mediaMirror(abs, { reportsRoot = REPORTS_ROOT, mediaRoot = MEDIA_ROOT } = {}) { + const rel = path.relative( + /* turbopackIgnore: true */ path.resolve(/* turbopackIgnore: true */ reportsRoot), + path.resolve(/* turbopackIgnore: true */ abs), + ); + if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel)) return null; + return path.join(/* turbopackIgnore: true */ path.resolve(/* turbopackIgnore: true */ mediaRoot), rel); +} + +// --------------------------------------------------------------------------- // READ vs WRITE, and why they are two lists. // // resolveInRoots() guards both what may be OPENED and what may be RENDERED TO. @@ -148,7 +209,7 @@ export const CHANNELS_DIR = path.resolve( export const READ_ROOTS = dedupe( process.env.MIX_ROOTS ? process.env.MIX_ROOTS.split(":").filter(Boolean) - : [SONG_REPORTS, REPORTS_ROOT, SONG_DATA, SONG_SCRATCH, CHANNELS_DIR], + : [SONG_REPORTS, REPORTS_ROOT, SONG_DATA, SONG_SCRATCH, CHANNELS_DIR, MEDIA_ROOT], ); export const WRITE_ROOTS = dedupe( diff --git a/umtool/lib/paths.ts b/umtool/lib/paths.ts @@ -8,6 +8,7 @@ import path from "node:path"; // SONG_REPORTS the um-song deliverables -- quartering-*.mp4 and their .plan.json // SONG_SCRATCH render scratch, ABOVE SONG_DATA // REPORTS_ROOT the tree every PROJECT hangs off -- songs AND report videos +// MEDIA_ROOT where a project's out/ is linked to (UMTOOL_MEDIA_DIR); = REPORTS_ROOT when unset // // Everything the bench reads or writes must resolve inside one of these. Not // because this is exposed -- it is a local tool on a loopback port -- but @@ -21,7 +22,9 @@ export { CACHE_DIR, cacheFile, INDEX_DIR, + MEDIA_ROOT, MEDIA_ROOTS, + MEDIA_TIERED, MIX_CACHE, READ_ROOTS, REPORTS_ROOT, @@ -31,6 +34,7 @@ export { WRITE_ROOTS, inside, labelFor, + mediaMirror, resolveInRoots, } from "./paths.mjs";