Last active
September 19, 2025 20:14
-
-
Save DrSensor/b765f9cef67dadb3c6cb9eaa53df7833 to your computer and use it in GitHub Desktop.
Revisions
-
DrSensor revised this gist
Sep 19, 2025 . 2 changed files with 41 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,7 +3,7 @@ pkgver=1.0.0 pkgrel=1 pkgdesc="pacman profile manager" arch=('any') url="https://gist.github.com/DrSensor/b765f9cef67dadb3c6cb9eaa53df7833" license=('MIT') depends=('pacman' 'bash') backup=('etc/pacprofile/pacman.conf') This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -20,6 +20,7 @@ Usage: pacprofile current # Show active profiles pacprofile install <profile> <pkg...> # Install into profile pacprofile remove <profile> <pkg...> # Remove from profile pacprofile status <profile> # Show status of profile EOF exit 1 } @@ -170,12 +171,51 @@ case "$1" in require_profile "$profile" CONF=$(profile_conf "$profile") IGNORE=$(ignore_except "$(profile_pkgs "$profile")" | tr '\n' ',') missing=$(comm -23 <(sort "$(profile_pkgs "$profile")") <(pacman -Qq | sort)) if [[ -n "$missing" ]]; then echo "Installing missing packages for '$profile': $missing" sudo $PACMGR --config "$CONF" -S $missing fi echo "Upgrading profile '$profile'..." run_upgrade "$CONF" "$IGNORE" done fi ;; status) [[ -z "$2" ]] && usage profile="$2" require_profile "$profile" installed=$(pacman -Qq | sort) tracked=$(sort "$(profile_pkgs "$profile")") missing=$(comm -23 <(echo "$tracked") <(echo "$installed")) present=$(comm -12 <(echo "$tracked") <(echo "$installed")) echo "==> Status for profile: $profile" echo echo "[Tracked packages]:" echo "$tracked" | sed 's/^/ /' echo echo "[Installed packages in profile]:" echo "$present" | sed 's/^/ /' echo echo "[Missing packages from system]:" if [[ -n "$missing" ]]; then echo "$missing" | sed 's/^/ /' else echo " (none)" fi echo # Extras: only if user want global check all_profiles=$(all_profiles_union) extras=$(comm -23 <(echo "$installed") <(echo "$all_profiles")) echo "[Extra installed packages (not in any profile)]:" if [[ -n "$extras" ]]; then echo "$extras" | sed 's/^/ /' else echo " (none)" fi ;; # --- Pacman hooks --- hook-install) pkg="$2" -
DrSensor created this gist
Sep 19, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,58 @@ pkgname=pacprofile pkgver=1.0.0 pkgrel=1 pkgdesc="pacman profile manager" arch=('any') # url="https://gist.github.com/drsensor/pacprofile" license=('MIT') depends=('pacman' 'bash') backup=('etc/pacprofile/pacman.conf') source=("$pkgname.sh") sha256sums=('SKIP') package() { install -Dm755 "$srcdir/$pkgname.sh" "$pkgdir/usr/local/bin/$pkgname" # config dir install -d "$pkgdir/etc/pacprofile" install -d "$pkgdir/etc/pacprofile/work" install -d "$pkgdir/etc/pacprofile/gaming" install -d "$pkgdir/etc/pacprofile/server" # copy system pacman.conf as base if [[ -f /etc/pacman.conf ]]; then install -m644 /etc/pacman.conf "$pkgdir/etc/pacprofile/pacman.conf" fi # create empty pkgs.txt for profiles touch "$pkgdir/etc/pacprofile/work/pkgs.txt" touch "$pkgdir/etc/pacprofile/gaming/pkgs.txt" touch "$pkgdir/etc/pacprofile/server/pkgs.txt" # pacman hooks install -d "$pkgdir/etc/pacman.d/hooks" cat >"$pkgdir/etc/pacman.d/hooks/pacprofile-install.hook" <<'EOF' [Trigger] Operation = Install Type = Package Target = * [Action] Description = Update pacprofile pkgs.txt on install When = PostTransaction Exec = /usr/local/bin/pacprofile hook-install %n EOF cat >"$pkgdir/etc/pacman.d/hooks/pacprofile-remove.hook" <<'EOF' [Trigger] Operation = Remove Type = Package Target = * [Action] Description = Update pacprofile pkgs.txt on remove When = PostTransaction Exec = /usr/local/bin/pacprofile hook-remove %n EOF } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,198 @@ #!/bin/bash # pacprofile - Profile-aware wrapper for Arch package managers # Supports multiple active profiles + pacman hook integration # Default backend is pacman, override with PACMGR env var PACMGR="${PACMGR:-pacman}" BASE_DIR="/etc/pacprofile" BASE_CONF="$BASE_DIR/pacman.conf" ACTIVE_DIR="$BASE_DIR/active" usage() { cat <<EOF Usage: pacprofile upgrade [<profile...>|--system] # Upgrade active or given profiles pacprofile list # List all profiles pacprofile show <profile> # Show pkgs in profile pacprofile set <profile...> # Set active profiles pacprofile add <profile...> # Add to active profiles pacprofile del <profile...> # Remove from active profiles pacprofile current # Show active profiles pacprofile install <profile> <pkg...> # Install into profile pacprofile remove <profile> <pkg...> # Remove from profile EOF exit 1 } profile_dir() { echo "$BASE_DIR/$1"; } profile_pkgs() { echo "$(profile_dir "$1")/pkgs.txt"; } profile_conf() { local dir=$(profile_dir "$1") [[ -f "$dir/pacman.conf" ]] && echo "$dir/pacman.conf" || echo "$BASE_CONF" } require_profile() { local profile="$1" [[ -f "$(profile_pkgs "$profile")" ]] || { echo "Profile '$profile' not found in $BASE_DIR" exit 1 } } all_profiles_union() { find "$BASE_DIR" -mindepth 2 -maxdepth 2 -name "pkgs.txt" -exec cat {} + | sort -u } ignore_except() { local allow_file="$1" local installed=$(pacman -Qq | sort) local allowed=$(sort "$allow_file") comm -23 <(echo "$installed") <(echo "$allowed") } ignore_all_profiles() { local installed=$(pacman -Qq | sort) local all=$(all_profiles_union) comm -23 <(echo "$installed") <(echo "$all") } active_profiles() { [[ -d "$ACTIVE_DIR" ]] || return 0 find "$ACTIVE_DIR" -mindepth 1 -maxdepth 1 -type l -printf "%f\n" | sort } set_active_profiles() { sudo rm -rf "$ACTIVE_DIR" sudo mkdir -p "$ACTIVE_DIR" for p in "$@"; do require_profile "$p" sudo ln -s "../$p" "$ACTIVE_DIR/$p" done } add_active_profiles() { sudo mkdir -p "$ACTIVE_DIR" for p in "$@"; do require_profile "$p" sudo ln -sfn "../$p" "$ACTIVE_DIR/$p" done } del_active_profiles() { for p in "$@"; do sudo rm -f "$ACTIVE_DIR/$p" done } run_upgrade() { local conf="$1" local ignore="$2" if [[ -n "$ignore" ]]; then sudo $PACMGR --config "$conf" -Syu --ignore "${ignore%,}" else sudo $PACMGR --config "$conf" -Syu fi } case "$1" in list) find "$BASE_DIR" -mindepth 1 -maxdepth 1 -type d -printf "%f\n" ;; show) [[ -z "$2" ]] && usage require_profile "$2" cat "$(profile_pkgs "$2")" ;; set) [[ $# -lt 2 ]] && usage shift set_active_profiles "$@" echo "Active profiles set to: $*" ;; add) [[ $# -lt 2 ]] && usage shift add_active_profiles "$@" echo "Added active profiles: $*" ;; del) [[ $# -lt 2 ]] && usage shift del_active_profiles "$@" echo "Removed active profiles: $*" ;; current) active=$(active_profiles) if [[ -z "$active" ]]; then echo "No active profiles." else echo "Active profiles: $active" fi ;; install) [[ $# -lt 3 ]] && usage profile="$2"; shift 2 require_profile "$profile" sudo $PACMGR -S "$@" for pkg in "$@"; do grep -qxF "$pkg" "$(profile_pkgs "$profile")" || echo "$pkg" | sudo tee -a "$(profile_pkgs "$profile")" >/dev/null done ;; remove) [[ $# -lt 3 ]] && usage profile="$2"; shift 2 require_profile "$profile" sudo $PACMGR -Rns "$@" for pkg in "$@"; do sudo sed -i "/^$pkg$/d" "$(profile_pkgs "$profile")" done ;; upgrade) shift if [[ "$1" == "--system" ]]; then IGNORE=$(ignore_all_profiles | tr '\n' ',') run_upgrade "$BASE_CONF" "$IGNORE" else profiles=("$@") if [[ ${#profiles[@]} -eq 0 ]]; then profiles=($(active_profiles)) fi [[ ${#profiles[@]} -eq 0 ]] && { echo "No profiles specified and no active profiles set."; exit 1; } for profile in "${profiles[@]}"; do require_profile "$profile" CONF=$(profile_conf "$profile") IGNORE=$(ignore_except "$(profile_pkgs "$profile")" | tr '\n' ',') echo "Upgrading profile '$profile'..." run_upgrade "$CONF" "$IGNORE" done fi ;; # --- Pacman hooks --- hook-install) pkg="$2" for p in $(active_profiles); do require_profile "$p" grep -qxF "$pkg" "$(profile_pkgs "$p")" || echo "$pkg" | sudo tee -a "$(profile_pkgs "$p")" >/dev/null done ;; hook-remove) pkg="$2" for dir in $(find "$BASE_DIR" -mindepth 1 -maxdepth 1 -type d); do sudo sed -i "/^$pkg$/d" "$dir/pkgs.txt" 2>/dev/null || true done ;; *) usage ;; esac