Hwaro::Utils::FileSafe
Class methods
Write content to path atomically: write to a same-directory
temp file, then rename over the target. hwaro serve rewrites
output files while HTTP fibers stream them to the browser — a plain
File.write truncates first, so a request landing mid-rebuild could
read an empty or half-written page. Rename is atomic on the same
filesystem, so readers see either the old bytes or the new bytes.
The temp name is unique per process AND fiber so parallel render workers writing sibling outputs can't collide on it.
Equivalent to FileUtils.mkdir_p but tolerates concurrent creation
of any path component. Safe to call from MT workers without an
external mutex.
We walk parents ourselves so EEXIST is absorbed per component.
Crystal's Dir.mkdir_p is exists? → mkdir for each parent and the
leaf, so two workers calling mkdir_p("/out/a/b/x") and
mkdir_p("/out/a/b/y") can race on every shared parent
(/out, /out/a, /out/a/b). A single retry of the whole call
isn't enough: the retry's parent walk can re-race on a different
shared parent, raise again, and a post-hoc Dir.exists?(leaf) check
is false because we never reached the leaf — so the EEXIST bubbles
out and a render fails ("Unable to create directory: '…': File
exists"). Tolerating EEXIST per component avoids the cascade.