]> git.sev.monster Git - dotfiles.git/blob - bin/apkv
bf895900ca394cc9c775f2a5322dc51a28f6220f
[dotfiles.git] / bin / apkv
1 #!/bin/sh
2
3 usage() {
4     echo "\
5 apkv: Quickly add and remove packages to/from Alpine virtual packages.
6
7 Usage:
8     $0 add <packages> <virtual>
9         Add <packages> to virtual package <virtual>. If the virtual package
10         does not exist, it will be created.
11     $0 del <packages> <virtual>
12         Remove <packages> from virtual package <virtual>. Empty virtual
13         packages are removed from world. The shorthand '$0 del * <virtual>' can
14         be used to empty <virtual>.
15     $0 list [packages]
16         List all or specific virtual packages and their contents.
17     $0 help
18         Show this help.
19
20 Virtual packages must be prefixed with a dot to be managed with apkv. If one is
21 not present, it will be added automatically.
22
23 Methods can be shortened to their closest unambiguous forms, e.g. a, d, or l.
24 However, due to implementation specifics, any string starting with those forms
25 will work; that functionality is unspecified and is not guaranteed.
26
27 For example, the following are equivalent:
28     apkv add syslinux .virt
29     apkv a syslinux virt
30     apkv abcdefg syslinux .virt
31
32 "
33 }
34
35 prepend_dot() {
36     case $1 in
37         .*) printf "$1";;
38         *)  printf ".$1";;
39     esac
40 }
41
42 show_reqs() {
43     _pkg="$1"
44     shift >/dev/null
45     [ -z "$_pkg" ] && return 1
46     if [ $# -gt 0 ]; then
47         _list=$(echo "$(for x do echo $x; done)" | sort | uniq)
48     else
49         apk info -e "$_pkg" >/dev/null || return 1
50         _list=$(apk info -R "$_pkg" | awk 'NR > 1 && NF' | sort)
51     fi
52     echo -e "\e[1m$_pkg\e[0m:" $_list
53 }
54
55 method="$1"
56 shift >/dev/null
57 case $method in
58     l*) for x in ${*:-$(apk info | grep '^\.')}; do
59             show_reqs "$(prepend_dot "$x")"
60         done
61         exit;;
62     a*) method=add;;
63     d*) method=del;;
64     h*) usage; exit;;
65     -*) usage; exit;;
66     *)  [ -n "$method" ] && echo "Invalid method $method" >&2; usage; exit 1;;
67 esac
68
69 ## add/del
70 # get and validate packages
71 pkgs=
72 virt=
73 for x; do
74     if [ -n "$pkgs" ]; then
75         pkgs="$pkgs $virt"
76     elif [ -n "$virt" ]; then
77         pkgs=$virt
78     fi
79     virt=$x
80 done
81 if [ -z "$pkgs" ]; then
82     echo 'Not enough arguments' >&2
83     usage
84     exit 1
85 fi
86 virt=$(prepend_dot $virt)
87 # exit if database locked (99) or no package found to delete from (1)
88 apk info -e "$virt" >/dev/null
89 code=$?
90 if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then
91     exit $code
92 fi
93
94 # we have validated our args, so let's prepare to run apk: get sudo command if
95 # it exists and we are not already root
96 # TODO: support doas
97 if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then
98     sudo=$(command -v sudo)
99 fi
100
101 # handle quick delete shorthand mentioned in help
102 if [ $method = del -a '*' = "$pkgs" ]; then
103     $sudo apk del "$virt"
104     exit $?
105 fi
106
107 currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
108 case $method in
109     # $(echo) construct is to use word splitting to normalize whitespace
110     add) currpkgs="$(echo $currpkgs) $pkgs";;
111     del) # XXX: there's probably a more efficient way to do this
112          for x in "$pkgs"; do
113              currpkgs=$(echo "$currpkgs" | grep -vFiw $x)
114          done;;
115 esac
116
117 if [ -z "$currpkgs" ]; then
118     # virtual package is empty
119     $sudo apk del "$virt"
120 else
121     show_reqs "$virt" $currpkgs
122     $sudo apk add -t "$virt" $currpkgs
123 fi
124 # pass along sudo/apk exit code
125 exit $?
126
127 # vi:sw=4:sts=4:et
This page took 0.031366 seconds and 2 git commands to generate.