The reset itself has been master's behaviour since9df9688(remote-run.sh checkout_tree: git checkout -- . and git clean of the overlay files, target dirs and stamps kept, before the branch checkout); the UI lane met the class again from worktrees whose tools predate it (remote-run.sh is piped to the box from each worktree per build). The check reads checkout_tree() and fails when the reset and the clean do not both come before the branch checkout; self-test: the real script passes, a copy without the reset fails, the same lines moved after the checkout fail. cargo-audit: already owned by provision.sh step_cargo_tools (b2262e5), confirmed ok (0.22.2) on the box; nothing added. Gate GREEN, 33 checks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
47 lines
3.8 KiB
Bash
Executable file
47 lines
3.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# The stale-overlay class (6 October 2026, the PC 1 worker at 18:4x UTC, the UI lane twice later the same night): tools/build-remote.sh
|
|
# rsyncs a worktree's uncommitted files over the box's checkout; once those files are committed and HEAD moves, the next run's
|
|
# `git checkout -B <branch> <sha>` on the box refuses with "Your local changes would be overwritten" and nothing builds until
|
|
# someone clears the tree by hand. Rule: the remote checkout RESETS the working tree first (`git checkout -- .` and a `git clean`
|
|
# of the untracked overlay files, target dirs and stamps kept), then checks the branch out; the overlay re-applies the Mac's
|
|
# working-tree state afterwards anyway. The code lives in infra/build-server/remote-run.sh checkout_tree() and is piped to the box
|
|
# from each Mac worktree per build, so a worktree whose tools predate the fix keeps the old behaviour until it has master.
|
|
# This check reads checkout_tree() and fails when the reset and the clean do not both come BEFORE the branch checkout.
|
|
#
|
|
# tools/ci/mirror-reset-check.sh # exit 1 with the reason
|
|
# tools/ci/mirror-reset-check.sh --self-test # the real script passes; a copy with the reset lines removed fails
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/../.."
|
|
check() { # <file>: exit 0 when checkout_tree resets and cleans before the branch checkout
|
|
local f="$1" body reset clean co
|
|
body=$(sed -n '/^checkout_tree()/,/^}/p' "$f")
|
|
[ -n "$body" ] || { echo "mirror-reset: $f has no checkout_tree() function"; return 1; }
|
|
reset=$(printf '%s\n' "$body" | grep -nE '^\s*git checkout -q -- \.' | head -1 | cut -d: -f1)
|
|
clean=$(printf '%s\n' "$body" | grep -nE '^\s*git clean -q?f' | head -1 | cut -d: -f1)
|
|
co=$(printf '%s\n' "$body" | grep -nE '^\s*git checkout -q -B ' | head -1 | cut -d: -f1)
|
|
[ -n "$co" ] || { echo "mirror-reset: $f: no branch checkout (git checkout -q -B) in checkout_tree"; return 1; }
|
|
[ -n "$reset" ] && [ "$reset" -lt "$co" ] || { echo "mirror-reset: $f: no 'git checkout -- .' before the branch checkout (line $co of checkout_tree)"; return 1; }
|
|
[ -n "$clean" ] && [ "$clean" -lt "$co" ] || { echo "mirror-reset: $f: no 'git clean' of the overlay before the branch checkout (line $co of checkout_tree)"; return 1; }
|
|
printf '%s\n' "$body" | grep -qE "git clean .*-e target" || { echo "mirror-reset: $f: the clean must keep target dirs (-e target)"; return 1; }
|
|
echo "mirror-reset: $f resets (line $reset) and cleans (line $clean) before the branch checkout (line $co)"
|
|
}
|
|
if [ "${1:-}" = --self-test ]; then
|
|
t=$(mktemp -d); trap 'rm -rf "$t"' EXIT
|
|
check infra/build-server/remote-run.sh >/dev/null || { echo "mirror-reset self-test: the real script FAILED the check"; exit 1; }
|
|
grep -vE '^\s*git (checkout -q -- \.|clean -q?f)' infra/build-server/remote-run.sh > "$t/no-reset.sh"
|
|
if check "$t/no-reset.sh" >/dev/null 2>&1; then echo "mirror-reset self-test: a script without the reset PASSED (the check is blind)"; exit 1; fi
|
|
# the order matters: the same lines after the branch checkout must fail too
|
|
python3 - infra/build-server/remote-run.sh "$t/wrong-order.sh" <<'PY'
|
|
import re, sys
|
|
s = open(sys.argv[1]).read()
|
|
body = re.search(r'^checkout_tree\(\).*?^}', s, flags=re.S | re.M).group(0)
|
|
lines = body.split("\n"); moved = [l for l in lines if re.match(r'\s*git (checkout -q -- \.|clean -q?f)', l)]
|
|
rest = [l for l in lines if l not in moved]
|
|
i = next(k for k, l in enumerate(rest) if re.match(r'\s*git checkout -q -B ', l))
|
|
rest[i + 1:i + 1] = moved
|
|
open(sys.argv[2], "w").write(s.replace(body, "\n".join(rest)))
|
|
PY
|
|
if check "$t/wrong-order.sh" >/dev/null 2>&1; then echo "mirror-reset self-test: a reset AFTER the branch checkout PASSED (the check ignores order)"; exit 1; fi
|
|
echo "mirror-reset self-test: the real script passes; no reset fails; reset after the checkout fails"; exit 0
|
|
fi
|
|
check infra/build-server/remote-run.sh
|