feat: trust topmost installed dependents
This commit is contained in:
1 parent
6da4312f5c
commit
a059e37564
3 files changed
+112
-3
No files matched your search
@@ -146,6 +146,7 @@ other command suffixes.
|
|||||||
| `N-` | exclude from this run (toggle; `N-` again re-includes); shown with a `-` marker |
|
| `N-` | exclude from this run (toggle; `N-` again re-includes); shown with a `-` marker |
|
||||||
| `Nx` | purge now, with its now-unneeded dependencies: the purge is simulated first and the prompt lists everything it removes (`Purge su-dummy-a now? This also removes: su-dummy-b [y/N]`); the answer is read from the same stdin; the rows of every removed package leave the list. `x` refuses when other installed packages depend on the target, like `pacman -Rns`; purge the dependents first (`not purged: su-dummy-b is required by: su-dummy-a - purge the dependents first`). Rows with old version `-` (new dependencies, not installed) cannot be purged |
|
| `Nx` | purge now, with its now-unneeded dependencies: the purge is simulated first and the prompt lists everything it removes (`Purge su-dummy-a now? This also removes: su-dummy-b [y/N]`); the answer is read from the same stdin; the rows of every removed package leave the list. `x` refuses when other installed packages depend on the target, like `pacman -Rns`; purge the dependents first (`not purged: su-dummy-b is required by: su-dummy-a - purge the dependents first`). Rows with old version `-` (new dependencies, not installed) cannot be purged |
|
||||||
| `N+` | trust forever: write it and its installed dependency closure to the statefile; the row leaves the list. Rows this hides are re-included if they were excluded (a trusted package is upgraded) |
|
| `N+` | trust forever: write it and its installed dependency closure to the statefile; the row leaves the list. Rows this hides are re-included if they were excluded (a trusted package is upgraded) |
|
||||||
|
| `N++` | follow installed dependents recursively and trust each topmost package and its installed dependencies, even when a topmost package is not in the update list |
|
||||||
| `*+` / `*-` | `+` / `-` for every listed package (`*-` is an all-or-nothing toggle: when all are excluded it re-includes them) |
|
| `*+` / `*-` | `+` / `-` for every listed package (`*-` is an all-or-nothing toggle: when all are excluded it re-includes them) |
|
||||||
| `a` | show packages trusted during this session again, marked with `=`; packages already trusted before the session remain hidden |
|
| `a` | show packages trusted during this session again, marked with `=`; packages already trusted before the session remain hidden |
|
||||||
| `l` | redraw the list |
|
| `l` | redraw the list |
|
||||||
|
|||||||
+67
-3
@@ -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.5.0
|
# Version: 0.6.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.5.0
|
readonly SU_VERSION=0.6.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'
|
||||||
@@ -120,6 +120,7 @@ interactive commands (one line, whitespace-separated tokens, N = number in brack
|
|||||||
when other installed packages depend on it, like pacman -Rns
|
when other installed packages depend on it, like pacman -Rns
|
||||||
consecutive Nx commands are purged together after one confirmation
|
consecutive Nx commands are purged together after one confirmation
|
||||||
N+ trust it forever (with its installed dependency closure)
|
N+ trust it forever (with its installed dependency closure)
|
||||||
|
N++ trust the topmost installed dependents and their dependency closures
|
||||||
*+ / *- apply + / - to every listed package
|
*+ / *- apply + / - to every listed package
|
||||||
a show packages trusted during this session again
|
a show packages trusted during this session again
|
||||||
l redraw the list
|
l redraw the list
|
||||||
@@ -148,6 +149,7 @@ session_help() {
|
|||||||
pacman -Rns; purge the dependents first
|
pacman -Rns; purge the dependents first
|
||||||
consecutive Nx commands are purged together after one confirmation
|
consecutive Nx commands are purged together after one confirmation
|
||||||
N+ trust N (and its installed dependencies) forever
|
N+ trust N (and its installed dependencies) forever
|
||||||
|
N++ trust the topmost installed dependents of N and their dependencies
|
||||||
*+ *- trust / exclude every listed package (*- again re-includes them)
|
*+ *- trust / exclude every listed package (*- again re-includes them)
|
||||||
a show packages trusted during this session again
|
a show packages trusted during this session again
|
||||||
l redraw the list (a '*' after the number marks an AUR package)
|
l redraw the list (a '*' after the number marks an AUR package)
|
||||||
@@ -2785,6 +2787,11 @@ session_trust() { # session_trust IDX...
|
|||||||
trust_pkg "${R_NAME[i]}" "$now"
|
trust_pkg "${R_NAME[i]}" "$now"
|
||||||
R_EXCL[i]=0
|
R_EXCL[i]=0
|
||||||
done
|
done
|
||||||
|
session_finish_trust
|
||||||
|
}
|
||||||
|
|
||||||
|
session_finish_trust() {
|
||||||
|
local i
|
||||||
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
||||||
if ((R_NUM[i] > 0 && !R_GONE[i])) && is_trusted "${R_NAME[i]}"; then SESSION_TRUSTED[${R_NAME[i]}]=1; fi
|
if ((R_NUM[i] > 0 && !R_GONE[i])) && is_trusted "${R_NAME[i]}"; then SESSION_TRUSTED[${R_NAME[i]}]=1; fi
|
||||||
done
|
done
|
||||||
@@ -2798,6 +2805,62 @@ session_trust() { # session_trust IDX...
|
|||||||
state_save
|
state_save
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_trust_dependents() {
|
||||||
|
local i=$1 node dep out root other candidate now head blocked
|
||||||
|
local -a queue=() nodes=() roots=() walk=() deps=()
|
||||||
|
local -A seen=() edges=() reach=() visited=()
|
||||||
|
if [[ ${R_OLD[i]} == - ]]; then
|
||||||
|
say "${R_NAME[i]} is not installed: cannot find installed dependents."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
queue=("${R_NAME[i]}")
|
||||||
|
seen[${R_NAME[i]}]=1
|
||||||
|
for ((head = 0; head < ${#queue[@]}; head++)); do
|
||||||
|
node=${queue[head]}
|
||||||
|
nodes+=("$node")
|
||||||
|
if ! out=$(be rdepends "$node"); then
|
||||||
|
err "cannot find installed dependents of $node; nothing was trusted"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
while IFS= read -r dep; do
|
||||||
|
[[ -n $dep ]] || continue
|
||||||
|
edges[$node]+=" $dep"
|
||||||
|
if [[ -z ${seen[$dep]+x} ]]; then seen[$dep]=1; queue+=("$dep"); fi
|
||||||
|
done <<<"$out"
|
||||||
|
done
|
||||||
|
for root in "${nodes[@]}"; do
|
||||||
|
walk=("$root")
|
||||||
|
visited=(["$root"]=1)
|
||||||
|
for ((head = 0; head < ${#walk[@]}; head++)); do
|
||||||
|
node=${walk[head]}
|
||||||
|
read -r -a deps <<<"${edges[$node]-}"
|
||||||
|
for dep in "${deps[@]}"; do
|
||||||
|
[[ -z ${visited[$dep]+x} ]] || continue
|
||||||
|
visited[$dep]=1
|
||||||
|
walk+=("$dep")
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for node in "${walk[@]}"; do reach["$root,$node"]=1; done
|
||||||
|
done
|
||||||
|
mapfile -t nodes < <(printf '%s\n' "${nodes[@]}" | sort -u)
|
||||||
|
for root in "${nodes[@]}"; do
|
||||||
|
blocked=0
|
||||||
|
for other in "${nodes[@]}"; do
|
||||||
|
[[ $root != "$other" && -n ${reach[$root,$other]+x} ]] || continue
|
||||||
|
if [[ -z ${reach[$other,$root]+x} || $other < $root ]]; then blocked=1; break; fi
|
||||||
|
done
|
||||||
|
((blocked)) || roots+=("$root")
|
||||||
|
done
|
||||||
|
now=$(now_utc)
|
||||||
|
for candidate in "${roots[@]}"; do
|
||||||
|
trust_pkg "$candidate" "$now"
|
||||||
|
for ((i = 0; i < ${#R_NAME[@]}; i++)); do
|
||||||
|
[[ ${R_NAME[i]} != "$candidate" ]] || R_EXCL[i]=0
|
||||||
|
done
|
||||||
|
done
|
||||||
|
session_finish_trust
|
||||||
|
}
|
||||||
|
|
||||||
session_toggle_all() {
|
session_toggle_all() {
|
||||||
local i all=1
|
local i all=1
|
||||||
local -a idx=()
|
local -a idx=()
|
||||||
@@ -2833,7 +2896,7 @@ session_line() {
|
|||||||
local tok n op i name
|
local tok n op i name
|
||||||
local -a toks=() batch=() purge_batch=()
|
local -a toks=() batch=() purge_batch=()
|
||||||
local -A initial=() named=()
|
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_+.@:~-]*)(\?\?|\?)$'
|
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
|
||||||
@@ -2893,6 +2956,7 @@ session_line() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
case $op in
|
case $op in
|
||||||
|
'++') session_trust_dependents "$i" ;;
|
||||||
'?') print_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
'?') print_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
||||||
'??') print_full_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
'??') print_full_info "${R_NAME[i]}" "${R_OLD[i]}" || true ;;
|
||||||
-)
|
-)
|
||||||
|
|||||||
@@ -555,3 +555,47 @@ UPGRADE='apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--forc
|
|||||||
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
|
assert_line 'su-dummy-b: dummy package su-dummy-b for skeptical-updater tests'
|
||||||
refute_output --partial '=[3] su-dummy-c'
|
refute_output --partial '=[3] su-dummy-c'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "N++ trusts the topmost installed dependent and its dependencies" {
|
||||||
|
run skup --no-refresh <<<$'2++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'trusted su-dummy-a (+1 dependency: su-dummy-b)'
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-a${T}user"
|
||||||
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ trusts all topmost branches including packages outside the list" {
|
||||||
|
local fixture_data="$BATS_TEST_TMPDIR/data"
|
||||||
|
cp -R "$FAKE_DATA" "$fixture_data"
|
||||||
|
printf 'su-dummy-b\nReverse Depends:\n su-dummy-a\n su-dummy-c\n' >"$fixture_data/apt/rdepends/su-dummy-b"
|
||||||
|
printf 'su-dummy-a\nReverse Depends:\n su-dummy-w\n' >"$fixture_data/apt/rdepends/su-dummy-a"
|
||||||
|
sed -i 's/su-virtual | su-dummy-alt/su-dummy-a/; s/^ii \(.*su-dummy-c\)\t\t\t\t/ii \1\t\tsu-dummy-b\t/' "$fixture_data/apt/dpkg-status.tsv"
|
||||||
|
FAKE_DATA="$fixture_data" run skup --no-refresh <<<$'2++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'trusted su-dummy-c'
|
||||||
|
assert_output --partial 'trusted su-dummy-w'
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-c${T}user"
|
||||||
|
assert_line "su-dummy-w${T}user"
|
||||||
|
assert_line "su-dummy-a${T}dep:su-dummy-w"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ terminates on a dependency cycle and chooses one root" {
|
||||||
|
local fixture_data="$BATS_TEST_TMPDIR/data"
|
||||||
|
cp -R "$FAKE_DATA" "$fixture_data"
|
||||||
|
printf 'su-dummy-a\nReverse Depends:\n su-dummy-b\n' >"$fixture_data/apt/rdepends/su-dummy-a"
|
||||||
|
sed -i 's/^ii \(.*su-dummy-b\)\t\t\t\t/ii \1\t\tsu-dummy-a\t/' "$fixture_data/apt/dpkg-status.tsv"
|
||||||
|
FAKE_DATA="$fixture_data" run skup --no-refresh <<<$'2++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_output --partial 'trusted su-dummy-a'
|
||||||
|
run cut -f2,3 "$STATE_FILE"
|
||||||
|
assert_line "su-dummy-a${T}user"
|
||||||
|
assert_line "su-dummy-b${T}dep:su-dummy-a"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "N++ trusts the package itself when it has no installed dependents" {
|
||||||
|
run skup --no-refresh <<<$'3++\nq'
|
||||||
|
assert_success
|
||||||
|
assert_line 'trusted su-dummy-c'
|
||||||
|
}
|
||||||
Reference in new issue
Block a user