]> git.sev.monster Git - dotfiles.git/blame - bin/apkv
zsh: replace ^R with fzf if it exists
[dotfiles.git] / bin / apkv
CommitLineData
c0b3d4b6 1#!/bin/sh
8e304013 2# TODO: add duplicate checker to see if a pkg is in multiple virtual pkgs
c0b3d4b6 3
de4637f9 4prog=$(basename $0)
c0b3d4b6 5usage() {
6 echo "\
7apkv: Quickly add and remove packages to/from Alpine virtual packages.
8
9Usage:
de4637f9 10 $prog add <packages> <virtual>
c0b3d4b6 11 Add <packages> to virtual package <virtual>. If the virtual package
12 does not exist, it will be created.
de4637f9 13
14 $prog del <packages> <virtual>
c0b3d4b6 15 Remove <packages> from virtual package <virtual>. Empty virtual
8e304013 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.
de4637f9 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
c0b3d4b6 28 Show this help.
29
de4637f9 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.
c0b3d4b6 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
de4637f9 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
c0b3d4b6 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
de4637f9 58 # override reqs list for apkv add
c0b3d4b6 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
de4637f9 70 l*) method=list;;
c0b3d4b6 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
de4637f9 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
65ebcb39 88 all=$(apk info | sort)
de4637f9 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
4974d671 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
de4637f9 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//}
4974d671 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
2b5fa3f9 107 eval "__$(echo $c | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1)=1"
de4637f9 108 done
109 done
110 # check world against owned packages
4974d671 111 # TODO: notify user if package is both in world and virtual package
de4637f9 112 orphans=$(
113 for x in $(cat /etc/apk/world | grep -v '^\.'); do
114 eval "[ \${__$(
2b5fa3f9 115 echo $x | tr -s '.:+-' _ | tr -s '<=~>@' "\n" | head -1
de4637f9 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
c0b3d4b6 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
de4637f9 172 # NOTE: $(echo) construct uses word splitting to remove newlines
c0b3d4b6 173 add) currpkgs="$(echo $currpkgs) $pkgs";;
174 del) # XXX: there's probably a more efficient way to do this
bf0563c2 175 for x in $pkgs; do
c0b3d4b6 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"
de4637f9 183 code=$?
c0b3d4b6 184else
185 show_reqs "$virt" $currpkgs
186 $sudo apk add -t "$virt" $currpkgs
de4637f9 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
4974d671 192 #apk_adb.c: [!]name[<,<=,<~,=,~,>~,>=,>,><]ver, @ for pinning
193 if grep -qE "^$x($|[<=~>@])" /etc/apk/world; then
de4637f9 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
c0b3d4b6 202fi
203# pass along sudo/apk exit code
de4637f9 204exit $code
c0b3d4b6 205
206# vi:sw=4:sts=4:et
This page took 0.06301 seconds and 4 git commands to generate.