diff sbin/fports @ 770:56ab5c012d5f

fports: Begin a new command "fports" and fully implemented its subcommand "fports deptree". fports is supposed to be the successor to check-ports.
author Franz Glasner <fzglas.hg@dom66.de>
date Wed, 23 Oct 2024 13:56:52 +0200
parents
children 43cebff4ea0d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbin/fports	Wed Oct 23 13:56:52 2024 +0200
@@ -0,0 +1,272 @@
+#!/bin/sh
+# -*- indent-tabs-mode: nil; -*-
+#:
+#: Check the version status of installed ports and compare them to
+#: version in remote repositories and the local ports index.
+#:
+#: :Author:    Franz Glasner
+#: :Copyright: (c) 2017-2024 Franz Glasner.
+#:             All rights reserved.
+#: :License:   BSD 3-Clause "New" or "Revised" License.
+#:             See LICENSE for details.
+#:             If you cannot find LICENSE see
+#:             <https://opensource.org/licenses/BSD-3-Clause>
+#: :ID:        @(#)@@SIMPLEVERSIONTAG@@
+#:
+
+: # separator for shellcheck: no module-level directives below
+
+# shellcheck disable=SC2034    # VERSION appears unused
+VERSION='@@VERSION@@'
+
+# shellcheck disable=SC2016    # no expansion
+USAGE='
+USAGE: fports [ GLOBAL-OPTIONS ] COMMAND [ COMMAND-OPTIONS ]
+
+GLOBAL OPTIONS:
+
+  -V    Print the program name and version number to stdout and exit
+
+  -h    Print this help message to stdout and exit
+
+'
+
+
+_p_datadir='@@DATADIR@@'
+[ "${_p_datadir#@@DATADIR}" = '@@' ] && _p_datadir="$(dirname "$0")"/../share/local-bsdtools
+. "${_p_datadir}/common.subr"
+. "${_p_datadir}/farray.sh"
+. "${_p_datadir}/ports.subr"
+
+
+#:
+#: Configuration directory.
+#:
+: "${CONFIGDIR:=@@ETCDIR@@}"
+
+#:
+#: Mapping configuration: installed package name -> original package name.
+#:
+#: Note:
+#:   This is independent of any repo
+#
+: "${PACKAGE_MAPPING:=${CONFIGDIR}/package-mapping.conf}"
+
+# shellcheck disable=SC1091   # does not exist -- cannot read
+[ -r "${CONFIGDIR}/pkgtools.conf" ] && . "${CONFIGDIR}/pkgtools.conf"
+
+
+# no unset variables
+set -u
+
+
+#:
+#: Implementation of the "deptree" command.
+#:
+command_deptree() {
+    local opt opt_reversed opt_maxlevel
+    # $@
+
+    opt_maxlevel=0
+    opt_reversed=no
+    while getopts "l:r" opt; do
+        case "${opt}" in
+            l)
+                opt_maxlevel=$(($OPTARG + 0));;
+            r)
+                opt_reversed=yes;;
+            \?)
+                exit 2;;
+            *)
+                fatal 2 "option handling failed";;
+        esac
+    done
+    shift $((OPTIND-1))
+    OPTIND=1
+
+    if checkyesno opt_reversed; then
+        _command_deptree_reversed "${opt_maxlevel}" "$@"
+    else
+        _command_deptree_normal "${opt_maxlevel}" "$@"
+    fi
+}
+
+
+#:
+#: Implementation of printing a "normal" dependency tree
+#:
+_command_deptree_normal() {
+    local maxlevel     # $@
+    
+    local pkgdeps pkgqueue curdeps pkg n v
+
+    maxlevel="${1}"
+    shift
+    
+    # shellcheck disable=SC2034    # pkgqueue seems unused
+    pkgqueue=''
+    farray_create pkgqueue  # queue (array) of packages that are queued for
+                            # resolution
+    
+    for pkg in "$@"; do
+        if ! pkg query '%n' "${pkg}" 1>/dev/null 2>/dev/null ; then
+            farray_release pkgqueue
+            fatal "${EX_DATAERR}" "Package not found: ${pkg}"
+        fi
+        farray_append pkgqueue "${pkg}"
+    done
+    pkgdeps=''
+    falist_create pkgdeps   # alist of packagges with its direct dependencies
+    while farray_pop pkg pkgqueue 1; do
+        if ! falist_contains pkgdeps "${pkg}"; then
+            curdeps=''
+            farray_create curdeps
+            while IFS=$' \t\n' read -r n v; do
+                [ -z "${n}" ] || [ -z "${v}" ] && continue
+                farray_append curdeps "${n}=${v}"
+                farray_append pkgqueue "${n}"
+            done <<EOF_01a8cebe-8659-4e32-87a4-bbce117e386b
+$(LC_ALL=C.UTF-8 pkg query '%dn %dv' "${pkg}")   
+EOF_01a8cebe-8659-4e32-87a4-bbce117e386b
+            falist_set pkgdeps "${pkg}" "${curdeps}"
+            farray_release curdeps
+            curdeps=''
+        fi
+    done
+    farray_release pkgqueue
+    #    falist_debug pkgdeps
+    for pkg in "$@"; do
+        _print_dependency_tree 0 "${maxlevel}" '-->' "${pkg}" "$(LC_ALL=C.UTF-8 pkg query '%v' "${pkg}")" "${pkgdeps}"
+    done
+    falist_release pkgdeps
+}
+
+
+#:
+#: Implementation of printing a reversed dependency tree
+#:
+_command_deptree_reversed() {
+    local maxlevel   # $@
+    
+    local pkgdeps pkgqueue curdeps pkg n v
+
+    maxlevel="${1}"
+    shift
+    
+    # shellcheck disable=SC2034    # pkgqueue seems unused
+    pkgqueue=''
+    farray_create pkgqueue  # queue (array) of packages that are queued for
+                            # resolution
+    
+    for pkg in "$@"; do
+        if ! pkg query '%n' "${pkg}" 1>/dev/null 2>/dev/null ; then
+            farray_release pkgqueue
+            fatal "${EX_DATAERR}" "Package not found: ${pkg}"
+        fi
+        farray_append pkgqueue "${pkg}"
+    done
+    pkgdeps=''
+    falist_create pkgdeps   # alist of packagges with its direct dependencies
+    while farray_pop pkg pkgqueue 1; do
+        if ! falist_contains pkgdeps "${pkg}"; then
+            curdeps=''
+            farray_create curdeps
+            while IFS=$' \t\n' read -r n v; do
+                [ -z "${n}" ] || [ -z "${v}" ] && continue
+                farray_append curdeps "${n}=${v}"
+                farray_append pkgqueue "${n}"
+            done <<EOF_5079e996-c6d2-4e6d-825d-53183a64ab06
+$(LC_ALL=C.UTF-8 pkg query '%rn %rv' "${pkg}")   
+EOF_5079e996-c6d2-4e6d-825d-53183a64ab06
+            falist_set pkgdeps "${pkg}" "${curdeps}"
+            farray_release curdeps
+            curdeps=''
+        fi
+    done
+    farray_release pkgqueue
+    #    falist_debug pkgdeps
+    for pkg in "$@"; do
+        _print_dependency_tree 0 "${maxlevel}" '<--' "${pkg}" "$(LC_ALL=C.UTF-8 pkg query '%v' "${pkg}")" "${pkgdeps}"
+    done
+    falist_release pkgdeps
+}
+
+
+#:
+#: Internal helper to print an indented dependency list for a package.
+#:
+#: Args:
+#:   $1 (int): The (indentation) level where a level of `0` is the root level
+#:   $2 (int): The maximum level (`$1`)  to print to
+#:   $3 (str): The package tag to use to for non-root-levels
+#:   $4 (str): The package name
+#:   $5 (str): The package version
+#:   $6 (alist): The llist of resolved packages and their dependencies
+#:
+_print_dependency_tree() {
+    # $1 $2 $3 $4 $5 $6
+
+    local i pkg ver curdeps
+
+    if [ "${2}" -ge 1 ]; then
+        [ "${1}" -gt "${2}" ] && return 0
+    fi
+    
+    i="${1}"
+    while [ "${i}" -gt 1 ]; do
+        printf '%s' '    '
+        i=$((i - 1))
+    done
+    [ "${1}" -ne 0 ] && printf '%s ' "${3}"
+    printf '%s v%s\n' "${4}" "${5}"
+    falist_get curdeps "${6}" "${pkg}"
+    i=1
+    while farray_tryget pkg "${curdeps}" "${i}"; do
+        ver="${pkg#*=}"
+        pkg="${pkg%%=*}"
+        _print_dependency_tree $(($1 + 1)) "${2}" "${3}" "${pkg}" "${ver}" "${6}"
+        i=$((i + 1))
+    done
+    farray_release curdeps
+}
+
+
+#
+# Global option handling
+#
+while getopts "Vh" _opt ; do
+    case "${_opt}" in
+        V)
+            printf 'fports %s\n' '@@SIMPLEVERSIONSTR@@'
+            exit 0
+            ;;
+        h)
+            echo "${USAGE}"
+            exit 0
+            ;;
+        \?)
+            exit 2;
+            ;;
+        *)
+            fatal 2 "option handling failed"
+            ;;
+    esac
+done
+
+#
+# Reset the Shell's option handling system to prepare for handling
+# command-local options.
+#
+shift $((OPTIND-1))
+OPTIND=1
+
+command="${1-}"
+shift
+
+case "${command}" in
+    '') fatal 2 "no command given";;
+    deptree)
+        command_deptree "$@";;
+    *)
+        fatal 2 "unknown command \`${command}'";;
+esac