From f7878ef7b0cbcd34b604f699e93478d2358d9919 Mon Sep 17 00:00:00 2001 From: bill-auger Date: Wed, 23 Sep 2020 03:00:06 -0400 Subject: [parabola-dependents]: formatted and verbose output --- src/maintenance-tools/parabola-dependents | 107 ++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/src/maintenance-tools/parabola-dependents b/src/maintenance-tools/parabola-dependents index 0e0f619..f601bb3 100755 --- a/src/maintenance-tools/parabola-dependents +++ b/src/maintenance-tools/parabola-dependents @@ -1,9 +1,7 @@ #!/bin/bash readonly BE_VERBOSE=$( [[ "$1" == '-v' ]] && echo 1 || echo 0 ) -readonly DB_DIR="$(su $(logname) -c 'mktemp -d -t parabola-dependents-XXXXXXXXXX')" -readonly CFG_FILE=${DB_DIR}/pacman-all.conf -readonly OPTS="--dbpath=${DB_DIR} --config=${CFG_FILE}" +# readonly REPOS=( nonprism nonsystemd{-testing,} libre{-testing,} readonly REPOS=( nonprism{-testing,} nonsystemd{-testing,} libre{-testing,} kernels{-testing,} testing core extra community{-testing,} pcr{-testing,} nonprism-multilib{-testing,} nonsystemd-multilib @@ -23,17 +21,31 @@ readonly USAGE='USAGE: List all parabola packages which are dependents of a specified package. + By default, only first-order dependents are listed, + with counts of higher-order dependents. + If does not exist, a dummy package will be created, in memory, for pactree to reflect upon. + Note: this script can take several minutes to complete, + if the dependency-tree for is large. + Options: -v - Display the dependency-chain.' + Itemize all higher-order dependents, displaying the dependency-chain.' readonly INVALID_ARG_MSG="no dependency package specified\n\n${USAGE}" readonly UNPRIVILEGED_MSG="this script requires super-user privileges" readonly CBLUE='\033[0;36m' readonly CRED='\033[0;31m' readonly CEND='\033[0m' +readonly SEP_CHAR='=' +DB_DIR='' # Init() +CFG_FILE='' # Init() +OPTS='' # Init() + +Ignored=() # CollectResults() +Dependents=() # CollectResults() +declare -A HiorderDependents # CollectResults() Log() # (log_fmt [args]*) @@ -41,7 +53,7 @@ Log() # (log_fmt [args]*) local log_fmt=$1 ; shift ; local args="$@" - printf "${CBLUE}${log_fmt}${CEND}\n" ${args} + printf "${CBLUE}${log_fmt}${CEND}\n" ${args} >&2 } LogError() # (source_file func_name line_n) @@ -51,7 +63,7 @@ LogError() # (source_file func_name line_n) local line_n=$3 printf "${CRED}ERROR: in ${func_name}\n${line_n}: %s${CEND}\n" \ - "$(awk "(( NR == ${line_n} )) { print }" ${source_file})" + "$(awk "(( NR == ${line_n} )) { print }" ${source_file})" >&2 } Init() # (dep_pkgname) @@ -59,11 +71,14 @@ Init() # (dep_pkgname) local dep_pkgname=$1 local dummy_pkg=${dep_pkgname}-0.0.0-42-$(uname -m).pkg.tar.xz + readonly DB_DIR="$(su $(logname) -c 'mktemp -d -t parabola-dependents-XXXXXXXXXX')" + readonly CFG_FILE=${DB_DIR}/pacman-all.conf + readonly OPTS="--dbpath=${DB_DIR} --config=${CFG_FILE}" + printf "[options]\nArchitecture = auto\n" > ${CFG_FILE} for repo in ${REPOS[@]} do printf "[${repo}]\nInclude = /etc/pacman.d/mirrorlist\n" >> ${CFG_FILE} done - printf "[parabola-dependents]\nServer = file://${DB_DIR}\n" >> ${CFG_FILE} Log "updating database ...." pacman ${OPTS} -Sy &> /dev/null || true @@ -80,8 +95,9 @@ Init() # (dep_pkgname) repo-add --new parabola-dependents.db.tar ./${dummy_pkg} &> /dev/null Log "dummy package '${dep_pkgname}' created" + printf "[parabola-dependents]\nServer = file://${DB_DIR}\n" >> ${CFG_FILE} fi - pacman ${OPTS} -Sy&> /dev/null + pacman ${OPTS} -Sy &> /dev/null } IsArchRepo() # (repo) @@ -89,31 +105,63 @@ IsArchRepo() # (repo) local repo=$1 ; [[ "${repo}" =~ ^(community|core|extra|multilib|testing)$ ]] } -ListParabolaDependents() # (dep_pkgname) +CollectResults() # (dep_pkgname) { local dep_pkgname=$1 - local dep_chain pkg repos + local dep_chains dep_chain dep_pkg via_pkg repos repo # TODO: --chain is a custom pactree feature export PATH="/code/pacman-contrib/src:${PATH}" - Log "searching ...." ; echo ; - # TODO: --chain is a custom pactree feature - pactree ${OPTS} --sync --reverse --unique --chain ${dep_pkgname} | sort | \ - while read dep_chain - do pkg=$(sed 's|.*<- ||' <<<${dep_chain}) - repos=$(pacman ${OPTS} -Si ${pkg} | grep Repository | cut -d ':' -f 2) - - for repo in ${REPOS} - do if IsArchRepo ${repo} - then echo "${repo}/${pkg} (ignoring)" >&2 - else echo -n "${repo}/${pkg}" - (( $BE_VERBOSE )) && echo " [ ${dep_chain} ]" || echo '' - fi - done + # query database + Log "searching ...." + mapfile -t dep_chains < <(pactree ${OPTS} --sync --reverse --unique --chain \ + ${dep_pkgname} | sort ) + + # compile results + Log "compiling results for (${#dep_chains[@]}) dependencies ...." + for dep_chain in "${dep_chains[@]}" + do dep_pkg=$(sed 's|.*<- ||' <<<${dep_chain}) + via_pkg=$(sed 's|.*\] <- \([^ ]*\).*|\1|' <<<${dep_chain}) + repos=$(pacman ${OPTS} -Si ${dep_pkg} | grep Repository | cut -d ':' -f 2 | tr -d ' ') + + for repo in ${repos} + do if IsArchRepo ${repo} + then Ignored+=( "${repo}/${dep_pkg}" ) + else Dependents+=( "${repo}/${dep_pkg} ${dep_chain}" ) + HiorderDependents[${via_pkg}]=$(( ${HiorderDependents[${via_pkg}]} + 1 )) + fi + done done } +PrintReport() +{ + local dep_chain is_hiorder_dep via_pkg repo_pkg + declare -i n_hiorder_deps + + echo + for dep_chain in "${Dependents[@]}" + do if (( BE_VERBOSE )) + then echo "${dep_chain/ /${SEP_CHAR}}" + else is_hiorder_dep=$( (( $(tr '<' '\n' <<<${dep_chain} | wc -l) > 2 )) && echo 1 || echo 0 ) + + if ! (( is_hiorder_dep )) + then via_pkg=$(sed 's|.*\] <- \([^ ]*\).*|\1|' <<<${dep_chain}) + repo_pkg=${dep_chain/ *} + n_hiorder_deps=$(( ${HiorderDependents[${via_pkg}]} - 1 )) + echo "${repo_pkg}${SEP_CHAR}(${n_hiorder_deps} higher-order deps)" + fi + fi + done | column --table --separator="${SEP_CHAR}" --table-wrap=2 + + echo + if (( BE_VERBOSE && ${#Ignored[@]} )) + then printf "%s${SEP_CHAR}(ignored)\n" "${Ignored[@]}" | column --table --separator="${SEP_CHAR}" + else echo "(${#Ignored[@]} ignored)" + fi +} + Cleanup() { if [[ -d "${DB_DIR}" && "${DB_DIR}" =~ parabola-dependents ]] @@ -128,10 +176,11 @@ trap 'LogError "${BASH_SOURCE[0]}" "${FUNCNAME[0]}" "${LINENO}"' ERR (( $BE_VERBOSE )) && shift || true -(( ! EUID )) || ! echo -e "${UNPRIVILEGED_MSG}" || false -(( $# )) || ! echo -e "${INVALID_ARG_MSG}" || false +(( ! EUID )) || ! echo -e "${UNPRIVILEGED_MSG}" || exit 1 +(( $# )) || ! echo -e "${INVALID_ARG_MSG}" || exit 1 -Init $1 -ListParabolaDependents $1 -Cleanup +LANG=C +Init $1 +CollectResults $1 +PrintReport -- cgit v1.2.2