#!/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