]> git.sev.monster Git - dotfiles.git/commitdiff
apkv: orphan listing, update comments
authorsev <git@sev.monster>
Mon, 28 Jun 2021 12:58:36 +0000 (07:58 -0500)
committersev <git@sev.monster>
Mon, 28 Jun 2021 13:03:56 +0000 (08:03 -0500)
apkv list -o will show orphaned packages that are not part of any
virtual package. orphans will also be shown when listing all virtual
packages with apkv list.

apkv add will now remove packages from world if present, since their
addition to a virtual package will keep them around as part of its
dependency chain.

bin/apkv

index 4f6900e0532ee45e50613569735c665d7557c836..5e586a286f5595e48d51f9d67153d00c0d78b47f 100755 (executable)
--- a/bin/apkv
+++ b/bin/apkv
@@ -1,33 +1,43 @@
 #!/bin/sh
+# TODO: add duplicate checker to seeif a pkg is in multiple virtual pkgs
 
+prog=$(basename $0)
 usage() {
     echo "\
 apkv: Quickly add and remove packages to/from Alpine virtual packages.
 
 Usage:
-    $0 add <packages> <virtual>
+    $prog add <packages> <virtual>
         Add <packages> to virtual package <virtual>. If the virtual package
         does not exist, it will be created.
-    $0 del <packages> <virtual>
+
+    $prog del <packages> <virtual>
         Remove <packages> from virtual package <virtual>. Empty virtual
-        packages are removed from world. The shorthand '$0 del * <virtual>' can
+        packages are removed from world. The shorthand '$prog del * <virtual>' can
         be used to empty <virtual>.
-    $0 list [packages]
-        List all or specific virtual packages and their contents.
-    $0 help
+
+    $prog list [-o | packages]
+        List virtual packages and their contents.
+            packages  List these virtual packages. If empty, list all.
+            -o        Only list orphan packages that are not owned by any
+                      virtual package. Orphans are automatically shown when
+                      listing all packages.
+
+    $prog help
         Show this help.
 
-Virtual packages must be prefixed with a dot to be managed with apkv. If one is
-not present, it will be added automatically.
+Virtual packages must be prefixed with a dot to be managed with apkv. Virtual
+package names passed as arguments will automatically be prefixed with dots if
+they are not present.
 
 Methods can be shortened to their closest unambiguous forms, e.g. a, d, or l.
 However, due to implementation specifics, any string starting with those forms
 will work; that functionality is unspecified and is not guaranteed.
 
-For example, the following are equivalent:
-    $0 add syslinux .virt
-    $0 a syslinux virt
-    $0 abcdefg syslinux .virt
+For example, the following are equivalent, with the first being preferred:
+    $prog add syslinux .virt
+    $prog a syslinux virt
+    $prog abcdefg syslinux virt
 
 "
 }
@@ -44,6 +54,7 @@ show_reqs() {
     shift >/dev/null
     [ -z "$_pkg" ] && return 1
     if [ $# -gt 0 ]; then
+        # override reqs list for apkv add
         _list=$(echo "$(for x do echo $x; done)" | sort | uniq)
     else
         apk info -e "$_pkg" >/dev/null || return 1
@@ -55,10 +66,7 @@ show_reqs() {
 method="$1"
 shift >/dev/null
 case $method in
-    l*) for x in ${*:-$(apk info | grep '^\.')}; do
-            show_reqs "$(prepend_dot "$x")"
-        done
-        exit;;
+    l*) method=list;;
     a*) method=add;;
     d*) method=del;;
     h*) usage; exit;;
@@ -66,6 +74,58 @@ case $method in
     *)  [ -n "$method" ] && echo "Invalid method $method" >&2; usage; exit 1;;
 esac
 
+if [ "$method" = list ]; then
+    if [ $# -eq 0 -o "$1" = '-o' ]; then
+        if [ "$1" = '-o' -a $# -gt 1 ]; then
+            echo "$method with -o switch does not accept arguments" >&2
+            usage
+            exit 1
+        fi
+        # ignore getopt's --, we don't care if an arg begins with - anyway
+        [ "$1" = '--' ] && switch >/dev/null
+
+        # OPTIMIZE: getting deps of virtual packages is slow, it would be
+        #           great to use apk info -R from show_reqs in orphan loop
+        all=$(apk info)
+        # show packages if no args
+        if [ $# -eq 0 ]; then
+            for x in $(echo "$all" | grep '^\.'); do
+                show_reqs "$(prepend_dot "$x")"
+            done
+        fi
+        # set all child packages of virtual packages as owned
+        for v in $(echo "$all" | grep '^\.'); do
+            for c in $(apk info -R $v | tail +2 | grep -v '^\.'); do
+                # NOTE: use tr because shell may not have ksh-derived ${c//}
+                # XXX: package name may have illegal chars for variable name
+                #      past those already replaced, and replacing chars may
+                #      result in variable collision—but official apk repos do
+                #      not have any packages that would cause issues
+                eval "__$(echo $c | tr -s '.:-' _)=1"
+            done
+        done
+        # check world against owned packages
+        # TODO: notify user if package is in world and also a virtual package
+        orphans=$(
+            for x in $(cat /etc/apk/world | grep -v '^\.'); do
+                eval "[ \${__$(
+                         echo $x | tr -s '.:-' _ | tr -s '<>=' "\n" | head -1
+                     )-0} -eq 0 ]" && echo $x
+            done
+        )
+        if [ -z "$orphans" ]; then
+            echo "No orphan packages found."
+        else
+            show_reqs orphans $orphans
+        fi
+    else
+        for x in $*; do
+            show_reqs "$(prepend_dot "$x")"
+        done
+    fi
+    exit
+fi
+
 ## add/del
 # get and validate packages
 pkgs=
@@ -106,7 +166,7 @@ fi
 
 currpkgs=$(apk info -R "$virt" | awk 'NR > 1 && NF')
 case $method in
-    # $(echo) construct is to use word splitting to normalize whitespace
+    # NOTE: $(echo) construct uses word splitting to remove newlines
     add) currpkgs="$(echo $currpkgs) $pkgs";;
     del) # XXX: there's probably a more efficient way to do this
          for x in $pkgs; do
@@ -117,11 +177,26 @@ esac
 if [ -z "$currpkgs" ]; then
     # virtual package is empty
     $sudo apk del "$virt"
+    code=$?
 else
     show_reqs "$virt" $currpkgs
     $sudo apk add -t "$virt" $currpkgs
+    code=$?
+    if [ $method = add -a $code -eq 0 ]; then
+        # remove packages from world if they are being moved to a virtual one
+        del=
+        for x in $pkgs; do
+            if apk info -e "$x" >/dev/null 2>&1; then
+                del="$del $x"
+            fi
+        done
+        if [ -n "$del" ]; then
+            echo "Removing packages from world:$del"
+            $sudo apk del $del
+        fi
+    fi
 fi
 # pass along sudo/apk exit code
-exit $?
+exit $code
 
 # vi:sw=4:sts=4:et
This page took 0.057856 seconds and 4 git commands to generate.