publishBuild

tcmts.cli.web.publishBuild · #lswnxyii · term · runs on the server

uses node:path

Put a build made in a directory of its own (staged, on the same filesystem) in its place, <apps>/<hash>/, at once: a rename. A build already there stays, unless replace says otherwise of it (another tcm's, or --force), and staged is dropped: a build is content-addressed, so it's the one this would be. One replaced is moved aside first (to aside, then removed), so a reader finds the old build or the new one, each whole. The manifest of the build in place.

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

export function publishBuild(
  apps: string,
  hash: string,
  staged: string,
  aside: string,
  replace: (there: BuildManifest) => boolean,
): BuildManifest {
  const to = path.join(apps, hash);
  const manifestIn = (dir: string) => {
    try {
      return JSON.parse(fs.readFileSync(path.join(dir, "tcm-app.json"), "utf8")) as BuildManifest;
    } catch {
      return undefined;
    }
  };
  const made = manifestIn(staged);
  if (!made) throw new Error(`${staged} holds no build`);
  fs.mkdirSync(apps, { recursive: true });
  for (let tries = 0; ; tries++) {
    try {
      fs.renameSync(staged, to);
      break;
    } catch (e) {
      const code = (e as NodeJS.ErrnoException).code;
      if (!["ENOTEMPTY", "EEXIST", "EPERM", "EACCES"].includes(code ?? "") || tries > 20) throw e;
    }
    // (one without a manifest is a build an older tcm left half-made)
    const there = manifestIn(to);
    if (there && !replace(there)) {
      fs.rmSync(staged, { recursive: true, force: true });
      return there;
    }
    // (another build may put its own in between: then that's looked at, as this one was)
    fs.rmSync(aside, { recursive: true, force: true });
    try {
      fs.renameSync(to, aside);
    } catch (e) {
      if ((e as NodeJS.ErrnoException).code !== "ENOENT") throw e;
    }
  }
  fs.rmSync(aside, { recursive: true, force: true });
  return made;
}

uses

used by