]> git.sev.monster Git - dotfiles.git/blame_incremental - bin/apkv
vimrc: enable modeline explicitly
[dotfiles.git] / bin / apkv
... / ...
CommitLineData
1#!/bin/sh
2# TODO: add duplicate checker to see if a pkg is in multiple virtual pkgs
3
4prog=$(basename $0)
5usage() {
6 echo "\
7apkv: Quickly add and remove packages to/from Alpine virtual packages.
8
9Usage:
10 $prog add <packages> <virtual>
11 Add <packages> to virtual package <virtual>. If the virtual package
12 does not exist, it will be created.
13
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.
19
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
25 listing all packages.
26
27 $prog help
28 Show this help.
29
30Virtual packages must be prefixed with a dot to be managed with apkv. Virtual
31package names passed as arguments will automatically be prefixed with dots if
32they are not present.
33
34Methods can be shortened to their closest unambiguous forms, e.g. a, d, or l.
35However, due to implementation specifics, any string starting with those forms
36will work; that functionality is unspecified and is not guaranteed.
37
38For example, the following are equivalent, with the first being preferred:
39 $prog add syslinux .virt
40 $prog a syslinux virt
41 $prog abcdefg syslinux virt
42
43"
44}
45
46prepend_dot() {
47 case $1 in
48 .*) printf "$1";;
49 *) printf ".$1";;
50 esac
51}
52
53show_reqs() {
54 _pkg="$1"
55 shift >/dev/null
56 [ -z "$_pkg" ] && return 1
57 if [ $# -gt 0 ]; then
58 # override reqs list for apkv add
59 _list=$(echo "$(for x do echo $x; done)" | sort | uniq)
60 else
61 apk info -e "$_pkg" >/dev/null || return 1
62 _list=$(apk info -R "$_pkg" | awk 'NR > 1 && NF' | sort)
63 fi
64 echo -e "\e[1m$_pkg\e[0m:" $_list
65}
66
67method="$1"
68shift >/dev/null
69case $method in
70 l*) method=list;;
71 a*) method=add;;
72 d*) method=del;;
73 h*) usage; exit;;
74 -*) usage; exit;;
75 *) [ -n "$method" ] && echo "Invalid method $method" >&2; usage; exit 1;;
76esac
77
78if [ "$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
82 usage
83 exit 1
84 fi
85 # ignore getopt's --, we don't care if an arg begins with - anyway
86 [ "$1" = '--' ] && switch >/dev/null
87
88 all=$(apk info | sort)
89 # show packages if no args
90 if [ $# -eq 0 ]; then
91 for x in $(echo "$all" | grep '^\.'); do
92 show_reqs "$(prepend_dot "$x")"
93 done
94 fi
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
106 # would cause issues
107 eval "__$(echo $c | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1)=1"
108 done
109 done
110 # check world against owned packages
111 # TODO: notify user if package is both in world and virtual package
112 orphans=$(
113 for x in $(cat /etc/apk/world | grep -v '^\.'); do
114 eval "[ \${__$(
115 echo $x | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1
116 )-0} -eq 0 ]" && echo $x
117 done
118 )
119 if [ -z "$orphans" ]; then
120 echo "No orphan packages found."
121 else
122 show_reqs orphans $orphans
123 fi
124 else
125 for x in $*; do
126 show_reqs "$(prepend_dot "$x")"
127 done
128 fi
129 exit
130fi
131
132## add/del
133# get and validate packages
134pkgs=
135virt=
136for x; do
137 if [ -n "$pkgs" ]; then
138 pkgs="$pkgs $virt"
139 elif [ -n "$virt" ]; then
140 pkgs=$virt
141 fi
142 virt=$x
143done
144if [ -z "$pkgs" ]; then
145 echo 'Not enough arguments' >&2
146 usage
147 exit 1
148fi
149virt=$(prepend_dot $virt)
150# exit if database locked (99) or no package found to delete from (1)
151apk info -e "$virt" >/dev/null
152code=$?
153if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then
154 exit $code
155fi
156
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
159# TODO: support doas
160if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then
161 sudo=$(command -v sudo)
162fi
163
164# handle quick delete shorthand mentioned in help
165if [ $method = del -a '*' = "$pkgs" ]; then
166 $sudo apk del "$virt"
167 exit $?
168fi
169
170currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
171case $method in
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
175 for x in $pkgs; do
176 currpkgs=$(echo "$currpkgs" | grep -vFiw $x)
177 done;;
178esac
179
180if [ -z "$currpkgs" ]; then
181 # virtual package is empty
182 $sudo apk del "$virt"
183 code=$?
184else
185 show_reqs "$virt" $currpkgs
186 $sudo apk add -t "$virt" $currpkgs
187 code=$?
188 if [ $method = add -a $code -eq 0 ]; then
189 # remove packages from world if they are being moved to a virtual one
190 del=
191 for x in $pkgs; do
192 #apk_adb.c: [!]name[<,<=,<~,=,~,>~,>=,>,><]ver, @ for pinning
193 if grep -qE "^$x($|[<=~>@])" /etc/apk/world; then
194 del="$del $x"
195 fi
196 done
197 if [ -n "$del" ]; then
198 echo "Removing packages from world:$del"
199 $sudo apk del $del
200 fi
201 fi
202fi
203# pass along sudo/apk exit code
204exit $code
205
206# vi:sw=4:sts=4:et
This page took 0.049556 seconds and 4 git commands to generate.