]> git.sev.monster Git - dotfiles.git/blame - bin/apkv
add git tree alias
[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
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
89 all=$(apk info)
90 # show packages if no args
91 if [ $# -eq 0 ]; then
92 for x in $(echo "$all" | grep '^\.'); do
93 show_reqs "$(prepend_dot "$x")"
94 done
95 fi
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"
105 done
106 done
107 # check world against owned packages
108 # TODO: notify user if package is in world and also a virtual package
109 orphans=$(
110 for x in $(cat /etc/apk/world | grep -v '^\.'); do
111 eval "[ \${__$(
112 echo $x | tr -s '.:-' _ | tr -s '<>=' "\n" | head -1
113 )-0} -eq 0 ]" && echo $x
114 done
115 )
116 if [ -z "$orphans" ]; then
117 echo "No orphan packages found."
118 else
119 show_reqs orphans $orphans
120 fi
121 else
122 for x in $*; do
123 show_reqs "$(prepend_dot "$x")"
124 done
125 fi
126 exit
127fi
128
c0b3d4b6 129## add/del
130# get and validate packages
131pkgs=
132virt=
133for x; do
134 if [ -n "$pkgs" ]; then
135 pkgs="$pkgs $virt"
136 elif [ -n "$virt" ]; then
137 pkgs=$virt
138 fi
139 virt=$x
140done
141if [ -z "$pkgs" ]; then
142 echo 'Not enough arguments' >&2
143 usage
144 exit 1
145fi
146virt=$(prepend_dot $virt)
147# exit if database locked (99) or no package found to delete from (1)
148apk info -e "$virt" >/dev/null
149code=$?
150if [ $code -eq 99 -o \( $method = del -a $code -ne 0 \) ]; then
151 exit $code
152fi
153
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
156# TODO: support doas
157if [ "$(id -u)" != 0 ] && command -v sudo >/dev/null 2>&1; then
158 sudo=$(command -v sudo)
159fi
160
161# handle quick delete shorthand mentioned in help
162if [ $method = del -a '*' = "$pkgs" ]; then
163 $sudo apk del "$virt"
164 exit $?
165fi
166
167currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
168case $method in
de4637f9 169 # NOTE: $(echo) construct uses word splitting to remove newlines
c0b3d4b6 170 add) currpkgs="$(echo $currpkgs) $pkgs";;
171 del) # XXX: there's probably a more efficient way to do this
bf0563c2 172 for x in $pkgs; do
c0b3d4b6 173 currpkgs=$(echo "$currpkgs" | grep -vFiw $x)
174 done;;
175esac
176
177if [ -z "$currpkgs" ]; then
178 # virtual package is empty
179 $sudo apk del "$virt"
de4637f9 180 code=$?
c0b3d4b6 181else
182 show_reqs "$virt" $currpkgs
183 $sudo apk add -t "$virt" $currpkgs
de4637f9 184 code=$?
185 if [ $method = add -a $code -eq 0 ]; then
186 # remove packages from world if they are being moved to a virtual one
187 del=
188 for x in $pkgs; do
189 if apk info -e "$x" >/dev/null 2>&1; then
190 del="$del $x"
191 fi
192 done
193 if [ -n "$del" ]; then
194 echo "Removing packages from world:$del"
195 $sudo apk del $del
196 fi
197 fi
c0b3d4b6 198fi
199# pass along sudo/apk exit code
de4637f9 200exit $code
c0b3d4b6 201
202# vi:sw=4:sts=4:et
This page took 0.053212 seconds and 4 git commands to generate.