#!/bin/bash # I, Ian Kelling, follow the GNU license recommendations at # https://www.gnu.org/licenses/license-recommendations.en.html. They # recommend that small programs, < 300 lines, be licensed under the # Apache License 2.0. This file contains or is part of one or more small # programs. If a small program grows beyond 300 lines, I plan to switch # its license to GPL. # Copyright 2024 Ian Kelling # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # basic yum/apt package manager abstraction, plus a few minor conveniences if command -v yum &> /dev/null; then # package manager p() { local s; [[ $EUID != 0 ]] && s=sudo $s yum "$@" } # package install pi() { local s; [[ $EUID != 0 ]] && s=sudo $s yum -y install "$@" } # package find pfd() { local s; [[ $EUID != 0 ]] && s=sudo $s yum search "$@" } # package remove/uninstall pu() { local s; [[ $EUID != 0 ]] && s=sudo $s yum autoremove "$@" } # shellcheck disable=SC2120 pup() { # upgrade local s; [[ $EUID != 0 ]] && s=sudo $s yum -y distro-sync full "$@" } # package list info pl() { yum info "$@" } pfile() { yum whatprovides \*/$1 } elif command -v apt-get &>/dev/null; then plock-wait() { local i i=0 while fuser /var/lib/dpkg/lock &>/dev/null; do sleep 1 i=$(( i+1 )) if (( i > 300 )); then echo "error: timed out waiting for /var/lib/dpkg/lock" >&2 return 1 fi done } pcheck() { for arg; do if [[ $1 == -* ]]; then shift else break fi done if dpkg -s -- "$@" |& grep -Fx "Status: install ok installed" &>/dev/null; then return 1 fi return 0 } pp() { # package policy apt-cache policy $@ } p() { local s; [[ $EUID != 0 ]] && s=sudo case $1 in install) $s apt-get --purge --auto-remove "$@" ;; *) $s apt-get "$@" ;; esac } pupdate() { local now t s f cachetime limittime; [[ $EUID != 0 ]] && s=sudo # update package list if its more than an 2 hours old f=/var/cache/apt/pkgcache.bin if [[ -r $f ]]; then cachetime=$(stat -c %Y $f ) else cachetime=0 fi now=$(date +%s) limittime=$(( now - 60*60*2 )) for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list; do if [[ -r $f ]]; then t=$(stat -c %Y $f ) if (( t > limittime )); then limittime=$t fi fi done if (( cachetime > limittime )); then $s apt-get update fi } pi() { pcheck "$@" || return 0 pupdate if [[ $- != *i* ]]; then echo pi "$*" fi if [[ $EUID == 0 ]]; then DEBIAN_FRONTEND=noninteractive apt-get -y install --purge --auto-remove "$@" else sudo DEBIAN_FRONTEND=noninteractive apt-get -y install --purge --auto-remove "$@" fi } pi-nostart() { local ret= pcheck "$@" || return 0 plock-wait pupdate local f=/usr/sbin/policy-rc.d if [[ $- != *i* ]]; then echo pi-nostart "$@" fi if [[ $EUID == 0 ]]; then dd of=$f status=none </dev/null; then needed=true break fi done $needed || return 0 plock-wait $s apt-get -y remove --purge --auto-remove "$@" # seems slightly redundant, but it removes more stuff sometimes. $s apt-get -y autoremove } # shellcheck disable=SC2120 pup() { # upgrade plock-wait pupdate local s; [[ $EUID != 0 ]] && s=sudo $s apt-get -y dist-upgrade --purge --auto-remove "$@" $s apt-get -y autoremove } # package info pl() { if type -p aptitude &>/dev/null; then aptitude show "$@" else apt-cache show "$@" fi } pfile() { # -a = search all repos local -a arg all all=false case $1 in -a) all=true shift ;; esac local file=$1 # ucfq can tell us about config files which are not tracked # with apt-file. but, for at least a few files I tested # which are tracked with apt-file, ucfq doesn't show their # package name. So, commenting this, waiting to find # a config file only tracked by ucfq to see if it gives the # package name and if I can identify this kind of file. # if [[ $file == /* ]] && ! ucfq -w $file | grep ::: &>/dev/null; then # ucfq $file if [[ $file == /* ]]; then dpkg -S "$file" else if ! $all; then arg=(--filter-origins "$(positive-origins)") fi if [[ $file == /* ]]; then apt-file "${arg[@]}" find -x /"$file"\$ update-alternatives --list "$file" 2>/dev/null else apt-file "${arg[@]}" find -x "$file"\$ fi fi } pkgfiles() { if dpkg -s "$1" &>/dev/null; then dpkg-query -L $1 | while read -r l; do [[ -f $l ]] && printf "%s\n" "$l"; done else apt-file -x list "^$1$" fi } elif command -v pacman &>/dev/null; then p() { pacaur "$@" } pi() { pacaur -S --noconfirm --needed --noedit "$@" } pfd() { pacaur -Ss "$@" } pu() { pacaur -Rs --noconfirm "$@" if p=$(pacaur -Qdtq); then pacaur -Rs $p fi } aurex() { p="$1" aur='https://aur.archlinux.org' curl -s $aur/"$(curl -s "$aur/rpc.php?type=info&arg=$p" \ | jq -r .results.URLPath)" | tar xz cd "$p" } pmirror() { local s; [[ $EUID != 0 ]] && s=sudo local x x=$(mktemp) curl -s "https://www.archlinux.org/mirrorlist/\ ?country=US&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on" \ | sed -r 's/^[ #]*(Server *=)/\1/' > $x if (( $(stat -c %s $x ) > 10 )); then $s cp $x /etc/pacman.d/mirrorlist rm $x fi } # shellcheck disable=SC2120 pup() { # upgrade local s; [[ $EUID != 0 ]] && s=sudo # file_time + 24 hours > current_time if ! (( $(stat -c%Y /etc/pacman.d/mirrorlist) + 60*60*24 > $(date +%s) )) then pmirror fi pacaur -Syu --noconfirm "$@" } # package info pl() { pacaur -Si "$@" } pfile() { pkgfile "$1" } pkgfiles() { if pacaur -Qs "^$1$" &>/dev/null; then pacman -Ql $1 else pkgfile -l $1 fi } fi