48c85fa19f
pr_ready is the one self-check to run before asking for review: from the files a branch changes it runs rustfmt, clippy with warnings denied, the tests of the touched crates (mapped through cargo metadata), the launcher's own workspace when it is affected, the tokens.css check, the Cargo.lock rule, the Python tests and the public-tree check, and the vanilla harnesses the change can affect, picked by tools/parity.py exactly as CI's parity job picks them. It runs locally or on a fleet machine through ~/fleet/rbuild; on the Mac mini the harnesses use the parity runner's own workspace and scripts. It prints one Markdown block for the pull request body and exits non-zero on any failure. tools/parity.py gains --changed-files for copies without Git history, and tools/ci/vanilla-data.sh accepts the preparation key from outside. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
93 lines
5.2 KiB
Bash
Executable File
93 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The vanilla data for this checkout on the self-hosted runner. Horizon never downloads the game: the runner
|
|
# holds the maintainer's own copy, imported and decompiled once (HORIZON_SHARED_SOURCE, default
|
|
# ~/code/horizon-parity/shared-local). It is cloned once into the runner's work folder ($RUNNER_WORKSPACE/
|
|
# shared-local; APFS clones, so no second copy of the bytes), and .local/ links to it as in a parity worktree.
|
|
# .local/horizon-client and the exporter outputs beside it, what horizon-prepare makes, are prepared by this
|
|
# checkout's own preparer once per preparer version (its sources, the exporters and research-lock.json), so a
|
|
# change to the preparer is checked with what it prepares; the four newest preparations are kept.
|
|
set -euo pipefail
|
|
shared="${RUNNER_WORKSPACE:?}/shared-local"
|
|
source="${HORIZON_SHARED_SOURCE:-$HOME/code/horizon-parity/shared-local}"
|
|
version=$(sed -n 's/.*"version": *"\([^"]*\)".*/\1/p' research-lock.json | head -1)
|
|
if [ ! -f "$shared/minecraft/$version/prepared.json" ]; then
|
|
[ -f "$source/minecraft/$version/prepared.json" ] || { echo "::error::no imported Minecraft $version in $source"; exit 1; }
|
|
mkdir -p "$shared"
|
|
if [ "$(uname)" = Darwin ]; then
|
|
for entry in "$source"/*; do
|
|
[ "$(basename "$entry")" = horizon-client ] || cp -cR "$entry" "$shared/"
|
|
done
|
|
else
|
|
for entry in "$source"/*; do
|
|
[ "$(basename "$entry")" = horizon-client ] || cp -R --reflink=auto "$entry" "$shared/"
|
|
done
|
|
fi
|
|
fi
|
|
mkdir -p .local "$shared/prepared"
|
|
for entry in "$shared"/*; do
|
|
name=$(basename "$entry")
|
|
case "$name" in prepared|sounds|*.log) continue ;; esac
|
|
if [ -L ".local/$name" ] || [ ! -e ".local/$name" ]; then ln -sfn "$entry" ".local/$name"; fi
|
|
done
|
|
|
|
# HORIZON_PREPARE_KEY: the same key, computed where the Git history is (tools/pr_ready.py on another machine).
|
|
key=${HORIZON_PREPARE_KEY:-$(git ls-files -s crates/horizon-prepare mods/horizon/src/test/java research-lock.json | shasum -a 256 | cut -c1-16)}
|
|
prepared="$shared/prepared/$key"
|
|
# Two runners share the vanilla data (~/.actions-runners/horizon-2/_work/horizon/shared-local links to the first
|
|
# one's): one preparation at a time. A lock older than 30 minutes belongs to a job that died.
|
|
lock="$shared/prepared/.lock"
|
|
until mkdir "$lock" 2>/dev/null; do
|
|
if [ -n "$(find "$lock" -maxdepth 0 -mmin +30 2>/dev/null)" ]; then rmdir "$lock" 2>/dev/null || true; fi
|
|
sleep 5
|
|
done
|
|
trap 'rmdir "$lock" 2>/dev/null || true' EXIT
|
|
# horizon-prepare writes .local/horizon-client and its exporters' outputs beside it: all of them live in
|
|
# $prepared, listed in $prepared/.entries, and .local/ links to them.
|
|
if [ ! -f "$prepared/.entries" ]; then
|
|
echo "Preparing resources with this checkout's horizon-prepare ($key)"
|
|
rm -rf "$prepared" && mkdir -p "$prepared"
|
|
# Links to another preparation's outputs go first, so what this one writes shows up as new entries.
|
|
for entry in .local/*; do
|
|
if [ -L "$entry" ] && [[ "$(readlink "$entry")" == "$shared/prepared/"* ]]; then rm "$entry"; fi
|
|
done
|
|
before=$(ls -1A .local | LC_ALL=C sort)
|
|
started=$SECONDS
|
|
cargo build --release --locked -p horizon-prepare
|
|
if ! target/release/horizon-prepare --root "$PWD" > "$RUNNER_TEMP/prepare.log" 2>&1; then
|
|
tail -40 "$RUNNER_TEMP/prepare.log"
|
|
rm -rf "$prepared"
|
|
exit 1
|
|
fi
|
|
LC_ALL=C comm -13 <(echo "$before") <(ls -1A .local | LC_ALL=C sort) > "$RUNNER_TEMP/prepared-entries"
|
|
while read -r name; do mv ".local/$name" "$prepared/$name"; done < "$RUNNER_TEMP/prepared-entries"
|
|
mv "$RUNNER_TEMP/prepared-entries" "$prepared/.entries"
|
|
echo "Prepared in $((SECONDS - started)) s: $(tr '\n' ' ' < "$prepared/.entries")"
|
|
fi
|
|
# The game finds some data relative to its resources (<resources>/../../datagen): beside the prepared folders,
|
|
# the same neighbours as in the shared folder.
|
|
for entry in "$shared"/*; do
|
|
name=$(basename "$entry")
|
|
case "$name" in prepared|sounds|*.log) continue ;; esac
|
|
[ -e "$prepared/$name" ] || ln -sfn "$entry" "$prepared/$name"
|
|
done
|
|
while read -r name; do
|
|
if [ -L ".local/$name" ] || [ ! -e ".local/$name" ]; then ln -sfn "$prepared/$name" ".local/$name"; else
|
|
echo "::error::.local/$name is not a link to the prepared resources"; exit 1; fi
|
|
done < "$prepared/.entries"
|
|
# The game's sounds (horizon-prepare sounds copies them from the official launcher's asset store) depend only on the
|
|
# Minecraft version: kept once in $shared/sounds/<version>/ (sounds.json and sounds/) and copied into each preparation
|
|
# as clones (APFS, or reflinks on Linux: no second copy of the bytes). Not links: vanilla's resource packs refuse
|
|
# symbolic links inside a pack, so its sound oracles would find no sound files.
|
|
assets="$prepared/horizon-client/$version/assets/minecraft"
|
|
if [ -f "$shared/sounds/$version/sounds.json" ] && [ -d "$assets" ]; then
|
|
for entry in sounds.json sounds; do
|
|
[ -L "$assets/$entry" ] && rm "$assets/$entry"
|
|
[ -e "$assets/$entry" ] && continue
|
|
if [ "$(uname)" = Darwin ]; then cp -cR "$shared/sounds/$version/$entry" "$assets/"
|
|
else cp -R --reflink=auto "$shared/sounds/$version/$entry" "$assets/"; fi
|
|
done
|
|
fi
|
|
touch "$prepared"
|
|
# The four newest preparations stay.
|
|
ls -1dt "$shared/prepared"/*/ 2>/dev/null | tail -n +5 | while read -r old; do rm -rf "$old"; done
|