Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
view sbin/fports @ 808:ab21dd56f99e
fports: Implement "fports detail -A" as a shortcut to "-b -n -m".
While there fixed some "program" usage in the manpage. Also rename
a bogus "options" directive to "option".
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Tue, 05 Nov 2024 11:57:34 +0100 |
| parents | ed94334bc6f1 |
| children | a59cc4bea000 |
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 -h|--help fports -V|--version fports deptree [-l maxlevel|--maxlevel=maxlevel] [-r|--reverse] [-t|--list|--transitive] package... fports detail [-A] [-b|--nofreebsd|--no-freebsd] [-n|--noauto|--no-auto] [-m|--mapped] [package...] GLOBAL OPTIONS: -V, --version Print the program name and version number to stdout and exit. -h, --help 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_reversed opt_maxlevel opt_flat # $@ local opt opt_maxlevel=0 opt_reversed=no opt_flat=no while getopts "l:rt-:" opt; do postprocess_getopts_for_long "l:rt-:" opt "maxlevel=" "reverse" "list" "transitive" "" case "${opt}" in l|maxlevel) opt_maxlevel=$(($OPTARG + 0));; r|reverse) # shellcheck disable=SC2034 opt_reversed=yes;; t|list|transitive) opt_flat=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}" "${opt_flat}" "$@" else _command_deptree_normal "${opt_maxlevel}" "${opt_flat}" "$@" fi } #: #: Implementation of printing a "normal" dependency tree #: _command_deptree_normal() { local maxlevel flat # $@ local pkgdeps pkgqueue curdeps pkg n v flatdeps maxlevel="${1}" flat="${2}" shift 2 # 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 if checkyesno flat; then for pkg in "$@"; do _flatten_pkgdeps flatdeps "${pkgdeps}" "${pkg}" _print_flatdeps '-->' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${flatdeps}" falist_release "${flatdeps}" done else for pkg in "$@"; do _print_dependency_tree 0 "${maxlevel}" '-->' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${pkgdeps}" done fi falist_release pkgdeps } #: #: Implementation of printing a reversed dependency tree #: _command_deptree_reversed() { local maxlevel flat # $@ local pkgdeps pkgqueue curdeps pkg n v flatdeps maxlevel="${1}" # shellcheck disable=SC2034 # appears unused flat="${2}" shift 2 # 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 if checkyesno flat; then for pkg in "$@"; do _flatten_pkgdeps flatdeps "${pkgdeps}" "${pkg}" _print_flatdeps '<--' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${flatdeps}" falist_release "${flatdeps}" done else for pkg in "$@"; do _print_dependency_tree 0 "${maxlevel}" '<--' "${pkg}" "$(LC_ALL=C.UTF-8 "${PKG}" query '%v' "${pkg}")" "${pkgdeps}" done fi 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 alist 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 } #: #: Args: #: $1 (str): The package tag to use #: $2 (str): The root package name #: $3 (str): The package version of the root package in `$3` #: $4 (alist): The alist of the flattened dependencies #: _print_flatdeps() { # $1 $2 $3 $4 local pkgnames i n v printf '%s v%s\n' "${2}" "${3}" # shellcheck disable=SC2034 # appears unused pkgnames='' farray_create pkgnames falist_keys pkgnames "$4" farray_sort pkgnames i=1 while farray_tryget n pkgnames "${i}"; do falist_get v "${4}" "${n}" printf '%s %s v%s\n' "${1}" "${n}" "${v}" i=$((i + 1)) done farray_release pkgnames } #: #: Flatten a package dependency alist. #: #: Args: #: $1 (str): The variable name where to store the flattened dependencies #: into. This object (alist) must be released by the caller. #: $2 (str): The alist with all packages and its dependencies #: $3 (str): The package for which to flatten its dependencies #: _flatten_pkgdeps() { local pkgdeps rootpkg # and $1 local alldeps queue pkg curdeps i depname depver pkgdeps="${2}" rootpkg="${3}" falist_contains pkgdeps "${rootpkg}" || fatal "${EX_SOFTWARE}" "given package \`${rootpkg}' not in the given package dependency map" queue='' farray_create queue # array with package names to be flattened farray_append queue "${rootpkg}" alldeps='' falist_create alldeps # alist with pkgname -> version while farray_pop pkg queue 1; do if ! falist_contains alldeps "${pkg}"; then curdeps='' falist_get curdeps pkgdeps "${pkg}" i=1 while farray_tryget depname curdeps "${i}"; do depver="${depname#*=}" depname="${depname%%=*}" if ! falist_contains alldeps "${depname}"; then falist_set alldeps "${depname}" "${depver}" fi farray_append queue "${depname}" i=$((i + 1)) done farray_release curdeps fi done farray_release "${queue}" setvar "${1}" "${alldeps}" } #: #: Implementation of the "detail" command. #: command_detail() { local opt_noauto opt_mapped # $@ local package \ packages do_sort idx prev_package \ repositories packagemapping instver instrepo \ repo title_printed indexfile _dummy opt acookie \ pkglabel pkgdescr pkgversion mapped_package do_sort=no opt_nofreebsd=no opt_noauto=no opt_mapped=no while getopts "Abnm-:" opt; do postprocess_getopts_for_long "Abnm-:" opt "nofreebsd" "no-freebsd" "noauto" "no-auto" "mapped" "" case "${opt}" in A) opt_nofreebsd=yes opt_noauto=yes opt_mapped=yes do_sort=yes ;; b|nofreebsd|no-freebsd) # shellcheck disable=SC2034 # appears unused opt_nofreebsd=yes do_sort=yes ;; n|noauto|no-auto) # shellcheck disable=SC2034 # appears unused opt_noauto=yes do_sort=yes ;; m|mapped) # shellcheck disable=SC2034 # appears unused opt_mapped=yes do_sort=yes ;; \?) exit 2;; *) fatal 2 "option handling failed";; esac done shift $((OPTIND-1)) OPTIND=1 packages='' farray_create packages repositories='' get_active_repositories repositories packagemapping='' init_package_mapping packagemapping indexfile="$(get_local_index_file)" if checkyesno opt_nofreebsd; then while IFS='|' read -r package repo; do [ "${repo}" != 'FreeBSD' ] && farray_append packages "${package}" done <<EOF_1fa6f326-49e6-4b01-a7ea-52372d00df1e $(LC_ALL=C.UTF-8 "${PKG}" query '%n|%R') EOF_1fa6f326-49e6-4b01-a7ea-52372d00df1e fi if checkyesno opt_noauto; then for package in $(LC_ALL=C.UTF-8 "${PKG}" query -e '%a = 0' '%n'); do farray_append packages "${package}" done fi if checkyesno opt_mapped; then acookie="$(falist_cookie_first packagemapping)" while falist_tryget_key_at package "${acookie}"; do farray_append packages "${package}" acookie="$(falist_cookie_next "${acookie}")" done fi for package in "$@"; do farray_append packages "${package}" done checkyesnovalue "${do_sort}" && farray_sort packages idx=1 prev_package='' # to skip duplicate packages while farray_tryget package packages "${idx}"; do if [ "${prev_package}" != "${package}" ]; then _package_max_detail "${package}" "${packagemapping}" "${repositories}" "${indexfile}" prev_package="${package}" fi idx=$((idx + 1)) done falist_release "${packagemapping}" farray_release "${repositories}" farray_release "${packages}" } #: #: Implementation of printing the most details possible for a package. #: #: Implements all the repeating stuff for a package for e.g. `command_detail`. #: #: Args: #: $1 (str): The name of the package #: $2 (alist): The #: $3 (array): The array with all the configured/active repositories #: $4 (str, null): The local index file if it exists #: _package_max_detail() { local package packagemapping repositories indexfile local instver instrepo repo title_printed _dummy \ pkglabel pkgdescr pkgversion mapped_package package="${1}" packagemapping="${2}" repositories="${3}" indexfile="${4}" # shellcheck disable=SC2034 # appears unused title_printed=no IFS='|' read -r instver instrepo <<EOF_e9bd7819-b4c5-4a86-b984-f5226db58cb1 $(LC_ALL=C.UTF-8 "${PKG}" query '%v|%R' "${package}") EOF_e9bd7819-b4c5-4a86-b984-f5226db58cb1 print_title title_printed "${package}" "${instver}" "${instrepo}" if [ -n "${indexfile}" ]; then read -r _dummy pkglabel pkgdescr <<EOF_b1f225bd-d234-4a23-8a2a-40c2e5b7ff3c $(LC_ALL=C.UTF-8 "${PKG}" version -U -I -n "${package}" -v "${indexfile}") EOF_b1f225bd-d234-4a23-8a2a-40c2e5b7ff3c pkgversion="$(parse_index_file_for_package_version "${indexfile}" "${package}")" print_detail_item "INDEX" "${pkgversion}" "${pkglabel}" "${pkgdescr}" fi farray_for_each repositories _package_repository_detail "${package}" 0 mapped_package="$(get_package_mapping "${packagemapping}" "${package}")" if [ -n "${mapped_package}" ]; then printf '%18s %s\n' "--------------->" "${mapped_package}" if [ -n "${indexfile}" ]; then pkgversion="$(parse_index_file_for_package_version "${indexfile}" "${mapped_package}")" pkglabel="$(LC_ALL=C.UTF-8 "${PKG}" version --test-version "${instver}" "${pkgversion}")" print_detail_item "INDEX" "${pkgversion}" "${pkglabel}" '' 19 fi farray_for_each repositories _mapped_package_repository_detail "${mapped_package}" "{instver}" 19 fi } #: #: Array callback to print package details with regard to a repository. #: #: Args: #: $1 (str): The repositories array #: $2 (int): The current index #: $3: The element value (i.e. repository name) #: $4 (str): The (master) package name #: $5 (int): The extra indent value to forward to called functions #: _package_repository_detail() { local repositories idx reponame package extraindent local _dummy \ pkglabel pkgdescr pkgversion repositories="${1}" # shellcheck disable=SC2034 # appears unused (yes, accept it) idx="${2}" reponame="${3}" package="${4}" extraindent="${5:-0}" read -r _dummy pkglabel pkgdescr <<EOF_19cf2d80-4eb9-4cda-bd4d-96b04e769206 $(LC_ALL=C.UTF-8 "${PKG}" version -U -R -r "${reponame}" -n "${package}" -v) EOF_19cf2d80-4eb9-4cda-bd4d-96b04e769206 pkgversion="$(LC_ALL=C.UTF-8 "${PKG}" rquery -U -r "${reponame}" '%v' "${package}")" print_detail_item "${reponame}" "${pkgversion}" "${pkglabel}" "${pkgdescr}" "${extraindent}" } #: #: Array callback to print package details for a mapped package with regard #: to a repository. #: #: Args: #: $1 (str): The repositories array #: $2 (int): The current index #: $3: The element value (i.e. repository name) #: $4 (str): The mapped package name #: $5 (str): The parent package version #: $6 (int): The extra indent value to forward to called functions #: _mapped_package_repository_detail() { local repositories idx reponame package parent_pkgversion extraindent local _dummy \ pkglabel pkgversion repositories="${1}" # shellcheck disable=SC2034 # appears unused (yes, accept it) idx="${2}" reponame="${3}" package="${4}" parent_pkgversion="${5}" extraindent="${6:-0}" pkgversion="$(LC_ALL=C.UTF-8 "${PKG}" rquery -U -r "${reponame}" '%v' "${package}")" pkglabel="$(LC_ALL=C.UTF-8 "${PKG}" version --test-version "${parent_pkgversion}" "${pkgversion}")" print_detail_item "${reponame}" "${pkgversion}" "${pkglabel}" '' "${extraindent}" } #: #: Print the output title line for a package. #: #: Args: #: $1 (str): The name of the variable where to get or store the flag #: whether the title for the package in `$2` has already been #: printed. #: $2 (str): The package name #: $3 (str): The package version #: $4 (str): The repository name from which the package has been installed #: #: Output (stdout): #: The formatted title line #: print_title() { local varname_title_printed package version repo varname_title_printed="${1}" package="${2}" version="${3}" repo="${4}" if ! checkyes "${varname_title_printed}"; then if [ -n "${version}" ]; then # The package is installed printf '%-36s %-17s (%s)\n' "${package}" "${version}" "${repo}" else # The package is not installed printf '%-36s NOT INSTALLED\n' "${package}" fi setvar "${varname_title_printed}" 'yes' fi } #: #: Print a detail item to stdout. #: #: The description `_descr` will not be printed if the label `_label` #: is ``?``. #: #: Args: #: $1 (str): The repository name #: $2 (str): The version number to print to #: $3 (str): The label (aka comparison character) to print to #: $4 (str): The description to print to #: $5 (int, optional): The extra indentation to use. (Default 0) #: #: Output (stdout): #: The formatted detail line #: print_detail_item() { local repo version label descr indent local real_descr repo="${1}" version="${2}" label="${3}" descr="${4}" indent="${5:-0}" if [ "${label}" = '?' ]; then real_descr='' else real_descr="${descr}" fi printf '%-*s %-15s: %-17s %s %s\n' $((indent)) '' "${repo}" "${version}" "${label}" "${real_descr}" } # # Global option handling # while getopts "Vh-:" _opt ; do postprocess_getopts_for_long "Vh-:" _opt "version" "help" "" case "${_opt}" in V|version) printf 'fports %s\n' '@@SIMPLEVERSIONSTR@@' exit 0 ;; h|help) 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 "$@";; detail) command_detail "$@";; *) fatal 2 "unknown command \`${command}'";; esac
