diff options
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/audit-packages.sh | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/scripts/audit-packages.sh b/scripts/audit-packages.sh new file mode 100755 index 0000000..f7af19f --- /dev/null +++ b/scripts/audit-packages.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# audit-packages.sh — verify every package archsetup installs still exists +# at its declared source, and flag packages that moved between the official +# repos and the AUR. +# +# Extraction covers direct `pacman_install pkg` / `aur_install pkg` calls +# and `for software in a b c; do` loop lists (backslash continuations +# included). Variable arguments ("$software") are the loop plumbing, not +# packages, and are skipped. +# +# Checks: +# official package missing from sync dbs -> MOVED TO AUR (if AUR has it) +# or MISSING EVERYWHERE +# AUR package gone from the AUR -> NOW IN OFFICIAL (if repos +# have it) or MISSING EVERYWHERE +# +# Usage: audit-packages.sh [--list] [installer-script] +# --list print the extracted package lists and exit (no network) +# default audit; exit 1 when anything is missing or moved +# +# Env overrides (tests): AUDIT_PACMAN, AUDIT_CURL. + +set -u + +PACMAN="${AUDIT_PACMAN:-pacman}" +CURL="${AUDIT_CURL:-curl}" + +mode=audit +case "${1:-}" in + --list) mode=list; shift ;; +esac + +script="${1:-$(dirname "$0")/../archsetup}" +if [ ! -r "$script" ]; then + echo "audit-packages: cannot read installer script: $script" >&2 + exit 2 +fi + +# Extract package names per source. Loop lists are attributed to the +# install command used inside the loop body. +extract() { + awk ' + # Collect a `for software in ...` list (may span backslash-continued + # lines); attribute it when the loop body shows which installer runs. + /for[ \t]+[A-Za-z_]+[ \t]+in[ \t]/ { + line = $0 + sub(/^.*[ \t]in[ \t]+/, "", line) + listpkgs = "" + while (1) { + stop = (line ~ /;[ \t]*do([ \t]|$)/) + sub(/;[ \t]*do.*$/, "", line) + gsub(/\\/, "", line) + listpkgs = listpkgs " " line + if (stop) break + if ((getline line) <= 0) break + } + pending = listpkgs + next + } + /^[ \t]*(pacman_install|aur_install)[ \t]/ { + cmd = ($0 ~ /pacman_install/) ? "official" : "aur" + arg = $2 + gsub(/["'\'']/, "", arg) + if (arg ~ /^\$/) { + # loop plumbing — emit the pending for-list under this source + n = split(pending, w, /[ \t]+/) + for (i = 1; i <= n; i++) if (w[i] != "") print cmd, w[i] + pending = "" + } else if (arg != "") { + print cmd, arg + } + } + ' "$script" | sort -u +} + +pairs=$(extract) +official=$(echo "$pairs" | awk '$1 == "official" { print $2 }') +aur=$(echo "$pairs" | awk '$1 == "aur" { print $2 }') + +if [ "$mode" = list ]; then + echo "OFFICIAL ($(echo "$official" | grep -c .)):" + echo "$official" | sed 's/^/ /' + echo "AUR ($(echo "$aur" | grep -c .)):" + echo "$aur" | sed 's/^/ /' + exit 0 +fi + +# One batched AUR RPC query answers existence for every AUR-relevant name. +aur_query() { + # args: package names; prints the names the AUR knows + local args="" p + for p in "$@"; do args="$args&arg[]=$p"; done + "$CURL" -sm 20 "https://aur.archlinux.org/rpc/v5/info?${args#&}" 2>/dev/null \ + | tr ',' '\n' | sed -n 's/.*"Name":[[:space:]]*"\([^"]*\)".*/\1/p' +} + +# shellcheck disable=SC2086 +aur_known=$(aur_query $official $aur) + +in_repos() { "$PACMAN" -Si "$1" >/dev/null 2>&1; } +in_aur() { echo "$aur_known" | grep -qx "$1"; } + +moved_to_aur="" now_official="" missing="" +for p in $official; do + in_repos "$p" && continue + if in_aur "$p"; then moved_to_aur="$moved_to_aur $p"; else missing="$missing $p"; fi +done +for p in $aur; do + if in_aur "$p"; then + in_repos "$p" && now_official="$now_official $p (also in repos)" + continue + fi + if in_repos "$p"; then now_official="$now_official $p"; else missing="$missing $p"; fi +done + +rc=0 +if [ -n "$missing" ]; then + echo "MISSING EVERYWHERE (not in repos, not in AUR):" + for p in $missing; do echo " $p"; done + rc=1 +fi +if [ -n "$moved_to_aur" ]; then + echo "MOVED TO AUR (pacman_install will fail; switch to aur_install):" + for p in $moved_to_aur; do echo " $p"; done + rc=1 +fi +if [ -n "$now_official" ]; then + echo "NOW IN OFFICIAL (aur_install works but pacman_install is cleaner):" + echo "$now_official" | tr ' ' '\n' | grep -v '^$' | sed 's/^/ /' + rc=1 +fi +total=$(( $(echo "$official" | grep -c .) + $(echo "$aur" | grep -c .) )) +echo "---" +echo "$total packages audited" +exit $rc |
