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