83 lines
5.3 KiB
Bash
Executable file
83 lines
5.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# The engine gate, as a script instead of as the integrator's memory.
|
|
#
|
|
# Why this exists: for a whole day the gate reported 59/59 while the two tests that read
|
|
# the save corpus were SKIPPING, because SOTS_SAVES_DIR was never set on CT111. The corpus
|
|
# had grown from 22 to 43 saves and the coverage ratchet had broken exactly as rule 27 says
|
|
# it should -- and a writer defect had appeared on 12 of them -- and the gate could not see
|
|
# either. A green verdict on a harness that is comparing nothing (rule 1), delivered by the
|
|
# person whose job was to notice it.
|
|
#
|
|
# Each check is its own command and its own exit code. Nothing here is &&-chained across
|
|
# checks, because a chain that short-circuits reports a check that never ran (rule 22's
|
|
# cousin, paid for once already).
|
|
#
|
|
# Usage: tools/gate.sh [--fresh] --fresh: rm -rf the remote build dirs first (rule 24)
|
|
set -u
|
|
|
|
# One gate at a time. Lane DW saw up to FOUR `gate.sh --fresh` runs concurrently, all rsyncing
|
|
# into the same remote tree and rm -rf'ing its build dirs -- rule 24's shape with no lock, and a
|
|
# way to report a build that is half someone else's. Every lane runs from this host, so a local
|
|
# flock is sufficient. Waits up to 30 min, then fails loudly rather than running unlocked.
|
|
if [ -z "${SOTS_GATE_LOCKED:-}" ]; then
|
|
exec env SOTS_GATE_LOCKED=1 flock -w 1800 /tmp/sots-gate.lock "$0" "$@" \
|
|
|| { echo "GATE FAIL could not acquire /tmp/sots-gate.lock within 30 min"; exit 2; }
|
|
fi
|
|
|
|
ENGINE="${ENGINE:-$HOME/sots-engine}"
|
|
RE="${RE:-$HOME/sots-re}"
|
|
CT=111
|
|
REMOTE_TREE=/srv/re-lab/build/sots-engine
|
|
REMOTE_CORPUS=/srv/re-lab/saves-corpus
|
|
REMOTE_DATA=/srv/re-lab/gob-extract # the extracted asset tree; game_design_census needs it
|
|
FRESH=0
|
|
[ "${1:-}" = "--fresh" ] && FRESH=1
|
|
|
|
ct() { ssh spicy "pct exec $CT -- bash -lc '$*'"; }
|
|
|
|
status=0
|
|
report() { # name rc
|
|
if [ "$2" -eq 0 ]; then echo "GATE ok $1"; else echo "GATE FAIL $1 (exit $2)"; status=1; fi
|
|
}
|
|
|
|
echo "== gate: $ENGINE @ $(git -C "$ENGINE" rev-parse --short HEAD), corpus $(ls "$RE"/verify/results/saves/*.sav | wc -l) saves, fresh=$FRESH"
|
|
|
|
# 1. clean-room, host
|
|
( cd "$ENGINE" && bash tools/clean_room_check.sh ); report clean-room $?
|
|
|
|
# 2. shim config structure, host
|
|
( cd "$ENGINE" && uv run --quiet python3 tools/check_shim_configs.py ); report shim-configs $?
|
|
|
|
# 3. sync the tree -- BOTH halves of rule 24: exclude local build dirs, and clear the remote ones
|
|
rsync -a --delete --exclude '.git' --exclude 'build*' -e ssh "$ENGINE"/ spicy:/tmp/eng-gate/; report sync-to-host $?
|
|
if [ $FRESH -eq 1 ]; then ct "rm -rf $REMOTE_TREE/build-host $REMOTE_TREE/build-shim"; report clear-remote-builds $?; fi
|
|
ssh spicy "tar -C /tmp/eng-gate -cf - . | pct exec $CT -- tar -C $REMOTE_TREE -xf -"; report sync-to-ct $?
|
|
|
|
# 4. sync the corpus -- the tests are only a gate if they run against it
|
|
rsync -a --delete --include='*.sav' --exclude='*' -e ssh "$RE"/verify/results/saves/ spicy:/tmp/sots-corpus/; report corpus-to-host $?
|
|
ssh spicy "pct exec $CT -- mkdir -p $REMOTE_CORPUS && tar -C /tmp/sots-corpus -cf - . | pct exec $CT -- tar -C $REMOTE_CORPUS -xf -"; report corpus-to-ct $?
|
|
NCORPUS=$(ct "ls $REMOTE_CORPUS | grep -c .sav")
|
|
echo "GATE info corpus on CT111: $NCORPUS saves"
|
|
|
|
# 5. host build + tests, WITH the corpus AND the extracted data tree
|
|
#
|
|
# `cmd | tail -1` returns TAIL's status, not the command's -- so for a day this
|
|
# script printed "GATE ok host-ctest" over a run with two FAILING tests, which is
|
|
# rule 1's failure wearing this script's own clothes. Every step below captures
|
|
# the real exit code first and only then trims the output.
|
|
ct "cd $REMOTE_TREE && cmake -S . -B build-host -DCMAKE_BUILD_TYPE=Release >/tmp/gate-cfg.log 2>&1 && cmake --build build-host -j8 >/tmp/gate-build.log 2>&1; rc=\$?; tail -1 /tmp/gate-build.log; exit \$rc"; report host-build $?
|
|
ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS SOTS_DATA_DIR=$REMOTE_DATA ctest --output-on-failure >/tmp/gate-ctest.log 2>&1; rc=\$?; tail -15 /tmp/gate-ctest.log; exit \$rc"; report host-ctest $?
|
|
# and prove the corpus tests RAN rather than skipped. The check is scoped to the
|
|
# tests gated on the CORPUS (they name SOTS_SAVES_DIR when they skip); every other
|
|
# skip is listed below it by name, because a skip nobody reads is how this started.
|
|
SKIPPED=$(ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS SOTS_DATA_DIR=$REMOTE_DATA ctest -V 2>&1 | grep -c SOTS_SAVES_DIR")
|
|
if [ "${SKIPPED:-1}" -ne 0 ]; then echo "GATE FAIL corpus tests skipped ($SKIPPED) -- the gate is hollow"; status=1; else echo "GATE ok corpus tests ran (0 skipped)"; fi
|
|
ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS SOTS_DATA_DIR=$REMOTE_DATA ctest -V 2>&1 | grep skipped" | sed 's/^/GATE info skip: /'
|
|
|
|
# 6. shim cross-build -- same exit-code discipline as step 5. The `ls` at the end
|
|
# is a second, independent check (the artefact exists), not the build's verdict:
|
|
# without --fresh a DLL from an earlier run would satisfy it on its own.
|
|
ct "cd $REMOTE_TREE && cmake -S . -B build-shim -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-mingw-i686.cmake -DCMAKE_BUILD_TYPE=Release >/tmp/gate-shim-cfg.log 2>&1; rc=\$?; cmake --build build-shim -j8 >/tmp/gate-shim.log 2>&1 || rc=1; tail -1 /tmp/gate-shim.log; ls -la build-shim/binkw32.dll || rc=1; exit \$rc"; report shim-cross-build $?
|
|
|
|
echo "== gate: $([ $status -eq 0 ] && echo GREEN || echo RED)"
|
|
exit $status
|