#!/bin/bash # Verifies installed packages come from the expected source (pacman/AUR/flatpak). # Reports missing packages, wrong-source installs, and unexpected foreign packages. # Pass --fix / -f to automatically reinstall packages from the correct source. set -euo pipefail RED="\e[31m"; YELLOW="\e[33m"; GREEN="\e[32m"; CYAN="\e[36m"; BOLD="\e[1m"; RESET="\e[0m" ok() { echo -e " ${GREEN}✔${RESET} $1"; } warn() { echo -e " ${YELLOW}⚠${RESET} $1"; } err() { echo -e " ${RED}✘${RESET} $1"; } hdr() { echo -e "\n${BOLD}${CYAN}$1${RESET}"; } fix() { echo -e " ${CYAN}↺${RESET} $1"; } FIX=0 [[ "${1:-}" == "--fix" || "${1:-}" == "-f" ]] && FIX=1 ISSUES=0 flag() { ISSUES=$((ISSUES + 1)); } WRONG_SOURCE_OFFICIAL=() # expected from pacman, installed from AUR WRONG_SOURCE_AUR=() # expected from AUR, installed from official # --------------------------------------------------------------------------- # Expected package sources — keep in sync with setup/modules/ # --------------------------------------------------------------------------- PACMAN_PKGS=( # core-packages.sh 7zip arch-install-scripts atftp atool base base-devel bind bluez btrfs-progs btop cockpit cockpit-files cockpit-podman cronie curl distrobox fail2ban fastfetch fd ffmpeg firefox flatpak gcc glib2 greetd-tuigreet grub htop inetutils iwd jq ldns less libpulse linux linux-firmware man-db mc nano neovim networkmanager openssh pamtester pciutils pipewire podman podman-compose python python-pip qrencode ruby-pkg-config rust rustup ipcalc iputils mtr net-tools nmap smartmontools symlinks tcpdump traceroute tree udisks2 udisks2-btrfs udiskie ufw usbutils vim vnstat wget wireplumber wireless_tools wpa_supplicant wprs yazi zip unzip zram-generator # shell-setup.sh zsh pyright bash atftp bash-language-server clang fzf hyfetch lua-language-server micro pulsemixer z dysk glow # hyprland.sh (official-repo portion) hyprland hyprcursor wl-clipboard hyprpaper hyprlock wofi kitty dunst nwg-dock-hyprland nwg-drawer nwg-menu nwg-look cmake meson cpio pkgconf hyprsunset hypridle ksshaskpass nm-connection-editor network-manager-applet blueman pipewire alsa-utils greetd-tuigreet grim slurp gst-plugin-pipewire imagemagick nerd-fonts otf-font-awesome pipewire-alsa pipewire-jack pipewire-pulse qt5-wayland qt6-wayland swww ttf-jetbrains-mono qt6ct xdg-desktop-portal-hyprland xdg-utils xorg-server xorg-xinit papirus-icon-theme cool-retro-term qalculate-gtk dbus thunar tumbler thunar-archive-plugin thunar-shares-plugin thunar-volman hyprpicker pcmanfm-qt ly pinta hyprpolkitagent pavucontrol playerctl wf-recorder sound-theme-freedesktop ) AUR_PKGS=( # hyprland.sh AUR portion hyprland-workspaces vicinae-bin bluetuith wvkbd kew iwmenu walker-bin ulauncher bzmenu wofi-calc bri chamel # optional apps localsend vesktop onlyoffice-bin vintagestory wprs-git zfs-dkms ) FLATPAK_PKGS=( org.prismlauncher.PrismLauncher ) # --------------------------------------------------------------------------- # Snapshot current state # --------------------------------------------------------------------------- ALL_INSTALLED=$(pacman -Qq 2>/dev/null) FOREIGN=$(pacman -Qmq 2>/dev/null) # AUR / manually installed OFFICIAL=$(pacman -Qnq 2>/dev/null) # in a sync repo is_installed() { echo "$ALL_INSTALLED" | grep -qx "$1"; } is_from_official() { echo "$OFFICIAL" | grep -qx "$1"; } is_from_aur() { echo "$FOREIGN" | grep -qx "$1"; } # --------------------------------------------------------------------------- # 1. Check pacman packages # --------------------------------------------------------------------------- hdr "1/3 Official-repo packages (pacman)" for pkg in "${PACMAN_PKGS[@]}"; do if ! is_installed "$pkg"; then err "$pkg — NOT INSTALLED"; flag elif is_from_aur "$pkg"; then warn "$pkg — installed, but from AUR instead of official repo"; flag WRONG_SOURCE_OFFICIAL+=("$pkg") else ok "$pkg" fi done # --------------------------------------------------------------------------- # 2. Check AUR packages # --------------------------------------------------------------------------- hdr "2/3 AUR packages (yay)" for pkg in "${AUR_PKGS[@]}"; do if ! is_installed "$pkg"; then warn "$pkg — not installed (optional — may be intentional)" elif is_from_official "$pkg"; then warn "$pkg — installed from official repo, not AUR (may need AUR build for correct version)"; flag WRONG_SOURCE_AUR+=("$pkg") else ok "$pkg" fi done # --------------------------------------------------------------------------- # 3. Check flatpak packages # --------------------------------------------------------------------------- hdr "3/3 Flatpak packages" if command -v flatpak &>/dev/null; then FLATPAK_INSTALLED=$(flatpak list --app --columns=application 2>/dev/null) for pkg in "${FLATPAK_PKGS[@]}"; do if echo "$FLATPAK_INSTALLED" | grep -qx "$pkg"; then ok "$pkg" else warn "$pkg — not installed (optional — may be intentional)" fi done else warn "flatpak not found — skipping flatpak checks" fi # --------------------------------------------------------------------------- # 4. Flag unexpected foreign (AUR) packages not in our lists # --------------------------------------------------------------------------- hdr "Bonus: foreign packages not declared in setup scripts" AUR_SET=$(printf "%s\n" "${AUR_PKGS[@]}") while IFS= read -r pkg; do if ! echo "$AUR_SET" | grep -qx "$pkg"; then echo -e " ${CYAN}?${RESET} $pkg — foreign package not in setup scripts" fi done <<< "$FOREIGN" # --------------------------------------------------------------------------- # Fix: reinstall wrong-source packages # --------------------------------------------------------------------------- FIXED=0 if [ "$FIX" -eq 1 ]; then if [ ${#WRONG_SOURCE_OFFICIAL[@]} -gt 0 ] || [ ${#WRONG_SOURCE_AUR[@]} -gt 0 ]; then hdr "Reinstalling wrong-source packages" fi for pkg in "${WRONG_SOURCE_OFFICIAL[@]}"; do fix "Reinstalling $pkg from official repo (was AUR)..." if sudo pacman -S --noconfirm "$pkg"; then ok "$pkg reinstalled from official repo" FIXED=$((FIXED + 1)) ISSUES=$((ISSUES - 1)) else err "$pkg reinstall failed" fi done for pkg in "${WRONG_SOURCE_AUR[@]}"; do fix "Reinstalling $pkg from AUR (was official repo)..." if yay -S --aur --noconfirm "$pkg"; then ok "$pkg reinstalled from AUR" FIXED=$((FIXED + 1)) ISSUES=$((ISSUES - 1)) else err "$pkg reinstall failed" fi done fi # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- echo if [ "$FIX" -eq 1 ] && [ "$FIXED" -gt 0 ]; then echo -e "${GREEN}${BOLD}Fixed ${FIXED} wrong-source package(s).${RESET}" fi if [ "$ISSUES" -eq 0 ]; then echo -e "${GREEN}${BOLD}All checks passed — no source mismatches or missing required packages.${RESET}" else echo -e "${RED}${BOLD}${ISSUES} issue(s) found — review items marked ✘ or ⚠ above.${RESET}" [ "$FIX" -eq 0 ] && [ $((${#WRONG_SOURCE_OFFICIAL[@]} + ${#WRONG_SOURCE_AUR[@]})) -gt 0 ] && \ echo -e "${YELLOW} Run with --fix to automatically reinstall wrong-source packages.${RESET}" exit 1 fi