From ea30cb3ddf9ba3ab6039695b70cf376fb20acd20 Mon Sep 17 00:00:00 2001 From: Chris Scragg Date: Tue, 16 Jun 2026 22:43:13 -0400 Subject: [PATCH] fix: make cargo-binstall resilient to flaky build-host networks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On WSL2 / Docker Desktop the NAT chokes cargo-binstall's concurrent fetcher checks (~20 simultaneous outbound connections is the observed ceiling). Resolving all 11 crates at once (~22 connections) times out the GitHub + QuickInstall lookups, and cargo-binstall then falls back to compile-from-source — which hard-fails the build: this image ships no Rust toolchain, and the source path rejects --install-path ("cargo-install does not support --install-path", exit 100). macOS never trips the NAT blip, so the build only failed on WSL. Add three guards, all no-ops on a healthy host: * --disable-strategies compile — never take the broken source path (all 11 crates publish prebuilt binaries, so compile is never needed here) * install in batches of 4 (~8 concurrent connections, well under the ceiling) instead of all 11 at once * retry each batch + --maximum-resolution-timeout 60 to ride out blips Verified: full `make rebuild` green end-to-end, claude-code healthy; shellcheck clean. Co-Authored-By: Claude Opus 4.8 --- .devcontainer/install-tools.sh | 54 ++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/.devcontainer/install-tools.sh b/.devcontainer/install-tools.sh index b1d725c..8bac94b 100755 --- a/.devcontainer/install-tools.sh +++ b/.devcontainer/install-tools.sh @@ -65,18 +65,48 @@ echo "==> Installing Rust CLI tools via cargo-binstall" # and verifies the crate checksum against the registry index. Pinning all 11 to # exact versions would require an out-of-band bump cadence for low-risk dev CLIs; # the registry checksum + --locked is the accepted trade-off here. -cargo-binstall --no-confirm --locked --install-path /usr/local/bin \ - eza \ - zoxide \ - starship \ - git-delta \ - bottom \ - du-dust \ - procs \ - sd \ - hyperfine \ - tokei \ - tealdeer +RUST_TOOLS=(eza zoxide starship git-delta bottom du-dust procs sd hyperfine tokei tealdeer) + +# Resilience to flaky build-host networks (notably WSL2 / Docker Desktop, whose NAT +# chokes cargo-binstall's concurrent fetcher checks — ~20 simultaneous outbound +# connections is the observed ceiling). Three guards, all no-ops on a healthy host: +# * --disable-strategies compile — NEVER fall back to building from source. This +# image ships no Rust toolchain, AND the source path rejects --install-path, so +# a single transient fetcher timeout would otherwise hard-fail the build with a +# misleading `cargo-install does not support --install-path` (exit 100). All 11 +# crates publish prebuilt binaries, so the compile strategy is never legitimately +# needed here. +# * --maximum-resolution-timeout 60 — give each GitHub/QuickInstall lookup room +# beyond the stingy 15s default before it's declared timed out. +# * install in batches of 4 (≈8 concurrent connections, well under the ceiling) +# and retry each batch — 11 crates at once sat right at the edge; batching + +# retry rides out a brief NAT/DNS blip. The cargo cache mount makes retries cheap. +binstall_retry() { # args: crate names; retries the batch to absorb transient blips + local attempt + for attempt in 1 2 3; do + if cargo-binstall --no-confirm --locked \ + --disable-strategies compile \ + --maximum-resolution-timeout 60 \ + --install-path /usr/local/bin "$@"; then + return 0 + fi + echo "WARN: cargo-binstall attempt ${attempt}/3 failed for: $* — retrying" >&2 + sleep "$((attempt * 8))" + done + echo "ERROR: cargo-binstall failed after 3 attempts for: $*" >&2 + return 1 +} +batch=() +for tool in "${RUST_TOOLS[@]}"; do + batch+=("$tool") + if [ "${#batch[@]}" -eq 4 ]; then + binstall_retry "${batch[@]}" + batch=() + fi +done +if [ "${#batch[@]}" -gt 0 ]; then + binstall_retry "${batch[@]}" +fi echo "==> Installing yq ${YQ_VER} (${GO_ARCH})" # Pinned version + SHA-256 gate (no /releases/latest redirect, no unverified write).