#!/bin/sh usage() { echo "\ apkv: Quickly add and remove packages to/from Alpine virtual packages. Usage: $0 add Add to virtual package . If the virtual package does not exist, it will be created. $0 del Remove from virtual package . Empty virtual packages are removed from world. The shorthand '$0 del * ' can be used to empty . $0 list [packages] List all or specific virtual packages and their contents. $0 help Show this help. Virtual packages must be prefixed with a dot to be managed with apkv. If one is not present, it will be added automatically. Methods can be shortened to their closest unambiguous forms, e.g. a, d, or l. However, due to implementation specifics, any string starting with those forms will work; that functionality is unspecified and is not guaranteed. For example, the following are equivalent: $0 add syslinux .virt $0 a syslinux virt $0 abcdefg syslinux .virt " } prepend_dot() { case $1 in .*) printf "$1";; *) printf ".$1";; esac } show_reqs() { _pkg="$1" shift >/dev/null [ -z "$_pkg" ] && return 1 if [ $# -gt 0 ]; then _list=$(echo "$(for x do echo $x; done)" | sort | uniq) else apk info -e "$_pkg" >/dev/null || return 1 _list=$(apk info -R "$_pkg" | awk 'NR > 1 && NF' | sort) fi echo -e "\e[1m$_pkg\e[0m:" $_list } method="$1" shift >/dev/null case $method in l*) for x in ${*:-$(apk info | grep '^\.')}; do show_reqs "$(prepend_dot "$x")" done exit;; a*) method=add;; d*) method=del;; h*) usage; exit;; -*) usage; exit;; *) [ -n "$method" ] && echo "Invalid method $method" >&2; usage; exit 1;; esac ## add/del # get and validate packages pkgs= virt= for x; do if [ -n "$pkgs" ]; then pkgs="$pkgs $virt" elif [ -n "$virt" ]; then pkgs=$virt fi virt=$x done if [ -z "$pkgs" ]; then echo 'Not enough arguments' >&2 usage exit 1 fi virt=$(prepend_dot $virt) # exit if database locked (99) or no package found to delete from (1) apk info -e "$virt" >/dev/null code=$? if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then exit $code fi # we have validated our args, so let's prepare to run apk: get sudo command if # it exists and we are not already root # TODO: support doas if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then sudo=$(command -v sudo) fi # handle quick delete shorthand mentioned in help if [ $method = del -a '*' = "$pkgs" ]; then $sudo apk del "$virt" exit $? fi currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF') case $method in # $(echo) construct is to use word splitting to normalize whitespace add) currpkgs="$(echo $currpkgs) $pkgs";; del) # XXX: there's probably a more efficient way to do this for x in $pkgs; do currpkgs=$(echo "$currpkgs" | grep -vFiw $x) done;; esac if [ -z "$currpkgs" ]; then # virtual package is empty $sudo apk del "$virt" else show_reqs "$virt" $currpkgs $sudo apk add -t "$virt" $currpkgs fi # pass along sudo/apk exit code exit $? # vi:sw=4:sts=4:et