2 # TODO: add duplicate checker to seeif 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>' can
17 be used to empty <virtual>.
19 $prog list [-o | packages]
20 List virtual packages and their contents.
21 packages List these virtual packages. If empty, list all.
22 -o Only list orphan packages that are not owned by any
23 virtual package. Orphans are automatically shown when
29 Virtual packages must be prefixed with a dot to be managed with apkv. Virtual
30 package names passed as arguments will automatically be prefixed with dots if
33 Methods can be shortened to their closest unambiguous forms, e.g. a, d, or l.
34 However, due to implementation specifics, any string starting with those forms
35 will work; that functionality is unspecified and is not guaranteed.
37 For example, the following are equivalent, with the first being preferred:
38 $prog add syslinux .virt
40 $prog abcdefg syslinux virt
55 [ -z "$_pkg" ] && return 1
57 # override reqs list for apkv add
58 _list=$(echo "$(for x do echo $x; done)" | sort | uniq)
60 apk info -e "$_pkg" >/dev/null || return 1
61 _list=$(apk info -R "$_pkg" | awk 'NR > 1 && NF' | sort)
63 echo -e "\e[1m$_pkg\e[0m:" $_list
74 *) [ -n "$method" ] && echo "Invalid method $method" >&2; usage; exit 1;;
77 if [ "$method" = list ]; then
78 if [ $# -eq 0 -o "$1" = '-o' ]; then
79 if [ "$1" = '-o' -a $# -gt 1 ]; then
80 echo "$method with -o switch does not accept arguments" >&2
84 # ignore getopt's --, we don't care if an arg begins with - anyway
85 [ "$1" = '--' ] && switch >/dev/null
87 all=$(apk info | sort)
88 # show packages if no args
90 for x in $(echo "$all" | grep '^\.'); do
91 show_reqs "$(prepend_dot "$x")"
94 # set all child packages of virtual packages as owned
95 # OPTIMIZE: getting deps of virtual packages is slow, it would be
96 # great to use apk info -R from show_reqs in orphan loop
97 # NOTE: since we don't have arrays in sh, set individual vars instead
98 for v in $(echo "$all" | grep '^\.'); do
99 for c in $(apk info -R $v | tail +2 | grep -v '^\.'); do
100 # NOTE: use tr because shell may not have ksh-derived ${c//}
101 # XXX: have not verified if package name may have more illegal
102 # chars for variable name past those already replaced, and
103 # replacing chars may result in variable collision—but
104 # official apk repos do not have any package names that
106 eval "__$(echo $c | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1)=1"
109 # check world against owned packages
110 # TODO: notify user if package is both in world and virtual package
112 for x in $(cat /etc/apk/world | grep -v '^\.'); do
114 echo $x | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1
115 )-0} -eq 0 ]" && echo $x
118 if [ -z "$orphans" ]; then
119 echo "No orphan packages found."
121 show_reqs orphans $orphans
125 show_reqs "$(prepend_dot "$x")"
132 # get and validate packages
136 if [ -n "$pkgs" ]; then
138 elif [ -n "$virt" ]; then
143 if [ -z "$pkgs" ]; then
144 echo 'Not enough arguments' >&2
148 virt=$(prepend_dot $virt)
149 # exit if database locked (99) or no package found to delete from (1)
150 apk info -e "$virt" >/dev/null
152 if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then
156 # we have validated our args, so let's prepare to run apk: get sudo command if
157 # it exists and we are not already root
159 if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then
160 sudo=$(command -v sudo)
163 # handle quick delete shorthand mentioned in help
164 if [ $method = del -a '*' = "$pkgs" ]; then
165 $sudo apk del "$virt"
169 currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
171 # NOTE: $(echo) construct uses word splitting to remove newlines
172 add) currpkgs="$(echo $currpkgs) $pkgs";;
173 del) # XXX: there's probably a more efficient way to do this
175 currpkgs=$(echo "$currpkgs" | grep -vFiw $x)
179 if [ -z "$currpkgs" ]; then
180 # virtual package is empty
181 $sudo apk del "$virt"
184 show_reqs "$virt" $currpkgs
185 $sudo apk add -t "$virt" $currpkgs
187 if [ $method = add -a $code -eq 0 ]; then
188 # remove packages from world if they are being moved to a virtual one
191 #apk_adb.c: [!]name[<,<=,<~,=,~,>~,>=,>,><]ver, @ for pinning
192 if grep -qE "^$x($|[<=~>@])" /etc/apk/world; then
196 if [ -n "$del" ]; then
197 echo "Removing packages from world:$del"
202 # pass along sudo/apk exit code