#!/usr/bin/env bash # Offline simulation of rustup installation/selection; no Rust or network required. set -Eeuo pipefail ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) WORK=$(mktemp -d) trap 'rm -rf "$WORK"' EXIT mkdir -p "$WORK/bin" "$WORK/source" "$WORK/state" cat > "$WORK/bin/rustup" <<'MOCK' #!/usr/bin/env bash set -Eeuo pipefail state=${MOCK_RUSTUP_STATE:?} case "$1" in run) channel=$2 [[ -r "$state/$channel.version" ]] || exit 1 printf 'rustc %s (mock)\n' "$(cat "$state/$channel.version")" ;; toolchain) [[ "$2" == install ]] || exit 7 channel=$3 [[ ${MOCK_INSTALL_FAIL:-0} != 1 ]] || exit 9 case "$channel" in stable) version=${MOCK_NEW_STABLE:-1.100.0} ;; *) case "$channel" in *.*.*) version=$channel ;; *) version=${channel}.0 ;; esac ;; esac echo "$version" > "$state/$channel.version" printf 'install %s\n' "$channel" >> "$state/calls" ;; target) action=$2 if [[ "$action" == list ]]; then [[ "$3" == --toolchain && "$5" == --installed ]] || exit 7 [[ -f "$state/$4.target" ]] && cat "$state/$4.target" elif [[ "$action" == add ]]; then [[ "$4" == --toolchain ]] || exit 7 echo "$3" > "$state/$5.target" printf 'target %s %s\n' "$5" "$3" >> "$state/calls" else exit 7 fi ;; *) printf 'Unexpected rustup arguments: %s\n' "$*" >&2; exit 7 ;; esac MOCK chmod +x "$WORK/bin/rustup" export PATH="$WORK/bin:$PATH" MOCK_RUSTUP_STATE="$WORK/state" TOML_PYTHON=python3 TOOL="$ROOT/scripts/ensure-rust-toolchain.sh" reset_state() { rm -f "$WORK/state/"*; } manifest() { printf '[package]\nname = "rust-proxy"\nversion = "0.31.2"\nrust-version = "%s"\n' "$1" > "$WORK/source/Cargo.toml"; rm -f "$WORK/source/rust-toolchain" "$WORK/source/rust-toolchain.toml"; } # No update or download when installed stable already satisfies the manifest. reset_state manifest 1.99 printf '1.100.0\n' > "$WORK/state/stable.version" result=$($TOOL "$WORK/source" linux) [[ "$result" == stable ]] [[ ! -e "$WORK/state/calls" ]] # Upgrade stable only when too old, then reuse it on subsequent checks. reset_state printf '1.98.1\n' > "$WORK/state/stable.version" result=$($TOOL "$WORK/source" linux) [[ "$result" == stable ]] grep -Fqx 'install stable' "$WORK/state/calls" [[ $($TOOL "$WORK/source" linux) == stable ]] [[ $(wc -l < "$WORK/state/calls") == 1 ]] # FreeBSD default 1.88 is auto raised to the project's 1.99 MSRV with its own target. reset_state result=$(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) [[ "$result" == 1.99 ]] grep -Fqx 'install 1.99' "$WORK/state/calls" grep -Fqx 'target 1.99 x86_64-unknown-freebsd' "$WORK/state/calls" [[ $(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) == 1.99 ]] [[ $(wc -l < "$WORK/state/calls") == 2 ]] # A deliberate rust-toolchain.toml pin is respected; do not silently override it. reset_state cat > "$WORK/source/rust-toolchain.toml" <<'PIN' [toolchain] channel = "1.98.0" PIN if "$TOOL" "$WORK/source" linux >/dev/null 2>&1; then printf 'An incompatible explicit pin should have failed\n' >&2 exit 1 fi [[ ! -e "$WORK/state/calls" ]] || { echo 'Should not install an incompatible pin' >&2; exit 1; } rm "$WORK/source/rust-toolchain.toml" # Pin that meets the project requirement is installed without changing stable. reset_state cat > "$WORK/source/rust-toolchain.toml" <<'PIN' [toolchain] channel = "1.99.0" PIN [[ $($TOOL "$WORK/source" linux) == 1.99.0 ]] grep -Fqx 'install 1.99.0' "$WORK/state/calls" rm "$WORK/source/rust-toolchain.toml" # RustProxy-like rust-toolchain.toml (stable) also upgrades stale stable for FreeBSD. reset_state manifest 1.99 cat > "$WORK/source/rust-toolchain.toml" <<'PIN' [toolchain] channel = "stable" profile = "minimal" components = ["rustfmt", "clippy"] PIN printf '1.98.1\n' > "$WORK/state/stable.version" [[ $(FREEBSD_RUST_TOOLCHAIN=1.88.0 "$TOOL" "$WORK/source" freebsd) == stable ]] grep -Fqx 'install stable' "$WORK/state/calls" grep -Fqx 'target stable x86_64-unknown-freebsd' "$WORK/state/calls" rm "$WORK/source/rust-toolchain.toml" # Workspace-inherited rust-version is resolved through TOML, not grep. reset_state cat > "$WORK/source/Cargo.toml" <<'MANIFEST' [workspace.package] rust-version = "1.99" [package] name = "rust-proxy" version = "0.31.2" rust-version = { workspace = true } MANIFEST printf '1.100.0\n' > "$WORK/state/stable.version" [[ $($TOOL "$WORK/source" linux) == stable ]] # An unavailable upgrade must be a hard failure. reset_state manifest 1.99 printf '1.98.1\n' > "$WORK/state/stable.version" if MOCK_INSTALL_FAIL=1 "$TOOL" "$WORK/source" linux >/dev/null 2>&1; then printf 'A failed rustup update should abort the build\n' >&2 exit 1 fi echo 'Rust toolchain selection: 8 offline scenarios OK'