From b6fa56820c6fe5b8eb3370411d6738a3f3148b4c Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 25 Oct 2026 18:56:57 +0100 Subject: [PATCH] ci: install qemu-user, not the virtual qemu-user-static (Ubuntu 26.04) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ubuntu-latest` became Ubuntu 26.04 on 2026-10-19. There `qemu-user-static` is a VIRTUAL package and apt refuses to choose between its two providers: E: Package 'qemu-user-static' has no installation candidate Package qemu-user-static is a virtual package provided by: qemu-user-binfmt-hwe 1:10.2.1+ds-1ubuntu4.4 qemu-user-binfmt 1:10.2.1+ds-1ubuntu3.3 The step exits 100 in about twenty seconds, so this lane went red between a green main and the next push with nothing committed here. ⚠ Installing a PROVIDER is not the fix: `qemu-user-binfmt` registers binfmt handlers, it does not ship the `qemu--static` binaries this lane invokes. A lane given only a provider takes its `command -v` branch and goes GREEN while testing nothing, which is worse than red. `qemu-user` ships the dynamic `qemu-`, which is all `go test -exec` needs, so both packages are installed and BOTH binary names are accepted at run time. ⛔ And a missing emulator now FAILS this lane, which PRINTS which emulator it ran (`running ppc64le under qemu-ppc64le`). Without that line, "ran under emulation" and "skipped" are indistinguishable from a green tick. Written by `qemufix` v0.37.0 (go-fleettools/fleettools#128), which recognises four shapes, refuses by name anything else rather than guessing, and is idempotent. Nothing else in the lane changed: the retry loop, `CGO_ENABLED=0`, the test timeouts and the package lists are carried through verbatim. Co-Authored-By: Claude Opus 5 --- .github/workflows/arch-qemu-nightly.yml | 37 +++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/.github/workflows/arch-qemu-nightly.yml b/.github/workflows/arch-qemu-nightly.yml index 869f2e94..43ada205 100644 --- a/.github/workflows/arch-qemu-nightly.yml +++ b/.github/workflows/arch-qemu-nightly.yml @@ -60,10 +60,21 @@ jobs: # first, and they are only refreshed if that was not enough. apt is also # told to give up on a stuck mirror rather than sit on it, which is what # made the outer timeout the only thing stopping it. - - name: Install qemu-user-static + # ⛔ `qemu-user-static` is a VIRTUAL package on Ubuntu 26.04, which + # `ubuntu-latest` became on 2026-10-19, and apt refuses to choose between its + # two providers: + # + # E: Package 'qemu-user-static' has no installation candidate + # + # ⚠ Installing a provider is NOT the fix: `qemu-user-binfmt` registers binfmt + # handlers, it does not ship the `qemu--static` binaries this lane + # invokes. `qemu-user` ships the dynamic `qemu-`, which is all that + # `go test -exec` needs, so both are installed and BOTH NAMES are accepted + # below. go-tex/engine#645 has the full account. + - name: Install qemu user-mode emulators run: | apt=(-y -qq -o Acquire::Retries=3 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30) - if timeout 240 sudo apt-get install "${apt[@]}" qemu-user-static; then + if timeout 240 sudo apt-get install "${apt[@]}" qemu-user qemu-user-binfmt; then exit 0 fi for attempt in 1 2; do @@ -71,11 +82,11 @@ jobs: timeout 240 sudo apt-get update "${apt[@]}" || true sudo rm -f /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock* sudo dpkg --configure -a || true - if timeout 240 sudo apt-get install "${apt[@]}" qemu-user-static; then + if timeout 240 sudo apt-get install "${apt[@]}" qemu-user qemu-user-binfmt; then exit 0 fi done - echo "::error::qemu-user-static could not be installed" + echo "::error::qemu-user qemu-user-binfmt could not be installed" exit 1 - name: Test under qemu (${{ matrix.goarch }}) # qemu-user emulation is ~50-100x slower than native, so the wall here is @@ -92,4 +103,20 @@ jobs: # margin, which ordinary runner variance crosses. 60m puts s390x at # about half the wall, which is what "generous headroom" was meant to # say. (On real s390x silicon the same suite runs natively in seconds.) - run: GOARCH=${{ matrix.goarch }} go test -timeout=60m -exec=${{ matrix.qemu }} ./... + run: | + base="${{ matrix.qemu }}" + q="" + for cand in "$base" "${base%-static}"; do + command -v "$cand" >/dev/null 2>&1 && q="$cand" && break + done + # ⛔ A missing emulator FAILS this lane. A lane that reports success for + # an architecture it never ran is the one outcome this matrix exists to + # rule out. + if [ -z "$q" ]; then + echo "::error::no qemu user emulator for ${{ matrix.goarch }} (looked for $base and ${base%-static})" + exit 1 + fi + # Printed on purpose: without it, "ran under emulation" and "skipped" are + # indistinguishable from a green tick. + echo "running ${{ matrix.goarch }} under $q" + GOARCH=${{ matrix.goarch }} go test -timeout=60m -exec="$q" ./...