view sbin/fports @ 771:1c9c1cd4fd47

farray.sh: Prepare for multiple array sort implementations
author Franz Glasner <fzglas.hg@dom66.de>
date Wed, 23 Oct 2024 15:59:46 +0200
parents 56ab5c012d5f
children 43cebff4ea0d
line wrap: on
line source

#!/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