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 # OPTIMIZE: getting deps of virtual packages is slow, it would be
88 # great to use apk info -R from show_reqs in orphan loop
90 # show packages if no args
92 for x in $(echo "$all" | grep '^\.'); do
93 show_reqs "$(prepend_dot "$x")"
96 # set all child packages of virtual packages as owned
97 for v in $(echo "$all" | grep '^\.'); do
98 for c in $(apk info -R $v | tail +2 | grep -v '^\.'); do
99 # NOTE: use tr because shell may not have ksh-derived ${c//}
100 # XXX: package name may have illegal chars for variable name
101 # past those already replaced, and replacing chars may
102 # result in variable collision—but official apk repos do
103 # not have any packages that would cause issues
104 eval "__$(echo $c | tr -s '.:-' _)=1"
107 # check world against owned packages
108 # TODO: notify user if package is in world and also a virtual package
110 for x in $(cat /etc/apk/world | grep -v '^\.'); do
112 echo $x | tr -s '.:-' _ | tr -s '<>=' "\n" | head -1
113 )-0} -eq 0 ]" && echo $x
116 if [ -z "$orphans" ]; then
117 echo "No orphan packages found."
119 show_reqs orphans $orphans
123 show_reqs "$(prepend_dot "$x")"
130 # get and validate packages
134 if [ -n "$pkgs" ]; then
136 elif [ -n "$virt" ]; then
141 if [ -z "$pkgs" ]; then
142 echo 'Not enough arguments' >&2
146 virt=$(prepend_dot $virt)
147 # exit if database locked (99) or no package found to delete from (1)
148 apk info -e "$virt" >/dev/null
150 if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then
154 # we have validated our args, so let's prepare to run apk: get sudo command if
155 # it exists and we are not already root
157 if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then
158 sudo=$(command -v sudo)
161 # handle quick delete shorthand mentioned in help
162 if [ $method = del -a '*' = "$pkgs" ]; then
163 $sudo apk del "$virt"
167 currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
169 # NOTE: $(echo) construct uses word splitting to remove newlines
170 add) currpkgs="$(echo $currpkgs) $pkgs";;
171 del) # XXX: there's probably a more efficient way to do this
173 currpkgs=$(echo "$currpkgs" | grep -vFiw $x)
177 if [ -z "$currpkgs" ]; then
178 # virtual package is empty
179 $sudo apk del "$virt"
182 show_reqs "$virt" $currpkgs
183 $sudo apk add -t "$virt" $currpkgs
185 if [ $method = add -a $code -eq 0 ]; then
186 # remove packages from world if they are being moved to a virtual one
189 if apk info -e "$x" >/dev/null 2>&1; then
193 if [ -n "$del" ]; then
194 echo "Removing packages from world:$del"
199 # pass along sudo/apk exit code