1 Commits
Author SHA1 Message Date
bryanpedini 5f90c24b8d feat: allow package names in interactive info commands 2026-10-30 21:17:43 +01:00
4 changed files with 85 additions and 7 deletions

No files matched your search

+6 -1
View File
@@ -131,7 +131,12 @@ package (pacman backend with paru or yay, see below) and a space on every other
One line, whitespace-separated tokens; `N` is the number in brackets. Numbers are One line, whitespace-separated tokens; `N` is the number in brackets. Numbers are
stable for the whole session (rows that leave the list leave a gap). Every token stable for the whole session (rows that leave the list leave a gap). Every token
of a line is checked for syntax first: an unknown token rejects the line. A number of a line is checked for syntax first: an unknown token rejects the line. A number
that is not listed prints an error and the remaining commands still run. or package name that is not listed prints an error and the remaining commands still run.
For `?` and `??`, a listed package name can replace the number, for example
`su-dummy-a?` or `su-dummy-a??`. A digits-only reference is interpreted as a number.
Names are restricted to these information commands to avoid unnecessary parsing
complexity: package names may contain `-` or end in `x`, which conflicts with the
other command suffixes.
| token | action | | token | action |
|-------|--------| |-------|--------|
+5
View File
@@ -126,6 +126,11 @@ Refreshing package lists... done.
Command grammar (one line, whitespace-separated tokens, each `N` is the number in brackets): Command grammar (one line, whitespace-separated tokens, each `N` is the number in brackets):
Unknown tokens reject the line; nonexistent numbers report an error and are skipped. Unknown tokens reject the line; nonexistent numbers report an error and are skipped.
For `?` and `??`, the exact name of a listed package may replace `N`; a digits-only
reference is treated as a number. Missing or no longer listed names are reported and
skipped. Other commands accept only numbers: package names can contain `-` or end in
`x`, and limiting name references to information commands avoids unnecessary parsing
complexity.
Consecutive `N+` commands and `*+` trust the selected dependency roots, recording Consecutive `N+` commands and `*+` trust the selected dependency roots, recording
other selected packages in their closures as dependencies regardless of input order. other selected packages in their closures as dependencies regardless of input order.
+26 -6
View File
@@ -6,7 +6,7 @@
# and zypper: list what would be upgraded, interrogate every package, remember the # and zypper: list what would be upgraded, interrogate every package, remember the
# ones you trust, then run the native upgrade (with per-run exclusions). # ones you trust, then run the native upgrade (with per-run exclusions).
# #
# Version: 0.2.0 # Version: 0.3.0
# #
# Specification: docs/DESIGN.md. Single file, bash >= 4.3, no runtime dependency # Specification: docs/DESIGN.md. Single file, bash >= 4.3, no runtime dependency
# beyond the distro's package manager and coreutils/sed/grep (awk only on the apt # beyond the distro's package manager and coreutils/sed/grep (awk only on the apt
@@ -23,7 +23,7 @@ export LC_ALL=C DEBIAN_FRONTEND=noninteractive
# never read from or written to a file (no HISTFILE; `history -r`/`-w`/`-a` are never used). # never read from or written to a file (no HISTFILE; `history -r`/`-w`/`-a` are never used).
unset HISTFILE unset HISTFILE
readonly SU_VERSION=0.2.0 readonly SU_VERSION=0.3.0
readonly SU_PROG=skeptical-updater readonly SU_PROG=skeptical-updater
readonly SU_STATE_HEADER='# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)' readonly SU_STATE_HEADER='# skeptical-updater trusted packages. Columns: backend package reason added(UTC ISO-8601)'
readonly SU_PROMPT_HELP='<enter> upgrade | N? what is it | N?? full info | N- exclude this run | Nx purge now | N+ trust forever' readonly SU_PROMPT_HELP='<enter> upgrade | N? what is it | N?? full info | N- exclude this run | Nx purge now | N+ trust forever'
@@ -114,6 +114,7 @@ interactive commands (one line, whitespace-separated tokens, N = number in brack
that depend on it - installed packages only that depend on it - installed packages only
N?? full native info: the installed record; lines starting with '*' come N?? full native info: the installed record; lines starting with '*' come
from the upstream candidate (differing values, fields it adds) from the upstream candidate (differing values, fields it adds)
For N? and N??, a listed package name may be used instead of N.
N- exclude from this run (toggle); shown with a '-' marker N- exclude from this run (toggle); shown with a '-' marker
Nx purge it now with its now-unneeded dependencies (shown, asks y/N); refused Nx purge it now with its now-unneeded dependencies (shown, asks y/N); refused
when other installed packages depend on it, like pacman -Rns when other installed packages depend on it, like pacman -Rns
@@ -138,6 +139,7 @@ session_help() {
<enter> upgrade now, skipping the rows marked '-' <enter> upgrade now, skipping the rows marked '-'
N? what is it: description, install reason + installed packages that need it N? what is it: description, install reason + installed packages that need it
N?? full native info: installed record, '*' lines from the upstream candidate N?? full native info: installed record, '*' lines from the upstream candidate
A listed package name may replace N for ? and ?? (e.g. okular?).
N- exclude N from this run (toggle) N- exclude N from this run (toggle)
Nx purge N now: lists every package the purge removes, then asks y/N. Nx purge N now: lists every package the purge removes, then asks y/N.
x refuses when other installed packages depend on the target, like x refuses when other installed packages depend on the target, like
@@ -2767,17 +2769,18 @@ SESSION_PROCEED=0
UPGRADE_FAILED_MSG= # set by <be>_upgrade when the failing step is not the package manager's own UPGRADE_FAILED_MSG= # set by <be>_upgrade when the failing step is not the package manager's own
session_line() { session_line() {
local tok n op i local tok n op i name
local -a toks=() batch=() local -a toks=() batch=()
local -A initial=() local -A initial=() named=()
local re='^([0-9]{1,6})(\?\?|\?|-|x|\+)$' local re='^([0-9]{1,6})(\?\?|\?|-|x|\+)$'
local name_re='^([A-Za-z0-9_+@][A-Za-z0-9_+.@:~-]*)(\?\?|\?)$'
read -r -a toks <<<"$1" || true read -r -a toks <<<"$1" || true
if ((${#toks[@]} == 0)); then if ((${#toks[@]} == 0)); then
SESSION_PROCEED=1 SESSION_PROCEED=1
return 0 return 0
fi fi
for tok in "${toks[@]}"; do for tok in "${toks[@]}"; do
if [[ ! $tok =~ $re ]]; then if [[ ! $tok =~ $re && ! $tok =~ $name_re ]]; then
case $tok in case $tok in
'*+' | '*-' | l | q | h | '?') ;; '*+' | '*-' | l | q | h | '?') ;;
*) *)
@@ -2788,7 +2791,10 @@ session_line() {
fi fi
done done
for ((n = 1; n <= N_MAX; n++)); do for ((n = 1; n <= N_MAX; n++)); do
if num_row "$n"; then initial[$n]=$REPLY; fi if num_row "$n"; then
initial[$n]=$REPLY
named[${R_NAME[REPLY]}]=$REPLY
fi
done done
for tok in "${toks[@]}"; do for tok in "${toks[@]}"; do
if [[ $tok =~ $re ]]; then if [[ $tok =~ $re ]]; then
@@ -2824,6 +2830,20 @@ session_line() {
fi fi
;; ;;
esac esac
elif [[ $tok =~ $name_re ]]; then
name=${BASH_REMATCH[1]}
op=${BASH_REMATCH[2]}
if [[ -z ${named[$name]+x} ]] || ((R_GONE[${named[$name]:-0}])); then
err "no package '$name' in the list (l to redraw)"
continue
fi
i=${named[$name]}
if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi
if [[ $op == '?' ]]; then
print_info "${R_NAME[i]}" "${R_OLD[i]}" || true
else
print_full_info "${R_NAME[i]}" "${R_OLD[i]}" || true
fi
else else
if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi if ((${#batch[@]})); then session_trust "${batch[@]}"; batch=(); fi
case $tok in case $tok in
+48
View File
@@ -101,6 +101,54 @@ UPGRADE='apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--forc
log_has 'apt-cache show --no-all-versions su-dummy-a' log_has 'apt-cache show --no-all-versions su-dummy-a'
} }
@test "listed package names support both information commands alongside numeric commands" {
run skup --no-refresh <<<$'su-dummy-a? 2? su-dummy-b?? 3-\nq'
assert_success
assert_line 'su-dummy-a: dummy package su-dummy-a for skeptical-updater tests'
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
assert_line ' Package: su-dummy-b'
assert_line 'excluded from this run: su-dummy-c'
log_has 'dpkg-query -s -- su-dummy-b'
}
@test "unknown or hidden package names report an error and do not stop later commands" {
write_state "$HEADER" "apt${T}su-dummy-a${T}user${T}2026-01-01T00:00:00Z"
run skup --no-refresh <<<$'missing? su-dummy-a?? 2?\nq'
assert_success
assert_output --partial "no package 'missing' in the list"
assert_output --partial "no package 'su-dummy-a' in the list"
assert_line 'su-dummy-c: dummy package su-dummy-c for skeptical-updater tests'
}
@test "names work for trusted rows shown with --all and new dependencies" {
write_state "$HEADER" "apt${T}su-dummy-a${T}user${T}2026-01-01T00:00:00Z"
run skup --no-refresh --all <<<$'su-dummy-a?\nq'
assert_success
assert_line 'su-dummy-a: dummy package su-dummy-a for skeptical-updater tests'
FAKE_APT_SIM=real run skup --no-refresh <<<$'su-dummy-newdep? su-dummy-newdep??\nq'
assert_success
assert_line 'reason: not installed'
log_lacks '^dpkg-query -s -- su-dummy-newdep'
log_has 'apt-cache show --no-all-versions su-dummy-newdep'
}
@test "a package removed during a line cannot be queried by name" {
run skup --no-refresh <<<$'3x su-dummy-c? 2?\ny\nq'
assert_success
assert_output --partial "no package 'su-dummy-c' in the list"
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
}
@test "package names are not accepted for trust, exclude or purge" {
for token in su-dummy-a+ su-dummy-a- su-dummy-ax; do
run skup --no-refresh <<<"$token"$'\nq'
assert_success
assert_output --partial "unknown command '$token'"
[[ ! -e $STATE_FILE ]]
log_lacks '^apt-get -y purge'
done
}
@test "N?? on a new dependency (old version -) never looks for an installed record" { @test "N?? on a new dependency (old version -) never looks for an installed record" {
FAKE_APT_SIM=real run skup --no-refresh <<<$'9??\nq' FAKE_APT_SIM=real run skup --no-refresh <<<$'9??\nq'
assert_success assert_success