Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118#!/usr/bin/env bash# KEEP THE STAGED APPLICATIONS ALIVE, because /tmp is swept by AGE and the prefixes live there.## WHY THIS EXISTS. systemd-tmpfiles deletes files under /tmp once they are old enough and leaves the# directory tree standing. The applications are staged into /tmp/cider-<tag>-1000/prefix and are the# one part of a prefix that cannot be rebuilt: the runtime comes from buck-out, the applications came# from a download.## It has now happened twice. On 2026-09-01 every bundle was hollowed out (#169). On 2026-09-19 it# took ONE file, iTermServer, and that was worse: the bundle still looked present to every ordinary# check, iTerm2 still started, and what it produced was a terminal with no shell plus a crash three# frames deep in NSFileManager. It cost an A/B against an innocent commit to find, and the file could# not be restored because no iTerm2 source archive was left on the machine either.## A MAIN EXECUTABLE SURVIVES AND ITS NEIGHBOURS DO NOT, which is what makes the damage so uneven:# every run reads the main binary and that keeps it young, while an auxiliary binary that is only# copied once ages out on schedule.## scripts/app-keep-warm.sh touch everything, print a count per application# scripts/app-keep-warm.sh --check compare against the recorded inventory, exit 1 on a loss# scripts/app-keep-warm.sh --write re-record the inventory from what is on disk now## The touch is cheap: 993 files over seven applications when this was written.set -uo pipefail
here=$(cd "$(dirname "$0")" && pwd)inventory="$here/app-inventory.txt"mode=touchcase "${1:-}" in--check) mode=check ;;--write) mode=write ;;"") ;;*) echo "usage: $0 [--check|--write]" >&2 exit 2 ;;esac
apps() { # One directory per staged application, whatever prefixes exist right now. find /tmp -maxdepth 4 -type d -path '/tmp/cider-*-1000/prefix/Applications' 2>/dev/null | sort}
tag_of() { # /tmp/cider-XX-1000/prefix/Applications -> XX printf '%s\n' "$1" | sed -E 's|^/tmp/cider-([^-]+)-1000/.*$|\1|'}
# The list is RELATIVE to the Applications directory, so it is comparable across machines.list_one() { (cd "$1" && find . -type f 2>/dev/null | sort)}
case "$mode" intouch) total=0 while read -r dir; do [ -n "$dir" ] || continue tag=$(tag_of "$dir") # -a and -m both, because a sweep may be configured on either. n=$(find "$dir" -type f -exec touch -a -m {} + -print 2>/dev/null | wc -l) total=$((total + n)) echo "$tag warmed=$n" done < <(apps) echo "WARMED $total files across the staged applications" ;;write) : >"$inventory" { echo "# What each staged application is supposed to contain, relative to its Applications" echo "# directory. Recorded so that a file DELETED BY THE /tmp SWEEP is caught as a missing" echo "# file rather than as a mysterious application failure three frames deep." echo "#" echo "# NOT A CLEAN BASELINE FOR it: iTermServer had ALREADY been swept when this was first" echo "# written, and no source archive remained to restore it, so the iTerm2 list here is the" echo "# damaged tree. Re-record it after a real re-stage." } >>"$inventory" while read -r dir; do [ -n "$dir" ] || continue tag=$(tag_of "$dir") while read -r f; do echo "$tag|$f" >>"$inventory" done < <(list_one "$dir") done < <(apps) echo "recorded $(grep -vc '^#' "$inventory") files in $inventory" ;;check) if [ ! -f "$inventory" ]; then echo "no inventory at $inventory; run --write first" >&2 exit 2 fi missing=0 while read -r dir; do [ -n "$dir" ] || continue tag=$(tag_of "$dir") have=$(mktemp) want=$(mktemp) list_one "$dir" >"$have" grep "^$tag|" "$inventory" | sed "s|^$tag||;s|^||" | cut -d'|' -f2- >"$want" # Only a LOSS is a failure. An extra file is an application writing state and is expected. gone=$(comm -13 "$have" "$want" | wc -l) if [ "$gone" -gt 0 ]; then echo "FAIL $tag is missing $gone file(s) from the recorded inventory:" comm -13 "$have" "$want" | head -10 | sed 's/^/ /' missing=$((missing + gone)) else echo "ok $tag" fi rm -f "$have" "$want" done < <(apps) if [ "$missing" -gt 0 ]; then echo "FAILED: $missing staged file(s) have gone. /tmp is swept by AGE; see scripts/app-stage.sh." exit 1 fi echo "PASS: every recorded staged file is still present" ;;esac