2 # TODO: add duplicate checker to see if a pkg is in multiple virtual pkgs
7 apkv: Quickly add and remove packages to/from Alpine virtual packages.
10 $prog add <packages> <virtual>
11 Add <packages> to virtual package <virtual>. If the virtual package
12 does not exist, it will be created.
14 $prog del <packages> <virtual>
15 Remove <packages> from virtual package <virtual>. Empty virtual
16 packages are removed from world. The shorthand '$prog del * <virtual>'
17 can be used to empty <virtual>, which is equivalent to
18 'apk del <virtual>', though with special handling of leading dots.
20 $prog list [-o | packages]
21 List virtual packages and their contents.
22 packages List these virtual packages. If empty, list all.
23 -o Only list orphan packages that are not owned by any
24 virtual package. Orphans are automatically shown when
30 Virtual packages must be prefixed with a dot to be managed with apkv. Virtual
31 package names passed as arguments will automatically be prefixed with dots if
34 Methods can be shortened to their closest unambiguous forms, e.g. a, d, or l.
35 However, due to implementation specifics, any string starting with those forms
36 will work; that functionality is unspecified and is not guaranteed.
38 For example, the following are equivalent, with the first being preferred:
39 $prog add syslinux .virt
41 $prog abcdefg syslinux virt
56 [ -z "$_pkg" ] && return 1
58 # override reqs list for apkv add
59 _list=$(echo "$(for x do echo $x; done)" | sort | uniq)
61 apk info -e "$_pkg" >/dev/null || return 1
62 _list=$(apk info -R "$_pkg" | awk 'NR > 1 && NF' | sort)
64 echo -e "\e[1m$_pkg\e[0m:" $_list
75 *) [ -n "$method" ] && echo "Invalid method $method" >&2; usage; exit 1;;
78 if [ "$method" = list ]; then
79 if [ $# -eq 0 -o "$1" = '-o' ]; then
80 if [ "$1" = '-o' -a $# -gt 1 ]; then
81 echo "$method with -o switch does not accept arguments" >&2
85 # ignore getopt's --, we don't care if an arg begins with - anyway
86 [ "$1" = '--' ] && switch >/dev/null
88 all=$(apk info | sort)
89 # show packages if no args
91 for x in $(echo "$all" | grep '^\.'); do
92 show_reqs "$(prepend_dot "$x")"
95 # set all child packages of virtual packages as owned
96 # OPTIMIZE: getting deps of virtual packages is slow, it would be
97 # great to use apk info -R from show_reqs in orphan loop
98 # NOTE: since we don't have arrays in sh, set individual vars instead
99 for v in $(echo "$all" | grep '^\.'); do
100 for c in $(apk info -R $v | tail +2 | grep -v '^\.'); do
101 # NOTE: use tr because shell may not have ksh-derived ${c//}
102 # XXX: have not verified if package name may have more illegal
103 # chars for variable name past those already replaced, and
104 # replacing chars may result in variable collision—but
105 # official apk repos do not have any package names that
107 eval "__$(echo $c | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1)=1"
110 # check world against owned packages
111 # TODO: notify user if package is both in world and virtual package
113 for x in $(cat /etc/apk/world | grep -v '^\.'); do
115 echo $x | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1
116 )-0} -eq 0 ]" && echo $x
119 if [ -z "$orphans" ]; then
120 echo "No orphan packages found."
122 show_reqs orphans $orphans
126 show_reqs "$(prepend_dot "$x")"
133 # get and validate packages
137 if [ -n "$pkgs" ]; then
139 elif [ -n "$virt" ]; then
144 if [ -z "$pkgs" ]; then
145 echo 'Not enough arguments' >&2
149 virt=$(prepend_dot $virt)
150 # exit if database locked (99) or no package found to delete from (1)
151 apk info -e "$virt" >/dev/null
153 if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then
157 # we have validated our args, so let's prepare to run apk: get sudo command if
158 # it exists and we are not already root
160 if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then
161 sudo=$(command -v sudo)
164 # handle quick delete shorthand mentioned in help
165 if [ $method = del -a '*' = "$pkgs" ]; then
166 $sudo apk del "$virt"
170 currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
172 # NOTE: $(echo) construct uses word splitting to remove newlines
173 add) currpkgs="$(echo $currpkgs) $pkgs";;
174 del) # XXX: there's probably a more efficient way to do this
176 currpkgs=$(echo "$currpkgs" | grep -vFiw $x)
180 if [ -z "$currpkgs" ]; then
181 # virtual package is empty
182 $sudo apk del "$virt"
185 show_reqs "$virt" $currpkgs
186 $sudo apk add -t "$virt" $currpkgs
188 if [ $method = add -a $code -eq 0 ]; then
189 # remove packages from world if they are being moved to a virtual one
192 #apk_adb.c: [!]name[<,<=,<~,=,~,>~,>=,>,><]ver, @ for pinning
193 if grep -qE "^$x($|[<=~>@])" /etc/apk/world; then
197 if [ -n "$del" ]; then
198 echo "Removing packages from world:$del"
203 # pass along sudo/apk exit code