N? and `info PKG` now print three lines, none indented:
PKG: <description>
reason: explicitly installed | installed as a dependency | unknown | not installed
required by: <installed dependents, comma separated> | nothing
The reason comes from a new <be>_reason backend function: apt-mark
showauto / showmanual (dpkg decides for a package in neither list), the
Install Reason of pacman -Qi, dnf repoquery --installed %{reason} (dnf4
and dnf5 words) and the Installed line of zypper info (rpm plus libzypp's
AutoInstalled when zypper is locked). A row whose old version is "-" is
not installed and the backend is not asked. The "(installed)" qualifier
moves to --help, README and DESIGN.
The rpm E2E fixture and e2e_reset now also mark su-dummy-a and su-dummy-c
as user-installed on dnf, which records plain rpm installs as "unknown",
so 1? and 2? show both reasons on all 12 distros. The verified commands
are recorded in discovery/{apt,pacman,rpm}.md.
94 lines
3.5 KiB
Bash
Executable File
94 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
|
|
|
# fake apt-mark (unit tests): hold state in $FAKE_DIR/holds (one name per line).
|
|
# FAKE_APT_MARK_LOCKED=N: the first N hold/unhold calls fail like dpkg's busy frontend lock.
|
|
# FAKE_APT_MARK_UNHOLD_SIGNAL=SIG: send SIG to the applet before an unhold (a second Ctrl-C).
|
|
# FAKE_APT_MARK_UNHOLD_RC=N: unhold fails (nothing released). FAKE_APT_MARK_FAIL_MSG: the message a
|
|
# failing hold prints. Every unhold logs whether $STATE_DIR/holds.lock is held by someone.
|
|
# showauto/showmanual: installed = the "?i" rows of data/apt/dpkg-status.tsv (not purged), auto = those
|
|
# listed in data/apt/auto.txt, manual = the others; FAKE_APT_MARK_NEITHER="pkg ..." are in neither
|
|
# list, FAKE_APT_MARK_SHOW_RC=N makes both fail. Like the real ones they print only the named
|
|
# packages (all of them without a name), native packages without their ":arch" qualifier.
|
|
# shellcheck source=../fakelib.bash
|
|
. "${BASH_SOURCE[0]%/*}/../fakelib.bash"
|
|
fake_log "$@"
|
|
h=$FAKE_DIR/holds
|
|
touch "$h"
|
|
verb=$1
|
|
shift
|
|
case $verb in hold | unhold)
|
|
if [[ -n ${FAKE_APT_MARK_LOCKED:-} ]]; then
|
|
n=$(cat "$FAKE_DIR/locked-calls" 2>/dev/null || echo 0)
|
|
if ((n < FAKE_APT_MARK_LOCKED)); then
|
|
echo $((n + 1)) >"$FAKE_DIR/locked-calls"
|
|
echo "${FAKE_APT_MARK_LOCK_MSG:-dpkg: error: dpkg frontend lock was locked by another process with pid 4242}"
|
|
echo "E: Sub-process dpkg --set-selections returned an error code (2)"
|
|
echo "E: Executing dpkg failed. Are you root?"
|
|
exit 100
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
# show_marked auto|manual NAME...
|
|
show_marked() {
|
|
local want=$1 n st name mark
|
|
shift
|
|
local -A pick=()
|
|
for n in "$@"; do pick[${n%:all}]=1; done
|
|
if [[ -n ${FAKE_APT_MARK_SHOW_RC:-} ]]; then
|
|
echo "E: Unable to determine the package states" >&2
|
|
exit "$FAKE_APT_MARK_SHOW_RC"
|
|
fi
|
|
while IFS=$'\t' read -r st name _; do
|
|
[[ $st == ?i* ]] || continue
|
|
fake_purged "$name" && continue
|
|
[[ " ${FAKE_APT_MARK_NEITHER:-} " == *" $name "* ]] && continue
|
|
if grep -qxF -- "$name" "$FAKE_DATA/apt/auto.txt"; then mark=auto; else mark=manual; fi
|
|
[[ $mark == "$want" ]] || continue
|
|
if (($# == 0)) || [[ -n ${pick[$name]:-} || -n ${pick[$name:amd64]:-} ]]; then printf '%s\n' "$name"; fi
|
|
done <"$FAKE_DATA/apt/dpkg-status.tsv" | sort
|
|
}
|
|
|
|
case $verb in
|
|
showhold) sort "$h" ;;
|
|
showauto) show_marked auto "$@" ;;
|
|
showmanual) show_marked manual "$@" ;;
|
|
hold)
|
|
for p in "$@"; do
|
|
if grep -qxF -- "$p" "$h"; then echo "$p was already set on hold."; else
|
|
echo "$p" >>"$h"
|
|
echo "$p set on hold."
|
|
fi
|
|
done
|
|
[[ -z ${FAKE_APT_MARK_FAIL_MSG:-} ]] || echo "$FAKE_APT_MARK_FAIL_MSG" >&2
|
|
exit "$(fake_rc FAKE_APT_MARK_HOLD_RC 0)"
|
|
;;
|
|
unhold)
|
|
if [[ -n ${SKEPTICAL_UPDATER_STATE_DIR:-} && -e $SKEPTICAL_UPDATER_STATE_DIR/holds.lock ]] && command -v flock >/dev/null; then
|
|
if flock -n "$SKEPTICAL_UPDATER_STATE_DIR/holds.lock" true; then l=free; else l=held; fi
|
|
echo "holds.lock during unhold: $l" >>"$FAKE_LOG"
|
|
fi
|
|
if [[ -n ${FAKE_APT_MARK_UNHOLD_RC:-} ]]; then
|
|
echo "E: Unable to correct problems" >&2
|
|
exit "$FAKE_APT_MARK_UNHOLD_RC"
|
|
fi
|
|
if [[ -n ${FAKE_APT_MARK_UNHOLD_SIGNAL:-} ]]; then
|
|
kill -s "$FAKE_APT_MARK_UNHOLD_SIGNAL" "$(cat "$FAKE_DIR/applet.pid" 2>/dev/null || echo "$PPID")" 2>/dev/null
|
|
sleep 0.2
|
|
fi
|
|
for p in "$@"; do
|
|
if grep -qxF -- "$p" "$h"; then
|
|
grep -vxF -- "$p" "$h" >"$h.new" || true
|
|
mv "$h.new" "$h"
|
|
echo "Canceled hold on $p."
|
|
else echo "$p was already not on hold."; fi
|
|
done
|
|
;;
|
|
*)
|
|
echo "fake apt-mark: unhandled: $verb $*" >&2
|
|
exit 99
|
|
;;
|
|
esac
|