Skip to content

Fix silent halt in personal packages layer, and make failures visible - #2

Open
davidjalbers wants to merge 2 commits into
mainfrom
claude/bootstrap-personal-packages-halt-kuo102
Open

Fix silent halt in personal packages layer, and make failures visible#2
davidjalbers wants to merge 2 commits into
mainfrom
claude/bootstrap-personal-packages-halt-kuo102

Conversation

@davidjalbers

Copy link
Copy Markdown
Contributor

The reported bug

The script stopped in the personal packages layer: personal packages installed was never logged and the chezmoi layer never ran, with the apt output from the previous step as the last thing on screen.

apt_from_file ended with:

[[ ${#extrepo[@]} -gt 0 ]] && apt_extrepo "${extrepo[@]}"

For an apt.txt with no extrepo … lines the array is empty, the test is false, and the && short-circuits. A short-circuited test && cmd has exit status 1, and it was the last command in the function — so apt_from_file returned 1 and set -e aborted the whole script. No message, no die, exit code 1. Everything had actually installed correctly; only the reporting was missing.

Replaced with if blocks, plus the same latent pattern in layer_packages where an emptied DEV_CORE_CASKS/DEV_CORE_FORMULAE would have died the same way.

Making the class of bug visible

That failure was invisible, so the rest of the change targets that rather than just the one line.

  • ERR trap naming the aborting line. The original bug produced zero output; this reduces it to a one-line diagnosis.
  • Download-then-run the Homebrew and chezmoi installers. bash -c "$(curl …)" discards curl's exit status, so a failed download ran an empty script and reported success. This surfaced during testing: with the installer unreachable, the script printed ✓ dotfiles applied and exited 0 having installed nothing.
  • fetch() names the URL when a manifest download fails, instead of curl exiting silently under set -e.
  • validate_config() runs before any layer, so an unedited MANUAL EDIT section fails in seconds instead of after a full package install.
  • Verify brew exists before eval-ing its shellenv.

Tidying

  • Temp files are registered and removed from an EXIT trap, so an aborted layer no longer leaks them.
  • apt-get update runs once and is re-armed only when extrepo actually changes the sources — 4 updates down to 2 on a full Debian run.
  • id -un instead of $USER, which is not exported by every shell and would crash under set -u.

Testing

Ran the full script against stubbed sudo/apt-get/extrepo/curl/chsh on a simulated Debian:

Case Result
apt.txt with no extrepo lines (the reported bug) reaches chezmoi, exit 0
apt.txt with only extrepo lines (mirror case) exit 0
Unedited placeholder config fails in ~1s, 0 packages installed
Manifest 404 aborts naming the URL
Unreachable installer aborts instead of falsely reporting success
Temp files after success / after abort 0 / 0

bash -n clean. shellcheck was not available in this environment.


Generated by Claude Code

claude added 2 commits July 29, 2026 12:46
`apt_from_file` ended with `[[ ${#extrepo[@]} -gt 0 ]] && apt_extrepo …`.
When a manifest has no `extrepo` lines the test is false, the `&&` short-
circuits, and the function returns 1. As the last command in the function
under `set -e`, that aborted the entire script right after the apt install
output — with no error message, so `ok "personal packages installed"` and
the chezmoi layer never ran.

Replace the guards with `if` blocks in `apt_from_file`, and fix the same
latent pattern in `layer_packages` for the macOS formulae/casks arrays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hnxvLH9J3K4PjhgPLyWb5
The personal-packages halt was one instance of a general problem: this
script could stop or skip work without saying anything. Address the class.

- ERR trap reports the aborting line number. The original bug produced no
  output at all; it would have been a one-line diagnosis with this.
- Download-then-run the Homebrew and chezmoi installers. `bash -c "$(curl …)"`
  discards curl's exit status, so a failed download ran an empty script and
  reported success — "dotfiles applied" with no chezmoi installed.
- fetch() names the URL when a manifest download fails, instead of curl
  exiting silently under set -e.
- validate_config() runs before any layer, so an unedited MANUAL EDIT section
  fails in seconds rather than after a full package install.
- Verify brew is actually present before eval-ing its shellenv.

Also:
- Register temp files and remove them from an EXIT trap, so an aborted layer
  no longer leaks them.
- Run `apt-get update` once and re-arm it only when extrepo changes the
  sources: 4 updates down to 2 on a full Debian run.
- Use `id -un` rather than $USER, which is not exported by every shell and
  would crash under `set -u`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hnxvLH9J3K4PjhgPLyWb5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants