Files
dotfiles-public/.tests/mutations/20-flags-after-subcommand-discarded.mut
bcherb2 4043787a58 fix: close the four known installer bugs (DU-H1, DU-H2, BUG-1, BUG-2)
- DU-H1: flags are parsed wherever they sit, so `install --unattended`
  and `--unattended install` are the same run; any unknown flag, word,
  or subcommand exits 2 to stderr before a package manager is touched.
- DU-H2: every download lands in one private mktemp -d (mode 700)
  workdir per run, is checked non-empty before sudo tar sees it, and an
  EXIT/INT/TERM trap cleans up. No fixed /tmp paths remain.
- BUG-1: ^t is now toggle-shown — it ticks only the rows the active
  filter is showing, and @needs expansion stops at the first invasive
  row, so an invasive package can never be ticked off-screen.
- BUG-2: ^t journals what it added, so a second ^t over the same shown
  set unticks exactly that set; the bind no longer clears the query.
- lab: the type verb polls fzf's reported query to a deadline instead
  of a fixed sleep; marks_settled retries within its deadline.

Suite 256/0 host, 214/0 docker (ubuntu:24.04), mutations 24/24 killed
(six new mutants re-introduce each bug and all die), lab 6/6 green.
2026-08-22 13:25:21 -04:00

57 lines
2.1 KiB
Plaintext

# what: the parser stops at the subcommand again, so flags after it are dropped
# why: DU-H1 as it shipped: `dotup install --unattended` ran a FULL ATTENDED install and said nothing, which is how invasive packages reached a machine that had asked for the safe defaults
# kills: install --unattended refuses invasive too
# run: unit
<<<OLD
CMD=
endopts=0
n=$#; i=0
while [ "$i" -lt "$n" ]; do
i=$((i + 1)); a=$1; shift
if [ "$endopts" -eq 0 ]; then
case $a in
--) endopts=1; continue ;;
--unattended) UNATTENDED=1; ASSUME_YES=1; continue ;;
--print|-n) DRYRUN=1; continue ;;
--yes|-y) ASSUME_YES=1; continue ;;
-h|--help) usage; exit 0 ;;
-?*) err "unknown flag: $a"; usage; exit 2 ;;
esac
fi
# The first bare word is the subcommand; every later one is an operand,
# rotated to the back of "$@" so the dispatch below reads them in the order
# they were typed with the flags taken out from between them.
if [ -z "$CMD" ]; then CMD=$a; else set -- "$@" "$a"; fi
done
# What each subcommand accepts. -1 is "as many as you like". An unknown
# subcommand, or one word more than a subcommand can use, is the same class of
# mistake as an unknown flag and gets the same answer: say so, and stop.
# This list and the dispatch below must name the same commands.
amin=0; amax=0
case ${CMD:-run} in
run|pick|install|private|render|expand-all|plan|preflight|fzf-path) ;;
toggle|toggle-shown|expand) amax=-1 ;;
preset|explain|resolve) amax=1 ;;
vercmp) amin=2; amax=2 ;;
*) err "unknown command: $CMD"; usage; exit 2 ;;
esac
[ "$#" -ge "$amin" ] || { err "${CMD:-run} needs $amin argument(s), got $#"; usage; exit 2; }
[ "$amax" -lt 0 ] || [ "$#" -le "$amax" ] || {
err "${CMD:-run} takes at most $amax argument(s), got $#:$(printf ' %s' "$@")"
usage; exit 2; }
<<<NEW
CMD=
while [ $# -gt 0 ]; do
case $1 in
--unattended) UNATTENDED=1; ASSUME_YES=1 ;;
--print|-n) DRYRUN=1 ;;
--yes|-y) ASSUME_YES=1 ;;
-h|--help) usage; exit 0 ;;
--*) err "unknown flag: $1"; usage; exit 2 ;;
*) CMD=$1; shift; break ;;
esac
shift
done
<<<END