Josh's decision of 6 October 2026: the Mac runs nothing the network depends on. docs/plans/hands-on-build-1.md plans node 1 and the observer (its node and tools/observer) as systemd units on the box, one hand at a time, with ports, DNS names, exec recovery, rollback and the decisions for main; infra/build-server/hands/install-hands.sh writes users, dirs, run scripts and units (inert, run on the box); move-hand.sh (dry run by default) builds 0.3.15 on the box, copies the override and snapshot, rsyncs each data dir hot then stopped, starts the unit and prints the hand's first executing line, copies the observer env by scp (mode 600), stops the Mac's observer first, unloads the launchd agents last. CLAUDE.md's running-agents rule carries the decision. lib.sh: a per-worktree lock on the box across sync, build and fetch (the shipper's collision at 18:48:56Z). remote-run.sh: the clean-tree test excuses stamps and target dirs at any depth with --untracked-files=all (a nested stamp failed every checkout of /srv/builds/igneum for twenty minutes) and removes a stale .git/index.lock; the self-test covers both. Plan rows for the three and the cuda prover pair built for the shipper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
119 lines
7.8 KiB
Bash
Executable file
119 lines
7.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Build on igneum-build-1 instead of this Mac. Run from any crate directory of any worktree on the Mac (a fork worktree under
|
|
# vendor/, igneum-pow, app/igneum-app, proving/igneum-prove): the sources go to /srv/builds/<worktree>/<same relative path> on
|
|
# the box (HEAD through the bare mirror, uncommitted changes by rsync, changed files re-stamped with touch in lib.sh's
|
|
# bs_overlay_dir: the copied-sources rule), the cargo command runs there
|
|
# with sccache and -j 90 under one of the box's build slots, and the artefacts come back into target-remote/ here.
|
|
#
|
|
# tools/build-remote.sh the default command for this crate (below)
|
|
# tools/build-remote.sh -- build --release -p kaspad --features kaspad/igneum-pow
|
|
# tools/build-remote.sh -- test --release -p kaspa-consensus-core --lib
|
|
# tools/build-remote.sh --artefacts "target/release/igneumd" --out /tmp/x -- build --release -p kaspad --features kaspad/igneum-pow
|
|
# tools/build-remote.sh --jobs 48 -- check
|
|
# tools/build-remote.sh --target-dir target-exp -- build --release another persistent target dir on the box
|
|
# tools/build-remote.sh --no-fetch -- clippy --all-targets nothing comes back (tests, check, clippy)
|
|
#
|
|
# Defaults by crate: a fork worktree builds `-p kaspad -p igneum-miner --features kaspad/igneum-pow` in release and fetches
|
|
# target/release/{igneumd,igneum-miner} (what packaging/README-ship.md and infra/cross expect); app/igneum-app builds release
|
|
# and fetches igneum-app, igneum-ota-sign, igneum-prove-verify; proving/igneum-prove fetches igneum-prove-host and
|
|
# igneum-prove-export; any other crate builds release and fetches nothing unless --artefacts names files.
|
|
#
|
|
# Artefacts land in <crate>/target-remote/<path without the leading target/> (target-remote/release/igneumd), NEVER in
|
|
# target/: the box builds x86_64 Linux ELF binaries (glibc 2.39, Ubuntu 24.04), which do not run on this Mac. Each one is
|
|
# reported with size and sha256. For Windows exes use tools/cross-remote.sh.
|
|
#
|
|
# Slots: the box has its own slot files (/srv/builds/_locks/build-<k>, count in /srv/builds/_locks/slots, default 1); this
|
|
# script takes one of THOSE, never the Mac's ~/.config/igneum/build-slots or tools/lock/with-lock.sh, so a remote build does
|
|
# not hold a Mac slot. A build waits up to 2 h for a remote slot, as with-lock.sh does.
|
|
#
|
|
# Needs: ~/.config/igneum/build-server (build@<ip>, written by infra/build-server/run-from-mac.sh), ~/.ssh/igneum_ed25519,
|
|
# the same rustc version on both sides (refused otherwise; IGNEUM_TOOLCHAIN_MISMATCH=ok overrides). IGNEUM_AGENT names the
|
|
# agent in the slot-file label and the box's JSONL log (/srv/builds/_log/builds.jsonl); default the worktree name.
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck disable=SC2034 # shared with the scripts that source lib.sh
|
|
BS_TOOL=build-remote
|
|
# shellcheck source=../infra/build-server/lib.sh
|
|
. "$HERE/../infra/build-server/lib.sh"
|
|
|
|
JOBS="${JOBS:-90}"; OUT=""; ARTEFACTS=""; TARGET_DIR="target"; FETCH=1; CARGO_ARGS=()
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--jobs) JOBS="$2"; shift 2 ;;
|
|
--out) OUT="$2"; shift 2 ;;
|
|
--artefacts) ARTEFACTS="$2"; ARTEFACTS_SET=1; shift 2 ;;
|
|
--target-dir) TARGET_DIR="$2"; shift 2 ;;
|
|
--no-fetch) FETCH=0; shift ;;
|
|
--) shift; CARGO_ARGS=("$@"); break ;;
|
|
-h|--help) sed -n '2,32p' "$0"; exit 0 ;;
|
|
*) CARGO_ARGS=("$@"); break ;;
|
|
esac
|
|
done
|
|
[ "${CARGO_ARGS[0]:-}" = cargo ] && CARGO_ARGS=("${CARGO_ARGS[@]:1}")
|
|
CARGO_ARGS_GIVEN=""; [ "${#CARGO_ARGS[@]}" -gt 0 ] && CARGO_ARGS_GIVEN=1
|
|
|
|
bs_host
|
|
bs_context
|
|
|
|
# defaults per crate
|
|
case "$BS_KIND:$BS_CRATE_REL" in
|
|
node:*)
|
|
[ "${#CARGO_ARGS[@]}" -gt 0 ] || CARGO_ARGS=(build --release -p kaspad -p igneum-miner --features kaspad/igneum-pow)
|
|
[ -n "$ARTEFACTS" ] || ARTEFACTS="$TARGET_DIR/release/igneumd $TARGET_DIR/release/igneum-miner" ;;
|
|
repo:app/igneum-app)
|
|
[ "${#CARGO_ARGS[@]}" -gt 0 ] || CARGO_ARGS=(build --release)
|
|
[ -n "$ARTEFACTS" ] || ARTEFACTS="$TARGET_DIR/release/igneum-app $TARGET_DIR/release/igneum-ota-sign $TARGET_DIR/release/igneum-prove-verify" ;;
|
|
repo:proving/igneum-prove)
|
|
[ "${#CARGO_ARGS[@]}" -gt 0 ] || CARGO_ARGS=(build --release)
|
|
[ -n "$ARTEFACTS" ] || ARTEFACTS="$TARGET_DIR/release/igneum-prove-host $TARGET_DIR/release/igneum-prove-export" ;;
|
|
*)
|
|
[ "${#CARGO_ARGS[@]}" -gt 0 ] || CARGO_ARGS=(build --release) ;;
|
|
esac
|
|
case "${CARGO_ARGS[0]}" in build) ;; *) [ -n "${ARTEFACTS_SET:-}" ] || { FETCH=0; ARTEFACTS=""; } ;; esac # test, check, clippy: nothing to fetch
|
|
[ -n "$OUT" ] || OUT="$BS_CRATE/target-remote"
|
|
|
|
bs_log "$BS_KIND crate $BS_WT/$BS_CRATE_REL at $BS_SHA ($BS_BRANCH) -> $BS_HOST:$BS_REMOTE_CRATE; cargo ${CARGO_ARGS[*]} -j $JOBS; target dir $TARGET_DIR"
|
|
bs_toolchain_check
|
|
t_sync0=$(date +%s)
|
|
bs_sync_sources
|
|
bs_log "sources in place after $(( $(date +%s) - t_sync0 )) s"
|
|
|
|
# the fork's kaspa-build-info embeds the commit through a build script that, having once found no branch, emits no
|
|
# rerun-if-changed and is never run again by cargo (release-0.3.11 plan: `cargo clean -p kaspa-build-info` first); so when
|
|
# the commit the box builds differs from the last one built in this target dir, that one crate is cleaned (a relink, seconds)
|
|
pre=""
|
|
if [ "$BS_KIND" = node ] && [ "${CARGO_ARGS[0]}" = build ]; then
|
|
pre="[ \"\$(cat '.build-remote-sha-$TARGET_DIR' 2>/dev/null)\" = '$BS_SHA' ] || CARGO_TARGET_DIR='$TARGET_DIR' cargo clean -q --release -p kaspa-build-info 2>/dev/null; "
|
|
fi
|
|
cmd="${pre}CARGO_TARGET_DIR='$TARGET_DIR' cargo $(printf '%q ' "${CARGO_ARGS[@]}")-j $JOBS 2>&1 | tee -a '$BS_REMOTE_WT/.build-remote.log'; rc=\${PIPESTATUS[0]}; [ \$rc = 0 ] && echo '$BS_SHA' > '.build-remote-sha-$TARGET_DIR'; ( exit \$rc )" # a subshell exit: the runner reads \$? and still prints its RESULT line
|
|
label="$BS_WT/$BS_CRATE_REL cargo ${CARGO_ARGS[*]}"
|
|
BR_KIND=$(bs_kind build-remote "${CARGO_ARGS[0]}"); BR_COMMAND="cargo ${CARGO_ARGS[*]}"; BR_TARGET=x86_64-unknown-linux-gnu
|
|
for ((i = 0; i < ${#CARGO_ARGS[@]}; i++)); do [ "${CARGO_ARGS[$i]}" = --target ] && BR_TARGET="${CARGO_ARGS[$((i + 1))]:-}"; done
|
|
BR_ARTEFACTS=""; [ "$FETCH" = 1 ] && BR_ARTEFACTS="$ARTEFACTS"
|
|
export BR_KIND BR_COMMAND BR_TARGET BR_ARTEFACTS
|
|
t0=$(date +%s)
|
|
set +e
|
|
bs_remote_run "$BS_REMOTE_CRATE" "$label" "$cmd" 2>&1 | tee "/tmp/build-remote-$$.log"
|
|
rc=${PIPESTATUS[0]}
|
|
set -e
|
|
secs=$(( $(date +%s) - t0 ))
|
|
result=$(grep -m1 '^build-remote: RESULT' "/tmp/build-remote-$$.log" || true); rm -f "/tmp/build-remote-$$.log"
|
|
if [ "$rc" != 0 ]; then bs_die "remote cargo failed (rc $rc) after $(bs_fmt_secs "$secs"); $result"; fi
|
|
bs_log "remote cargo ${CARGO_ARGS[0]} done in $(bs_fmt_secs "$secs") wall from the Mac; ${result#build-remote: RESULT }"
|
|
|
|
if [ "$FETCH" = 1 ] && [ -n "$ARTEFACTS" ]; then
|
|
mkdir -p "$OUT"
|
|
for a in $ARTEFACTS; do
|
|
rel="${a#"$TARGET_DIR"/}"; dest="$OUT/$rel"; mkdir -p "$(dirname "$dest")"
|
|
if ! bs_rsync -p "$BS_HOST:$BS_REMOTE_CRATE/$a" "$dest" 2>/dev/null; then
|
|
# a default artefact the caller's own `-p` selection did not build is noted, not fatal (6 Oct 2026: `-p igneum-prove-host`
|
|
# alone left no igneum-prove-export); a missing artefact the caller NAMED with --artefacts is fatal
|
|
if [ -n "${ARTEFACTS_SET:-}" ] || [ -z "${CARGO_ARGS_GIVEN:-}" ]; then bs_die "no $a on the box after the build"; fi
|
|
bs_log "no $a on the box (not built by cargo ${CARGO_ARGS[*]}); skipped"; continue
|
|
fi
|
|
bs_log "artefact $dest: $(bs_size "$dest") bytes, sha256 $(bs_sha256 "$dest"), $(file -b "$dest" | cut -c1-60)"
|
|
# the commit-string gate (rule of 6 October 2026): a node binary without its commit in its strings fails the run
|
|
case "$BS_KIND:$(basename "$dest")" in node:igneumd) "$HERE/ci/commit-string-check.sh" "$dest" "$BS_SHA" || bs_die "commit-string gate failed for $a" ;; esac # only kaspad depends on kaspa-build-info
|
|
done
|
|
fi
|
|
bs_wt_unlock
|