/** * Staleness helper for build-infra's `packageNetapp` (cli/build.ts). * * Before celilo#1258 build-infra repackaged all 37 modules on every run * (about 5 minutes to reach a 38 second test) because nothing reused a * current .netapp. publishModule's reuse of the staged netapp is a separate * fix that landed from ce-nvd8 (bf05c946) and keeps its own probe. */ import { execSync } from 'node:child_process'; import { existsSync } from 'node:fs'; /** * True when `netappPath` exists and nothing that ships in the package has * changed under `sourceDir` since it was written. * * `find -newer -quit` asks the filesystem instead of walking in JS and stops * at the first newer file. A staleness check that cannot answer repackages: * reusing on an inconclusive result is how a test silently runs against a * stale module. * * Only paths the package actually contains can make it stale. `e2e/` is * excluded from a module package wholesale and `node_modules/.bin` is excluded * from the hook runtime closure — see `classifyModulePath` and * `includeNodeModulesPath` in apps/celilo/src/module/packaging/, which are the * authority. They are restated rather than imported because packages/e2e has * no import path into apps/celilo, and registry-server's bootstrap.ts already * carries the same duplication for the same reason. * * Both subtrees are excluded at the DIRECTORY level as well as the file * level (path suffixes `e2e` and `node_modules/.bin`, with and without a * trailing component): a directory's mtime moves whenever an entry inside * it is created or replaced, so `bun install` recreating the binlinks in a * module's `e2e/node_modules/.bin` would otherwise mark every module * permanently dirty through the dir entry alone. * * Getting these wrong is safe in one direction only, and it is this one: * counting a non-packaged path makes us repackage needlessly (slow), while * MISSING a packaged path would reuse a stale netapp (wrong). Every exclusion * here is a path the packager does not ship, so it cannot cause the latter. */ export function isNetappCurrent(netappPath: string, sourceDir: string): boolean { if (!existsSync(netappPath)) return false; // Each exclude needs both the bare dir and its contents: `find -newer` // matches the directory's own mtime too, and creating or replacing an // entry inside moves it. const excludes = [ "-not -path '*/e2e'", "-not -path '*/e2e/*'", "-not -path '*/node_modules/.bin'", "-not -path '*/node_modules/.bin/*'", ]; try { const newer = execSync( `find ${JSON.stringify(sourceDir)} -newer ${JSON.stringify(netappPath)} ${excludes.join(' ')} -print -quit`, { encoding: 'utf-8', timeout: 30_000 }, ).trim(); return newer === ''; } catch { return false; // a check that cannot answer repackages } }