165 lines
5.8 KiB
Bash
Executable File
165 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
|
|
|
# fake pacman (unit tests). The "real" database is $FAKE_PACMAN_DBPATH (see pacman-conf);
|
|
# -Sy --dbpath DIR logs what DIR/sync was seeded with and writes DIR/sync/su-dummy.db
|
|
# ("reviewed <n>"; plus a .sig with FAKE_PACMAN_SIG=1); -Su logs the real su-dummy.db it applies.
|
|
# FAKE_PACMAN_SUP_RC=1 makes the -Sup pre-check fail like the ignored-dependency trap;
|
|
# FAKE_PACMAN_SU_KILL=SIG: -Su signals the applet (Ctrl-C during the upgrade);
|
|
# FAKE_PACMAN_STDERR=TEXT: -Sl and -Qu also print TEXT on stderr (an unreadable database).
|
|
# -Rs --print: FAKE_PACMAN_RS_REFUSE=1 makes pacman refuse ("breaks dependency");
|
|
# FAKE_PACMAN_RS_EXTRA="pkg:other" adds other to the plan of pkg.
|
|
# FAKE_PACMAN_REASON="pkg=text" replaces the "Install Reason" of pkg in -Qi (empty text: no such line).
|
|
# FAKE_PACMAN_QU=fixture|real|none selects the -Qu sample,
|
|
# FAKE_PACMAN_SL=empty makes -Sl print nothing, FAKE_PACMAN_SUP_EXTRA="a b" adds packages that
|
|
# only -Sup (the real transaction) shows. Every -Q*/-S[il] call records its COLUMNS value, every
|
|
# call its --dbpath (or "real") in $FAKE_DIR/pacman-dbpath.
|
|
# shellcheck source=../fakelib.bash
|
|
. "${BASH_SOURCE[0]%/*}/../fakelib.bash"
|
|
fake_log "$@"
|
|
D=$FAKE_DATA/pacman
|
|
|
|
# blocks FILE NAME...: print the blank-line separated blocks whose Name is one of NAME, or whose
|
|
# Repository/Name is (-Si repo/name); all blocks when no NAME; exit 1 (after printing the others)
|
|
# if a NAME is missing
|
|
blocks() {
|
|
local f=$1 line block='' name='' repo='' rc=0 n
|
|
shift
|
|
local -A want=() found=()
|
|
for n in "$@"; do want[$n]=1; done
|
|
while IFS= read -r line || [[ -n $block ]]; do
|
|
if [[ -z $line ]]; then
|
|
if [[ -n $block ]] && { (($# == 0)) || [[ -n ${want[$name]:-} || -n ${want[$repo/$name]:-} ]]; } && ! fake_purged "$name"; then
|
|
printf '%s\n' "$block"
|
|
found[$name]=1
|
|
found[$repo/$name]=1
|
|
fi
|
|
block='' name='' repo=''
|
|
continue
|
|
fi
|
|
[[ $line =~ ^Name\ +:\ (.*)$ ]] && name=${BASH_REMATCH[1]}
|
|
[[ $line =~ ^Repository\ +:\ (.*)$ ]] && repo=${BASH_REMATCH[1]}
|
|
block+=$line$'\n'
|
|
done <"$f"
|
|
for n in "$@"; do
|
|
if [[ -z ${found[$n]:-} ]]; then
|
|
echo "error: package '$n' was not found" >&2
|
|
rc=1
|
|
fi
|
|
done
|
|
return "$rc"
|
|
}
|
|
|
|
op='' dbpath=real print=0
|
|
targets=()
|
|
while (($#)); do
|
|
case $1 in
|
|
--dbpath)
|
|
dbpath=$2
|
|
shift
|
|
;;
|
|
--logfile | --print-format | --ignore) shift ;;
|
|
--print) print=1 ;;
|
|
--*) ;;
|
|
-[A-Z]*) [[ -n $op ]] || op=$1 ;;
|
|
-*) ;;
|
|
*) targets+=("$1") ;;
|
|
esac
|
|
shift
|
|
done
|
|
echo "$op $dbpath" >>"$FAKE_DIR/pacman-dbpath"
|
|
case $op in -Q* | -Si | -Sl) echo "$op ${COLUMNS-unset}" >>"$FAKE_DIR/pacman-columns" ;; esac
|
|
|
|
qu() {
|
|
local f=$D/Qu-${FAKE_PACMAN_QU:-fixture}.txt line
|
|
[[ -f $f ]] || return 0
|
|
while IFS= read -r line; do
|
|
fake_purged "${line%% *}" || printf '%s\n' "$line"
|
|
done <"$f"
|
|
}
|
|
|
|
case $op in
|
|
-Sy)
|
|
if [[ $dbpath != real ]]; then
|
|
echo "seeded: $(cd "$dbpath/sync" && echo *)" >>"$FAKE_LOG"
|
|
rc=$(fake_rc FAKE_PACMAN_SY_RC 0)
|
|
((rc)) && exit "$rc"
|
|
n=$(($(cat "$FAKE_DIR/sy-count" 2>/dev/null || echo 0) + 1))
|
|
echo "$n" >"$FAKE_DIR/sy-count"
|
|
echo "reviewed $n" >"$dbpath/sync/su-dummy.db"
|
|
[[ -z ${FAKE_PACMAN_SIG:-} ]] || echo "signature $n" >"$dbpath/sync/su-dummy.db.sig"
|
|
fi
|
|
exit "$(fake_rc FAKE_PACMAN_SY_RC 0)"
|
|
;;
|
|
-Qu)
|
|
[[ -z ${FAKE_PACMAN_STDERR:-} ]] || echo "$FAKE_PACMAN_STDERR" >&2
|
|
out=$(qu)
|
|
[[ -n $out ]] || exit 1
|
|
printf '%s\n' "$out"
|
|
;;
|
|
-Sup)
|
|
if [[ -n ${FAKE_PACMAN_SUP_RC:-} ]]; then
|
|
echo ":: unable to satisfy dependency 'su-dummy-b>=2.0' required by su-dummy-a"
|
|
echo "error: failed to prepare transaction (could not satisfy dependencies)" >&2
|
|
exit "$FAKE_PACMAN_SUP_RC"
|
|
fi
|
|
qu | while read -r n _ _ _ flag; do [[ $flag == '[ignored]' ]] || echo "$n"; done
|
|
for n in ${FAKE_PACMAN_SUP_EXTRA:-}; do echo "$n"; done
|
|
;;
|
|
-Sl)
|
|
[[ -z ${FAKE_PACMAN_STDERR:-} ]] || echo "$FAKE_PACMAN_STDERR" >&2
|
|
[[ ${FAKE_PACMAN_SL:-} == empty ]] || cat "$D/Sl.txt"
|
|
;;
|
|
-Qi)
|
|
if [[ -z ${FAKE_PACMAN_REASON:-} ]]; then
|
|
blocks "$D/Qi.txt" "${targets[@]}"
|
|
exit
|
|
fi
|
|
rc=0
|
|
out=$(blocks "$D/Qi.txt" "${targets[@]}") || rc=$?
|
|
awk -v n="${FAKE_PACMAN_REASON%%=*}" -v r="${FAKE_PACMAN_REASON#*=}" '
|
|
/^Name +: / { cur = $0; sub(/^Name +: /, "", cur) }
|
|
/^Install Reason +: / && cur == n { if (r != "") print "Install Reason : " r; next }
|
|
{ print }' <<<"$out"
|
|
exit "$rc"
|
|
;;
|
|
-Si) blocks "$D/Si.txt" "${targets[@]}" ;;
|
|
-Su | -Syu)
|
|
echo "real sync at $op: $(cat "$FAKE_PACMAN_DBPATH/sync/su-dummy.db" 2>/dev/null || echo none) / $(cat "$FAKE_PACMAN_DBPATH/sync/su-dummy.db.sig" 2>/dev/null || echo no-sig)" >>"$FAKE_LOG"
|
|
if [[ -e $FAKE_PACMAN_DBPATH/db.lck ]]; then echo "db.lck at $op: yes" >>"$FAKE_LOG"; else echo "db.lck at $op: no" >>"$FAKE_LOG"; fi
|
|
if [[ -n ${FAKE_PACMAN_SU_KILL:-} ]]; then
|
|
kill -s "$FAKE_PACMAN_SU_KILL" "$PPID"
|
|
sleep 0.2
|
|
fi
|
|
exit "$(fake_rc FAKE_PACMAN_SU_RC 0)"
|
|
;;
|
|
-Rs)
|
|
((print)) || exit 98
|
|
tg=${targets[0]}
|
|
if [[ -n ${FAKE_PACMAN_RS_REFUSE:-} || " ${targets[*]} " == *' su-dummy-b '* && " ${targets[*]} " != *' su-dummy-a '* ]]; then
|
|
echo "checking dependencies..."
|
|
echo ":: removing $tg breaks dependency '$tg' required by su-dummy-a"
|
|
echo "error: failed to prepare transaction (could not satisfy dependencies)" >&2
|
|
exit 1
|
|
fi
|
|
for tg in "${targets[@]}"; do
|
|
case $tg in
|
|
su-dummy-a) printf '%s\n' su-dummy-a su-dummy-b ;;
|
|
su-dummy-b | su-dummy-c | glib2 | expat | ca-certificates-mozilla | pfetch | su-dummy-aur) echo "$tg" ;;
|
|
*) echo "error: target not found: $tg" >&2; exit 1 ;;
|
|
esac
|
|
for r in ${FAKE_PACMAN_RS_EXTRA:-}; do [[ ${r%%:*} == "$tg" ]] && echo "${r#*:}"; done
|
|
done
|
|
;;
|
|
-Rns)
|
|
rc=$(fake_rc FAKE_PACMAN_RNS_RC 0)
|
|
if ((rc)); then echo "error: failed to prepare transaction (could not satisfy dependencies)" >&2; else fake_mark_purged "${targets[@]}"; fi
|
|
exit "$rc"
|
|
;;
|
|
*)
|
|
echo "fake pacman: unhandled: $op $*" >&2
|
|
exit 99
|
|
;;
|
|
esac
|