diff sbin/check-ports @ 128:3dcae0e91769

Move all admin scripts into the "sbin" folder
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 17 Oct 2019 09:09:13 +0200
parents bin/check-ports@cf9dde7a3a0d
children 54de2955bfa9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbin/check-ports	Thu Oct 17 09:09:13 2019 +0200
@@ -0,0 +1,501 @@
+#!/bin/sh
+# -*- indent-tabs-mode: nil; -*-
+: 'Check the version status of installed ports and compare them to
+repository versions.
+
+:Author:    Franz Glasner
+:Copyright: (c) 2017-2019 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:        @(#)@@PKGORIGIN@@ $HGid$
+
+'
+
+VERSION="@@VERSION@@"
+
+#
+# Configuration directory
+#
+: ${CONFIGDIR:=@@ETCDIR@@}
+
+test -r "${CONFIGDIR}/tools.conf" && . "${CONFIGDIR}/tools.conf"
+
+#
+# Mapping configuration: installed package name -> original package name
+# Note: This is independent of any repo
+#
+: ${PACKAGE_MAPPING:=${CONFIGDIR}/package-mapping.conf}
+
+#
+# Local repository with non-public packages and/or ports with changed
+# OPTIONS (i.e. not using the defaults) or forks of official packages with
+# other package names
+#
+: ${LOCAL_REPO:=LocalRepo}
+
+#
+# Local repository with ports with default OPTIONS (i.e. unchanged)
+# but newer than the packages in the "FreeBSD" repository.
+# Some sort of a fast-track repository.
+#
+: ${LOCALBSDPORTS_REPO:=LocalBSDPorts}
+
+#
+# The official FreeBSD binary repository
+#
+: ${FREEBSD_REPO:=FreeBSD}
+
+#
+# Directly installed from ports
+#
+: ${PORTS_DIRECT_INSTALLED_REPO:=unknown-repository}
+
+#
+# For the workaround of the bug in pkg rquery -I
+#
+: ${PORTSDIR:=/usr/ports}
+: ${INDEXDIR:=${PORTSDIR}}
+: ${INDEXFILE:=@@INDEXFILE@@}
+
+
+get_remote_repo_versions() {
+    : 'Determine the remote repository versions of all packages in
+    repository `_repo`.
+
+    Args:
+        _repo: the name of the repote repository
+
+    Returns:
+        status 0 on success, 1 on errors
+
+    Output (Globals):
+        remote_versions_${_repo}: the versions of all packages in `_repo` and
+                                  their extended version status with respect to
+                                  locally installed packages
+
+    '
+    local _repo _data _rv
+
+    _repo=$1
+
+    _data=$(pkg version -U -R -r ${_repo} -v)
+    _rv=$?
+    eval remote_versions_${_repo}=\"\${_data}\"
+    return ${_rv}
+}
+
+get_remote_repo_data() {
+    : 'Get the extended package version information from the remote repository
+    `_repo` for package `_name`.
+
+    Args:
+        _repo: the name of the remote repository
+        _name: the package name
+
+    Input (Globals):
+        remote_versions_${_repo}: the extended version info for *all* packages
+                                  in repo `_repo`.
+
+    Returns:
+        status 0 on success, 1 on errors or if the package is not found
+        in the remote repository
+
+    Output (Globals):
+        remote_label_${_repo}:
+        remote_descr_${_repo}:
+
+    '
+    local _repo _name _rversions _rfqp _rl _rdescr
+
+    _repo=$1
+    _name=$2
+
+    eval _rversions=\"\${remote_versions_${_repo}}\"
+    while read _rfqp _rl _rdescr ; do
+        if [ ${_rfqp%-*} = ${_name} ] ; then
+            eval remote_label_${_repo}=\"\${_rl}\"
+            eval remote_descr_${_repo}=\"\${_rdescr}\"
+            return 0
+        fi
+    done <<EOF884657
+${_rversions}
+EOF884657
+    eval remote_label_${_repo}=""
+    eval remote_descr_${_repo}=""
+    return 1
+}
+
+get_local_index_versions() {
+    : 'Determine the extendes versions of all packages in the local index
+    (ports).
+
+    Returns:
+        status 0 on success or 1 on errors
+
+    Output (Globals):
+        local_index_versions:
+
+    '
+    local_index_versions=$(pkg version -I -v)
+}
+
+get_repo_for_installed_package() {
+    : 'Determine for a package `_name` from which repository is has been
+    installed.
+
+    Args:
+        _name: the name of the package to search for
+
+    Input (Globals):
+        installed_data  the output of ``pkg query "%n %v %R"`` of all
+                        installed packages
+
+    Returns:
+        0 on success, 1 on errors or if the package is not installed
+
+    Output (Globals):
+        repository: the repository from which the installed packages `_name`
+                    has been installed
+
+    '
+    local _name _n _v _r
+
+    _name=$1
+
+    while read _n _v _r ; do
+        if [ ${_name} = ${_n} ] ; then
+            repository=${_r}
+            return 0
+        fi
+    done <<EOF223777
+${installed_data}
+EOF223777
+    return 1
+}
+
+get_immediate_index_version() {
+    : 'Determine for package `_package` the version of the package in the
+    local ports index.
+
+    Args:
+        _package: the package name to search for
+
+    Input (Globals):
+        INDEXDIR:  the directory where to search the index file
+        INDEXFILE: the name of the index file
+
+    Returns:
+        0 on success, 1 on errors or if the package is not in the index
+
+    Output (Globals):
+        immediate_index_version: the version number of `_package` in the
+                                 index
+
+    '
+    local _package _line _fqpn _n _lines
+
+    _package=$1
+
+#    _val=$(pkg rquery -I "${_package}" | cut -f 1 -d '|')
+#    _rv=$?
+#    immediate_index_version=${_val##*-}
+#    return ${_rv}
+
+    if [ -r "${INDEXDIR}/${INDEXFILE}" ] ; then
+        #
+        # Note: Direct piping does not set immediate_index_version at return correctly
+        #       "_line" is set correctly and parsing works, but the return 0 seems to kill
+        #       some of the previous effects.
+        #
+        # "grep" does a fast pre-selection, reading, parsing and comparing is done for
+        # exact matching.
+        #
+        _lines=$(egrep '^'"${_package}" "${INDEXDIR}/${INDEXFILE}")
+        while read _line ; do
+            _fqpn="${_line%%|*}"
+            _n=${_fqpn%-*}
+	    if [ "${_package}" = "${_n}" ] ; then
+                immediate_index_version="${_fqpn##*-}"
+                return 0
+            fi
+        done <<EOF1334TGH1
+${_lines}
+EOF1334TGH1
+    fi
+
+    immediate_index_version=""
+    return 1
+}
+
+get_immediate_remote_repo_version() {
+    : 'Ask a remote repository for the version of a package.
+
+    Args:
+        _repo: the repository name
+        _name: the name of the package
+
+    Returns:
+        0 on success and other status codes otherwise
+
+    Output (Globals):
+        immediate_remote_repo_version_${_repo}: the version of package `_name`
+                                in repo `_repo`
+
+    '
+    local _repo _name _version _rv
+
+    _repo=$1
+    _name=$2
+
+    _version=$(pkg rquery -U -r "${_repo}" '%v' "${_name}")
+    _rv=$?
+    eval immediate_remote_repo_version_${_repo}=\"\${_version}\"
+    return ${_rv}
+}
+
+assert_local_version() {
+    : 'Check whether an installed package `_name` has given
+    version `_version`.
+
+    Args:
+        _name:    the package name
+        _version: the version to check for
+
+    Input (Globals):
+        installed_data: the output of ``pkg query "%n %v %R"`` of all
+                        installed packages
+
+    Returns:
+        - 0 if the installed version of package `_name` is equal to `_version`
+        - 1 if the installed version of package `_name` differs from `_version`
+        - 2 on other errors
+
+    '
+    local _name _version _n _v _r
+
+    _name=$1
+    _version=$2
+
+    while read _n _v _r ; do
+        if [ ${_name} = ${_n} ] ; then
+            if [ ${_version} != ${_v} ] ; then
+                return 1
+            else
+                return 0
+            fi
+        fi
+    done <<EOF223
+${installed_data}
+EOF223
+    return 2
+}
+
+get_mapping() {
+    : 'Determine whether a package `_package` is essentially the same as
+    another package.
+
+    Args:
+        _package: the new name of the package
+
+    Returns:
+        0 when a package mapping has been found, 1 otherwise
+
+    Output (Globals):
+        mapped_package_name: the name of the package on which `_package` is
+                             based on
+
+    This command reads from the mapping database in in file
+    `/usr/local/etc/local-bsdtools/package-mapping.conf`.
+    Example::
+
+        #
+        # _package                         mapped_package_name
+        #
+        fmg-nextcloud-php71                nextcloud-php71
+        fmg-nextcloud-twofactor_totp-php71 nextcloud-twofactor_totp-php71
+
+    '
+    local _package _n _mapped
+
+    _package=$1
+
+    if [ -r "${PACKAGE_MAPPING}" ] ; then
+        while read _n _mapped ; do
+            if [ "${_n}" = "${_package}" ] ; then
+                mapped_package_name="${_mapped}"
+                return 0
+            fi
+        done < ${PACKAGE_MAPPING}
+    fi
+    mapped_package_name=""
+    return 1
+}
+
+print_title() {
+    : 'Print the output title line for a package
+
+    Args:
+        _package: the package name
+        _repo:    the repository name
+
+    Input (Globals).
+        title_printed: a global that determines if the title really needs
+                       to be printed.
+
+                       If it is an empty string the the title is
+                       really printed and the variable is set to
+                       "yes".
+
+    Output (Globals):
+        title_printed: set to "yes" if the title has been printed
+
+    '
+    local _package _repo
+
+    _package=$1
+    _repo=$2
+    if [ -z "${title_printed}" ] ; then
+        echo "${_package}    (${_repo})"
+        title_printed=yes
+    fi
+}
+
+
+alldata_flag=""
+alldata_flag_LocalBSDPorts=""
+alldata_flag_LocalRepo=""
+short_flag=""
+verbose_flag=""
+
+while getopts "VAasv" _opt ; do
+    case ${_opt} in
+	V)
+            echo "check-ports v${VERSION} (rv:@@HGREVISION@@)"
+            exit 0
+	    ;;
+        A)
+            # print for every package the status of all repositories
+            alldata_flag=1
+            alldata_flag_LocalBSDPorts=1
+            alldata_flag_LocalRepo=1
+            ;;
+        a)
+            # print the data of all repos that have the package
+            alldata_flag=1
+            ;;
+        s)
+            # "short" output: if installed from FreeBSD repo: don't
+            # report if only the index is newer
+            short_flag=1
+            ;;
+        v)
+            # print all titles and repo of every installed always
+            verbose_flag=1
+            ;;
+        \?)
+            exit 2
+            ;;
+        *)
+            echo "option handling failed" >&2
+            exit 2
+            ;;
+    esac
+done
+
+if [ -n "${short_flag}" -a -n "${alldata_flag}" ]; then
+    echo "the -s option cannot be combined with -A or -a" >&2
+    exit 2
+fi
+
+installed_packages=$(pkg query '%n')
+installed_data="$(pkg query '%n %v %R' $installed_packages)"
+
+get_remote_repo_versions ${LOCAL_REPO}
+get_remote_repo_versions ${LOCALBSDPORTS_REPO}
+get_remote_repo_versions ${FREEBSD_REPO}
+get_local_index_versions
+
+while read lfqp llabel ldescr ; do
+    _installed_name=${lfqp%-*}
+    _installed_version=${lfqp##*-}
+    title_printed=""
+    get_repo_for_installed_package ${_installed_name}
+    get_mapping ${_installed_name}
+    if [ -n "${verbose_flag}" ] ; then
+        print_title "${lfqp}" "${repository}"
+    fi
+    if ! assert_local_version ${_installed_name} ${_installed_version} ; then
+        echo "Assertion failed: $lfqp ${_installed_name} ${_installed_version} ${llabel}" >&2
+        exit 1
+    fi
+    get_remote_repo_data ${LOCAL_REPO} ${_installed_name}
+    get_remote_repo_data ${LOCALBSDPORTS_REPO} ${_installed_name}
+    get_remote_repo_data ${FREEBSD_REPO} ${_installed_name}
+    _print_detail=""
+    if [ -n "${mapped_package_name}" ] ; then
+        _print_detail=1
+    fi
+    if [ \( -n "${alldata_flag}" \) ]; then
+        _print_detail=1
+    else
+        if [ -n "${short_flag}" ]; then
+            #
+            # NOTE: -s and -A/-a are incompatible: so "alldata_XXX" needs not
+            #       to be checked!
+            #
+            case "${repository}" in
+                "${FREEBSD_REPO}")
+                    if [ \( "${llabel}" != '<' -a "${llabel}" != '=' \) -o "${remote_label_FreeBSD}" != '=' -o "${remote_label_LocalRepo}" != '?' -o "${remote_label_LocalBSDPorts}" != '?' ]; then
+                        _print_detail=1
+                    fi
+                    ;;
+                "${LOCAL_REPO}")
+                    _print_detail=1
+                    ;;
+                "${LOCALBSDPORTS_REPO}")
+                    if [ "${llabel}" != '=' -o "${remote_label_FreeBSD}" != '>' -o "${remote_label_LocalRepo}" != '?' -o "${remote_label_LocalBSDPorts}" = '?' -o "${remote_label_LocalBSDPorts}" = '<' ]; then
+                        _print_detail=1
+                    fi
+                    ;;
+                "${PORTS_DIRECT_INSTALLED_REPO}")
+                    _print_detail=1
+                    ;;
+                *)
+                    echo "ERROR: unhandled repository: ${repository}" >&2
+                    exit 1
+                    ;;
+            esac
+        else
+            if [ \( \( "${llabel}" != '?' -a "${llabel}" != '=' \) -o \( "${remote_label_FreeBSD}" != '?' -a "${remote_label_FreeBSD}" != '=' \) -o \( "${remote_label_LocalBSDPorts}" != '?' -a "${remote_label_LocalBSDPorts}" != '=' \) -o \( "${remote_label_LocalRepo}" != '?' -a "${remote_label_LocalRepo}" != '=' \) \) -o \( "${repository}" = "${PORTS_DIRECT_INSTALLED_REPO}" \) ]; then
+                _print_detail=1
+            fi
+        fi
+    fi
+    if [ -n "${_print_detail}" ]; then
+        print_title "${lfqp}" "${repository}"
+        echo "   INDEX        : ${llabel} ${ldescr}"
+        echo "   FreeBSD      : ${remote_label_FreeBSD} ${remote_descr_FreeBSD}"
+        if [ \( -n "${alldata_flag_LocalBSDPorts}" \) -o \( "${remote_label_LocalBSDPorts}" != '?' \) ] ; then
+            echo "   LocalBSDPorts: ${remote_label_LocalBSDPorts} ${remote_descr_LocalBSDPorts}"
+        fi
+        if [ \( -n "${alldata_flag_LocalRepo}" \) -o \( "${remote_label_LocalRepo}" != '?' \) ] ; then
+            echo "   LocalRepo    : ${remote_label_LocalRepo} ${remote_descr_LocalRepo}"
+        fi
+        if [ -n "${mapped_package_name}" ] ; then
+	    echo "   ---> ${mapped_package_name}"
+            get_immediate_index_version "${mapped_package_name}"
+	    get_immediate_remote_repo_version ${LOCAL_REPO} ${mapped_package_name}
+            get_immediate_remote_repo_version ${LOCALBSDPORTS_REPO} ${mapped_package_name}
+            get_immediate_remote_repo_version ${FREEBSD_REPO} ${mapped_package_name}
+            echo "      INDEX        : ${immediate_index_version}"
+            echo "      FreeBSD      : ${immediate_remote_repo_version_FreeBSD}"
+	    echo "      LocalBSDPorts: ${immediate_remote_repo_version_LocalBSDPorts}"
+	    echo "      LocalRepo    : ${immediate_remote_repo_version_LocalRepo}"
+        fi
+    fi
+done <<EOF856661111299999
+${local_index_versions}
+EOF856661111299999