summaryrefslogtreecommitdiff
path: root/scripts/package-inventory
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/package-inventory')
-rwxr-xr-xscripts/package-inventory222
1 files changed, 222 insertions, 0 deletions
diff --git a/scripts/package-inventory b/scripts/package-inventory
new file mode 100755
index 0000000..4742645
--- /dev/null
+++ b/scripts/package-inventory
@@ -0,0 +1,222 @@
+#!/bin/bash
+# package-inventory - Compare archsetup packages vs live system
+# Shows: packages in archsetup but missing from system,
+# packages on system but not in archsetup
+#
+# Usage: package-inventory [--archsetup-only | --system-only | --summary]
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
+ARCHSETUP="$SCRIPT_DIR/archsetup"
+
+# Colors
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+CYAN='\033[0;36m'
+BOLD='\033[1m'
+NC='\033[0m'
+
+# ============================================================================
+# Extract packages from archsetup script
+# ============================================================================
+extract_archsetup_packages() {
+ local tmp
+ tmp=$(mktemp)
+
+ # Extract pacman_install and aur_install calls (single package per line)
+ grep -E '^\s*(pacman_install|aur_install)\s+' "$ARCHSETUP" \
+ | grep -v '^\s*#' \
+ | sed -E 's/^\s*(pacman_install|aur_install)\s+//' \
+ | sed -E 's/\s*#.*//' \
+ | sed 's/"//g' \
+ | grep -v '^\$' \
+ >> "$tmp"
+
+ # Extract packages from for-loops: "for software in pkg1 pkg2 pkg3 ...; do"
+ # These span multiple lines with backslash continuations
+ awk '
+ /for software in/ { capture=1; sub(/.*for software in/, ""); }
+ capture {
+ cont = ($0 ~ /\\$/)
+ gsub(/\\/, "");
+ gsub(/;.*/, "");
+ gsub(/do$/, "");
+ # Print each word as a package
+ for (i=1; i<=NF; i++) {
+ pkg = $i
+ # Skip shell syntax
+ if (pkg ~ /^\$|^#|^for|^in|^do|^done/) continue
+ gsub(/"/, "", pkg)
+ if (pkg != "") print pkg
+ }
+ if (!cont) capture=0
+ }
+ ' "$ARCHSETUP" >> "$tmp"
+
+ # Extract pipx packages (these won't be in pacman -Qqe, note them separately)
+ # Skip for now — pipx packages aren't pacman-managed
+
+ sort -u "$tmp"
+ rm -f "$tmp"
+}
+
+# ============================================================================
+# Get packages on live system
+# ============================================================================
+get_system_packages_explicit() {
+ pacman -Qqe | sort -u # explicitly installed
+}
+
+get_system_packages_all() {
+ pacman -Qq | sort -u # all installed (including deps)
+}
+
+# ============================================================================
+# Categorize system packages
+# ============================================================================
+get_system_native() {
+ pacman -Qqen | sort -u # native (official repos)
+}
+
+get_system_foreign() {
+ pacman -Qqem | sort -u # foreign (AUR/manual)
+}
+
+# ============================================================================
+# Main comparison
+# ============================================================================
+main() {
+ local mode="${1:-}"
+
+ local archsetup_pkgs system_explicit system_all
+ archsetup_pkgs=$(extract_archsetup_packages)
+ system_explicit=$(get_system_packages_explicit)
+ system_all=$(get_system_packages_all)
+
+ # "not installed" = not on system at all (filters out dep-installed packages)
+ # "not in archsetup" = explicitly installed but not declared in archsetup
+ local missing_from_system missing_from_archsetup in_both
+ missing_from_system=$(comm -23 <(echo "$archsetup_pkgs") <(echo "$system_all"))
+ missing_from_archsetup=$(comm -13 <(echo "$archsetup_pkgs") <(echo "$system_explicit"))
+ in_both=$(comm -12 <(echo "$archsetup_pkgs") <(echo "$system_explicit"))
+
+ local archsetup_count system_count both_count missing_sys_count missing_arch_count
+ archsetup_count=$(echo "$archsetup_pkgs" | wc -l)
+ system_count=$(echo "$system_explicit" | wc -l)
+ both_count=$(echo "$in_both" | grep -c . || true)
+ missing_sys_count=$(echo "$missing_from_system" | grep -c . || true)
+ missing_arch_count=$(echo "$missing_from_archsetup" | grep -c . || true)
+
+ case "$mode" in
+ --archsetup-only)
+ echo "$missing_from_system"
+ ;;
+ --system-only)
+ echo "$missing_from_archsetup"
+ ;;
+ --summary)
+ print_summary "$archsetup_count" "$system_count" "$both_count" \
+ "$missing_sys_count" "$missing_arch_count"
+ ;;
+ --help|-h)
+ echo "Usage: package-inventory [OPTION]"
+ echo ""
+ echo "Compare packages in archsetup script vs installed on this system."
+ echo ""
+ echo "Options:"
+ echo " (none) Full report with all sections"
+ echo " --archsetup-only Packages in archsetup but not on system (plain list)"
+ echo " --system-only Packages on system but not in archsetup (plain list)"
+ echo " --summary Summary counts only"
+ echo " --help This help message"
+ ;;
+ "")
+ print_full_report "$archsetup_pkgs" "$system_explicit" \
+ "$missing_from_system" "$missing_from_archsetup" "$in_both" \
+ "$archsetup_count" "$system_count" "$both_count" \
+ "$missing_sys_count" "$missing_arch_count"
+ ;;
+ *)
+ echo "Unknown option: $mode" >&2
+ echo "Run with --help for usage." >&2
+ exit 1
+ ;;
+ esac
+}
+
+# ============================================================================
+# Output formatting
+# ============================================================================
+print_summary() {
+ local archsetup_count="$1" system_count="$2" both_count="$3"
+ local missing_sys_count="$4" missing_arch_count="$5"
+
+ echo -e "${BOLD}Package Inventory Summary${NC}"
+ echo "─────────────────────────────────────"
+ echo -e " Archsetup declares: ${CYAN}${archsetup_count}${NC} packages"
+ echo -e " System has installed: ${CYAN}${system_count}${NC} packages (explicit)"
+ echo -e " In common: ${GREEN}${both_count}${NC}"
+ echo -e " In archsetup, not system: ${YELLOW}${missing_sys_count}${NC}"
+ echo -e " On system, not archsetup: ${YELLOW}${missing_arch_count}${NC}"
+}
+
+print_full_report() {
+ local archsetup_pkgs="$1" system_pkgs="$2"
+ local missing_from_system="$3" missing_from_archsetup="$4" in_both="$5"
+ local archsetup_count="$6" system_count="$7" both_count="$8"
+ local missing_sys_count="$9" missing_arch_count="${10}"
+
+ echo ""
+ print_summary "$archsetup_count" "$system_count" "$both_count" \
+ "$missing_sys_count" "$missing_arch_count"
+
+ if [[ -n "$missing_from_system" ]]; then
+ echo ""
+ echo -e "${BOLD}${YELLOW}In archsetup but NOT installed on this system (${missing_sys_count}):${NC}"
+ echo -e "${YELLOW}These may need installing, or are for a different desktop/hardware.${NC}"
+ echo "─────────────────────────────────────"
+ echo "$missing_from_system" | while read -r pkg; do
+ echo " $pkg"
+ done
+ fi
+
+ if [[ -n "$missing_from_archsetup" ]]; then
+ echo ""
+ echo -e "${BOLD}${YELLOW}On system but NOT in archsetup (${missing_arch_count}):${NC}"
+ echo -e "${YELLOW}Add to archsetup, or remove from system if no longer needed.${NC}"
+ echo "─────────────────────────────────────"
+
+ # Split into native and foreign for easier review
+ local native foreign
+ native=$(get_system_native)
+ foreign=$(get_system_foreign)
+
+ local foreign_extras native_extras
+ foreign_extras=$(comm -12 <(echo "$missing_from_archsetup") <(echo "$foreign"))
+ native_extras=$(comm -12 <(echo "$missing_from_archsetup") <(echo "$native"))
+
+ local foreign_count native_count
+ foreign_count=$(echo "$foreign_extras" | grep -c . || true)
+ native_count=$(echo "$native_extras" | grep -c . || true)
+
+ if [[ -n "$foreign_extras" ]]; then
+ echo -e " ${CYAN}AUR/foreign (${foreign_count}):${NC}"
+ echo "$foreign_extras" | while read -r pkg; do
+ echo " $pkg"
+ done
+ fi
+
+ if [[ -n "$native_extras" ]]; then
+ echo -e " ${CYAN}Official repos (${native_count}):${NC}"
+ echo "$native_extras" | while read -r pkg; do
+ echo " $pkg"
+ done
+ fi
+ fi
+
+ echo ""
+}
+
+main "$@"