changeset 796:e48d173534ec

fports: Implement "fports detail" to print the status of all given packages in the most detail possible
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 31 Oct 2024 14:42:51 +0100
parents 77da00746485
children 7f64b4420703
files docs/man/man8/fports.rst sbin/fports share/local-bsdtools/ports.subr
diffstat 3 files changed, 222 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/docs/man/man8/fports.rst	Wed Oct 30 15:29:54 2024 +0100
+++ b/docs/man/man8/fports.rst	Thu Oct 31 14:42:51 2024 +0100
@@ -15,6 +15,8 @@
 
 **fports deptree** [**-l** `maxlevel`] [**-r**] [**t**] `package` ...
 
+**fports detail** `package` ...
+
 
 Description
 -----------
@@ -69,6 +71,17 @@
      that depend on a given `package`.
 
 
+**fports detail** `package` ...
+
+  Print the status of all given packages in the most detail possible.
+
+  The status of the package is printed with regard to its installation status,
+  local index (if it exists) and all configured and active repositories.
+
+  A package mapping is considered also if applicable.
+  See :manpage:`package-mapping.conf(5)`.
+
+
 Environment
 -----------
 
--- a/sbin/fports	Wed Oct 30 15:29:54 2024 +0100
+++ b/sbin/fports	Thu Oct 31 14:42:51 2024 +0100
@@ -24,6 +24,7 @@
 USAGE: fports -h
        fports -V
        fports deptree [-l maxlevel] [-r] [-t] package...
+       fports detail package...
 
 GLOBAL OPTIONS:
 
@@ -305,7 +306,6 @@
 
     falist_contains pkgdeps "${rootpkg}" || fatal "${EX_SOFTWARE}" "given package \`${rootpkg}' not in the given package dependency map"
 
-    # shellcheck disable=SC2034    # appears unused
     queue=''
     farray_create queue     # array with package names to be flattened
 
@@ -331,12 +331,196 @@
         fi
     done
 
-    farray_release queue
+    farray_release "${queue}"
 
     setvar "${1}" "${alldeps}"
 }
 
 
+#:
+#: Implementation of the "detail" command.
+#:
+command_detail() {
+    # $@
+
+    local package \
+          repositories packagemapping instver instrepo \
+          repo title_printed indexfile _dummy \
+          pkglabel pkgdescr pkgversion mapped_package
+
+    repositories=''
+    get_active_repositories repositories
+    packagemapping=''
+    init_package_mapping packagemapping
+    indexfile="$(get_local_index_file)"
+
+    for package in "$@"; do
+        # 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 _command_package_repository_detail "${package}" 0
+        mapped_package="$(get_package_mapping "${packagemapping}" "${package}")"
+        if [ -z "${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 _command_mapped_package_repository_detail "${mapped_package}" "{instver}" 19
+        fi
+    done
+
+    falist_release "${packagemapping}"
+    farray_release "${repositories}"
+}
+
+
+#:
+#: 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
+#:
+_command_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
+#:
+_command_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
 #
@@ -373,6 +557,8 @@
     '') fatal 2 "no command given";;
     deptree)
         command_deptree "$@";;
+    detail)
+        command_detail "$@";;
     *)
         fatal 2 "unknown command \`${command}'";;
 esac
--- a/share/local-bsdtools/ports.subr	Wed Oct 30 15:29:54 2024 +0100
+++ b/share/local-bsdtools/ports.subr	Thu Oct 31 14:42:51 2024 +0100
@@ -192,6 +192,27 @@
 }
 
 
+#:
+#: Create an array with all configured and active repository names.
+#:
+#: Args:
+#:   $1 (str): The variable name where to store the array with the
+#:             repository names. It must be released by the caller.
+#:
+get_active_repositories() {
+    # $1
+
+    local repo
+
+    farray_create "${1}" || return
+    while IFS='' read -r repo; do
+        farray_append "${1}" "${repo}"
+    done <<EOF_b4e5385c-4c37-413b-b6f2-7909ac9eaa86
+$(get_configured_pkg_repository_names)
+EOF_b4e5385c-4c37-413b-b6f2-7909ac9eaa86
+}
+
+
 _cleanup_init_repositories() {
     [ -n "${__repodb}" ] && falist_release "${_repodb}"
     [ -n "${__allrepos}" ] && falist_release "${_allrepos}"