Read sdkmanager's status, not the status of the yes feeding it #97

Merged
JMR-dev merged 2 commits from fix/sdkmanager-pipefail into main 2026-08-25 14:41:23 +00:00
JMR-dev commented 2026-08-25 05:16:30 +00:00 (Migrated from github.com)

Closes #41 (R32 — filed PLAUSIBLE on shell semantics, demonstrated here).

yes | sdkmanager --install "$pkg" > /dev/null 2>&1 || { echo "  FAILED to install"; ... }

yes never ends. The moment sdkmanager exits and closes the pipe, yes dies of SIGPIPE with 141 — and this script runs under pipefail, which takes the rightmost non-zero status. A package that installed perfectly reported "FAILED to install".

Measured, not reasoned

set -o pipefail; yes | true            → 141   (three runs, three times)
set -o pipefail; yes | sh -c 'exit 3'  → 3
${PIPESTATUS[1]} for those two         → 0 and 3

The pipeline status cannot distinguish a clean install from a broken one. PIPESTATUS can. That's the entire change — no restructuring of the licence flow, so a fresh SDK still gets its licences accepted exactly as before.

What I deliberately did not touch

echo no | avdmanager eleven lines below has the same shape and is not affected — one line fits the pipe buffer, so echo has exited before the close and there's no signal to receive:

echo no | true  → 0   (five consecutive runs)
yes     | true  → 141 (three consecutive runs)

Only an unbounded producer is exposed. The comment says so, because someone reading this fix later would otherwise "fix" the echo too and change a line that was never wrong.

Why it went unnoticed

It only misfires when the image is absent, and every existing checkout already has the images. The failure mode is also silent in the worst direction: the install succeeds, the script says it failed, and the AVD is then created from a package that is really there.

shellcheck clean at the pinned digest (0.11.0, the version CI runs), bash -n clean.

Closes #41 (R32 — filed `PLAUSIBLE` on shell semantics, **demonstrated here**). ```bash yes | sdkmanager --install "$pkg" > /dev/null 2>&1 || { echo " FAILED to install"; ... } ``` `yes` never ends. The moment sdkmanager exits and closes the pipe, `yes` dies of SIGPIPE with **141** — and this script runs under `pipefail`, which takes the rightmost non-zero status. **A package that installed perfectly reported "FAILED to install".** ## Measured, not reasoned ``` set -o pipefail; yes | true → 141 (three runs, three times) set -o pipefail; yes | sh -c 'exit 3' → 3 ${PIPESTATUS[1]} for those two → 0 and 3 ``` The pipeline status cannot distinguish a clean install from a broken one. `PIPESTATUS` can. That's the entire change — no restructuring of the licence flow, so a fresh SDK still gets its licences accepted exactly as before. ## What I deliberately did not touch `echo no | avdmanager` eleven lines below has the same *shape* and is **not** affected — one line fits the pipe buffer, so `echo` has exited before the close and there's no signal to receive: ``` echo no | true → 0 (five consecutive runs) yes | true → 141 (three consecutive runs) ``` Only an unbounded producer is exposed. The comment says so, because someone reading this fix later would otherwise "fix" the echo too and change a line that was never wrong. ## Why it went unnoticed It only misfires when the image is **absent**, and every existing checkout already has the images. The failure mode is also silent in the worst direction: the install succeeds, the script says it failed, and the AVD is then created from a package that is really there. shellcheck clean at the **pinned digest** (0.11.0, the version CI runs), `bash -n` clean.
Sign in to join this conversation.