Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save jjaimealeman/570b19efd1d41d373de0c6ad0e6958dd to your computer and use it in GitHub Desktop.

Select an option

Save jjaimealeman/570b19efd1d41d373de0c6ad0e6958dd to your computer and use it in GitHub Desktop.
pkg
#!/usr/bin/env bash
# Manage packages using Pacman (Arch) and Yay (AUR) repositories.
#
# SAVE AS:
# ~/.local/bin/pkg
#
# SOURCE FROM:
# https://github.com/nickjj/dotfiles/blob/master/.local/bin/pkg
#
# Examples:
# pkg --help
set -o errexit
set -o pipefail
set -o nounset
if [ -r /etc/os-release ]; then
# shellcheck disable=SC1091
OS_DISTRO="$(. /etc/os-release && echo "${ID_LIKE:-${ID}}")"
if [ "${OS_DISTRO}" != "arch" ]; then
echo "This script is only available on Arch Linux, sorry!" >&2
exit 1
fi
fi
POSITION=0
CMD=
AUR=
usage() {
cat <<EOF
Usage examples:
pkg CMD [-a|--aur]
pkg install # Install / search new packages
^ pacman -Syu --needed
pkg install --aur # Install / search new AUR packages
^ yay -S --answerclean N --needed
pkg list # List locally installed packages
^ pacman -Qei
pkg list --aur # List locally installed AUR packages
^ yay -Qm
pkg remove # Remove installed packages
^ pacman -Rns
pkg remove --aur # Remove installed AUR packages
^ pacman -Rns
pkg news [q] # Show Arch news (optionally headlines only)
^ yay -Pww[q]
EOF
}
while [[ "${#}" -gt 0 ]]; do
case "${1}" in
-h | --help | help)
usage
exit 0
;;
-a | --aur)
AUR="true"
shift
;;
*)
case "${POSITION}" in
0)
CMD="${1}"
POSITION=1
shift
;;
1)
[[ "${CMD}" == "news" && "${1}" == "q" ]] && break
printf "Unknown argument: %s\n\n" "${1}" >&2
usage >&2
exit 1
;;
esac
;;
esac
done
[[ -z "${CMD}" ]] && usage >&2 && exit 1
fzf_args() {
local prompt="${1}"
local preview="${2}"
local tiebreak="${3:-}"
local args=(
--multi
--prompt "${prompt} "
--delimiter "::"
--preview "${preview}"
--preview-window "down:55%:wrap"
--preview-label-pos "bottom"
--preview-label " tab: multi-select, shift+tab: deselect "
)
[ -n "${tiebreak}" ] && args+=(--nth "1,2" --tiebreak "begin,index")
printf "%s\n" "${args[@]}"
}
install() {
local packages=
# shellcheck disable=SC2016
mapfile -t fzf_opts \
< <(fzf_args "Search packages to install..." 'pacman -Si $(echo {} | cut -d " " -f 1)' "tiebreak")
packages="$(
pacman -Ss "" | awk '
/^[a-z]+\/[^\s]+/ {
split($1,a,"/")
pkg = a[2]
getline desc
sub(/^[ \t]+/, "", desc)
printf "%s :: %s\n", pkg, desc
}' |
fzf "${fzf_opts[@]}" | cut -d " " -f 1
)"
if [ -n "${packages}" ]; then
# shellcheck disable=SC2086
sudo pacman -Syu --needed ${packages}
fi
}
install_aur() {
local packages=
local query packages=
read -rp "Enter AUR search query (at least 3 characters): " query
if [[ ${#query} -lt 3 ]]; then
echo "'${query}' must be 3 or more characters, aborting!" >&2
exit 1
fi
# shellcheck disable=SC2016
mapfile -t fzf_opts \
< <(fzf_args "Filter AUR packages to install..." 'yay -Si $(echo {} | cut -d " " -f 1)' "tiebreak")
packages="$(
yay -Ssa "$query" | awk '
/^[^ ]/ {
split($1, a, "/")
pkg = a[2]
next
}
/^[ ]/ {
desc = $0
sub(/^[ \t]+/, "", desc)
printf "%s :: %s\n", pkg, desc
}
' |
fzf "${fzf_opts[@]}" | cut -d " " -f 1
)"
if [ -n "${packages}" ]; then
# shellcheck disable=SC2086
yay -S --answerclean N --needed ${packages}
fi
}
list() {
local packages=
# shellcheck disable=SC2016
mapfile -t fzf_opts \
< <(fzf_args "Search installed packages..." 'pacman -Qi $(echo {} | cut -d " " -f 1)' "tiebreak")
packages="$(
pacman -Qei | awk '
BEGIN { name = ""; desc = "" }
/^Name\s*:/ { name = $3 }
/^Description\s*:/ { desc = substr($0, index($0,$3)) }
/^$/ && name != "" && desc != "" {
printf "%s :: %s\n", name, desc
name = ""; desc = ""
}' | fzf "${fzf_opts[@]}"
)"
}
list_aur() {
local packages=
# shellcheck disable=SC2016
mapfile -t fzf_opts \
< <(fzf_args "Search installed AUR packages..." 'yay -Qi $(echo {} | cut -d" " -f1)' "tiebreak")
packages="$(
yay -Qm | awk '
{
pkg = $1
cmd = "yay -Qi " pkg " 2>/dev/null | grep -m1 \"^Description\""
desc = ""
if ((cmd | getline line) > 0) {
sub(/^[^:]*:\s*/, "", line)
desc = line
}
close(cmd)
printf "%s :: %s\n", pkg, desc
}' | fzf "${fzf_opts[@]}"
)"
}
remove() {
local packages=
# shellcheck disable=SC2016
mapfile -t fzf_opts \
< <(fzf_args "Search installed packages to remove..." 'pacman -Qi $(echo {} | cut -d " " -f 1)' "tiebreak")
packages="$(
pacman -Qei | awk '
BEGIN { name = ""; desc = "" }
/^Name\s*:/ { name = $3 }
/^Description\s*:/ { desc = substr($0, index($0,$3)) }
/^$/ && name != "" && desc != "" {
printf "%s :: %s\n", name, desc
name = ""; desc = ""
}' | fzf "${fzf_opts[@]}" | cut -d " " -f 1
)"
if [ -n "${packages}" ]; then
# shellcheck disable=SC2086
sudo pacman -Rns ${packages}
fi
}
remove_aur() {
local packages=
# shellcheck disable=SC2016
mapfile -t fzf_opts \
< <(fzf_args "Search installed AUR packages to remove..." 'yay -Qi $(echo {} | cut -d " " -f 1)' "tiebreak")
# This is the same code as listing from the AUR plus an added cut pipe. This
# could be refactored at some point, for now it's not the end of the world.
packages="$(
yay -Qm | awk '
{
pkg = $1
cmd = "yay -Qi " pkg " 2>/dev/null | grep -m1 \"^Description\""
desc = ""
if ((cmd | getline line) > 0) {
sub(/^[^:]*:\s*/, "", line)
desc = line
}
close(cmd)
printf "%s :: %s\n", pkg, desc
}' | fzf "${fzf_opts[@]}" | cut -d " " -f 1
)"
if [ -n "${packages}" ]; then
# shellcheck disable=SC2086
sudo pacman -Rns ${packages}
fi
}
show_news() {
local headlines="${1}"
# This occasionally breaks when Arch is getiting attacked but the main site
# is sometimes still up so let's always allow this to work to display a link
# to the main site in all cases.
yay -Pww"${headlines}" || true
cat <<EOF
---
View the official Arch news site: https://archlinux.org/news/
EOF
}
if [[ "${CMD}" = "install" && -z "${AUR}" ]]; then
install
elif [[ "${CMD}" = "install" && -n "${AUR}" ]]; then
install_aur
elif [[ "${CMD}" = "list" && -z "${AUR}" ]]; then
list
elif [[ "${CMD}" = "list" && -n "${AUR}" ]]; then
list_aur
elif [[ "${CMD}" = "remove" && -z "${AUR}" ]]; then
remove
elif [[ "${CMD}" = "remove" && -n "${AUR}" ]]; then
remove_aur
elif [[ "${CMD}" = "news" ]]; then
show_news "${1:-}"
else
printf "Unknown command: %s\n\n" "${CMD}" >&2
usage >&2
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment