Merge pull request #2857 from flatcar/krnowak/pkg-auto-cache

pkg-auto: Add parsing of md5-metadata to aid report generation
This commit is contained in:
Krzesimir Nowak 2025-04-29 14:53:53 +02:00 committed by GitHub
commit f251c126d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 4045 additions and 657 deletions

View File

@ -1,2 +1,12 @@
# ignoring SC2034 (VARIABLE_NAME appears unused), too many false
# positives
#
# ignoring SC2178 (Variable was used as an array but is now assigned a
# string.) - buggy for local variables, happens very often for
# references
SHELLCHECK_OPTS := -e SC2034 -e SC2178
all: shellcheck
shellcheck:
docker run --rm -v "$$PWD:/mnt" koalaman/shellcheck:latest --norc --shell=bash --source-path=SCRIPTDIR --source-path=SCRIPTDIR/impl --external-sources --check-sourced *.sh impl/*.sh
docker run --rm -v "$$PWD:/mnt" koalaman/shellcheck:latest --norc --shell=bash --source-path=SCRIPTDIR --source-path=SCRIPTDIR/impl --source-path=SCRIPTDIR/impl/for-shellcheck --external-sources --check-sourced $(SHELLCHECK_OPTS) *.sh impl/*.sh

View File

@ -148,9 +148,9 @@ function download() {
}
if [[ -n ${SCRIPTS} ]]; then
# shellcheck disable=SC1091 # sourcing generated file
# shellcheck source=for-shellcheck/version.txt
VERSION_ID=$(source "${SCRIPTS}/sdk_container/.repo/manifests/version.txt"; printf '%s' "${FLATCAR_VERSION_ID}")
# shellcheck disable=SC1091 # sourcing generated file
# shellcheck source=for-shellcheck/version.txt
BUILD_ID=$(source "${SCRIPTS}/sdk_container/.repo/manifests/version.txt"; printf '%s' "${FLATCAR_BUILD_ID}")
fi
@ -159,19 +159,16 @@ ver_dash="${VERSION_ID}${BUILD_ID:+-}${BUILD_ID}"
exts=(zst bz2 gz)
# shellcheck disable=SC2034 # used indirectly as cmds_name and cmds
zst_cmds=(
zstd
)
# shellcheck disable=SC2034 # used indirectly as cmds_name and cmds
bz2_cmds=(
lbunzip2
pbunzip2
bunzip2
)
# shellcheck disable=SC2034 # used indirectly as cmds_name and cmds
gz_cmds=(
unpigz
gunzip

View File

@ -9,9 +9,8 @@ set -euo pipefail
## -a: aux directory
## -d: debug package - list many times
## -h: this help
## -i: SDK image override in form of ${arch}:${name}, the name part
## should be a valid docker image with an optional tag
## -ip: add SDK image overrides using flatcar-packages images
## -i: override SDK image, it should be a valid docker image with an
## optional tag
## -n: new base
## -o: old base
## -r: reports directory
@ -27,24 +26,19 @@ set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/impl/util.sh"
source "${PKG_AUTO_IMPL_DIR}/cleanups.sh"
# shellcheck disable=SC2034 # used by name below
gc_aux_directory=''
# shellcheck disable=SC2034 # used by name below
gc_new_base=''
# shellcheck disable=SC2034 # used by name below
gc_old_base=''
# shellcheck disable=SC2034 # used by name below
gc_reports_directory=''
# shellcheck disable=SC2034 # used by name below
gc_scripts_directory=''
# shellcheck disable=SC2034 # used by name below
gc_cleanup_opts=''
# gc_${arch}_sdk_img are declared on demand
gc_image_override=''
gc_debug_packages=()
declare -A opt_map
opt_map=(
['-a']=gc_aux_directory
['-i']=gc_image_override
['-n']=gc_new_base
['-o']=gc_old_base
['-r']=gc_reports_directory
@ -68,36 +62,6 @@ while [[ ${#} -gt 0 ]]; do
print_help
exit 0
;;
-i)
if [[ -z ${2:-} ]]; then
fail 'missing value for -i'
fi
arch=${2%%:*}
image_name=${2#*:}
var_name="gc_${arch}_sdk_img"
unset arch
# shellcheck disable=SC2178 # shellcheck does not grok refs
declare -n ref="${var_name}"
unset var_name
# shellcheck disable=SC2178 # shellcheck does not grok refs
ref=${image_name}
unset image_name
unset -n ref
shift 2
;;
-ip)
for arch in "${gc_arches[@]}"; do
var_name="gc_${arch}_sdk_img"
# shellcheck disable=SC2178 # shellcheck does not grok refs
declare -n ref="${var_name}"
unset var_name
# shellcheck disable=SC2178 # shellcheck does not grok refs
ref="flatcar-packages-${arch}"
unset -n ref
done
unset arch
shift
;;
--)
shift
break
@ -110,9 +74,7 @@ while [[ ${#} -gt 0 ]]; do
if [[ -z ${2:-} ]]; then
fail 'missing value for -w'
fi
# shellcheck disable=SC2178 # shellcheck does not grok refs
declare -n ref="${var_name}"
# shellcheck disable=SC2178 # shellcheck does not grok refs
ref=${2}
unset -n ref
unset var_name
@ -134,15 +96,10 @@ pairs=(
'old-base' gc_old_base
'new-base' gc_new_base
'cleanups' gc_cleanup_opts
'sdk-image-override' gc_image_override
'debug-packages' gc_debug_packages_csv
)
for arch in "${gc_arches[@]}"; do
pairs+=( "${arch}-sdk-img" "gc_${arch}_sdk_img" )
done
pairs+=( 'debug-packages' gc_debug_packages_csv )
if [[ ${#} -ne 1 ]]; then
fail 'expected one positional parameters: a path for the config'
fi
@ -157,7 +114,6 @@ config=${1}; shift
name=${pairs["${name_idx}"]}
opt_idx=$((opt_idx + 2))
name_idx=$((name_idx + 2))
# shellcheck disable=SC2178 # shellcheck does not grok refs
declare -n ref="${name}"
if [[ -n ${ref:-} ]]; then
printf '%s: %s\n' "${opt}" "${ref}"

190
pkg_auto/impl/debug.sh Normal file
View File

@ -0,0 +1,190 @@
#!/bin/bash
if [[ -z ${__DEBUG_SH_INCLUDED__:-} ]]; then
__DEBUG_SH_INCLUDED__=x
source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
# Adds package names for which debugging output may be enabled.
function pkg_debug_add() {
if [[ ${#} -eq 0 ]]; then
return
fi
if ! declare -p __D_DEBUG_PACKAGES >/dev/null 2>&1; then
declare -gA __D_DEBUG_PACKAGES=()
fi
local pkg
for pkg; do
__D_DEBUG_PACKAGES["${pkg}"]=x
done
}
# Resets debugging state to zero (no packages to debug, debug output
# disabled).
function pkg_debug_reset() {
unset __D_DEBUG_PACKAGES __D_DEBUG
}
# Enables debugging output when specific packages are processed.
#
# Params:
#
# @ - package names to enable debugging for
function pkg_debug_enable() {
local -A pkg_set=()
local -a vals=()
local pkg
if ! declare -p __D_DEBUG_PACKAGES >/dev/null 2>&1; then
return 0
fi
for pkg; do
if [[ -n ${pkg_set["${pkg}"]:-} ]]; then
continue
fi
pkg_set["${pkg}"]=x
if [[ -n ${__D_DEBUG_PACKAGES["${pkg}"]:-} ]]; then
vals+=( "${pkg}" )
fi
done
if [[ ${#vals[@]} -gt 0 ]]; then
declare -g __D_DEBUG
join_by __D_DEBUG ',' "${vals[@]}"
fi
}
# Get a list of package names for which debugging output may be
# enabled.
function pkg_debug_packages() {
local -n pkg_names_ref=${1}; shift
if ! declare -p __D_DEBUG_PACKAGES >/dev/null 2>&1; then
pkg_names_ref=()
else
pkg_names_ref=( "${!__D_DEBUG_PACKAGES[@]}" )
fi
}
# Checks if debugging output is enabled. Returns true if yes,
# otherwise false.
function pkg_debug_enabled() {
local -i ret=0
[[ -n ${__D_DEBUG:-} ]] || ret=1
return ${ret}
}
# Disables debugging output.
function pkg_debug_disable() {
unset __D_DEBUG
}
# Prints passed parameters if debugging is enabled.
#
# Params:
#
# @ - parameters to print
function pkg_debug() {
if [[ -n ${__D_DEBUG:-} ]]; then
pkg_debug_print_c "${__D_DEBUG}" "${@}"
fi
}
# Prints passed lines if debugging is enabled.
#
# Params:
#
# @ - lines to print
function pkg_debug_lines() {
if [[ -n ${__D_DEBUG:-} ]]; then
pkg_debug_print_lines_c "${__D_DEBUG}" "${@}"
fi
}
# Prints passed parameters unconditionally with debug
# formatting. Useful for more complicated debugging logic using
# pkg_debug_enabled.
#
# if pkg_debug_enabled; then
# pkg_debug_print 'debug message'
# fi
#
# Params:
#
# @ - parameters to print
function pkg_debug_print() {
if [[ -z ${__D_DEBUG:+notempty} ]]; then
info "bad use of pkg_debug_print, __D_DEBUG is unset"
debug_stacktrace
fail '<print failwhale here>'
fi
pkg_debug_print_c "${__D_DEBUG}" "${@}"
}
# Prints passed lines unconditionally with debug formatting. Useful
# for more complicated debugging logic using pkg_debug_enabled.
#
# if pkg_debug_enabled; then
# pkg_debug_print_lines 'debug' 'message'
# fi
#
# Params:
#
# @ - lines to print
function pkg_debug_print_lines() {
if [[ -z ${__D_DEBUG:+notempty} ]]; then
info "bad use of pkg_debug_print_lines, __D_DEBUG is unset"
debug_stacktrace
fail '<print failwhale here>'
fi
pkg_debug_print_lines_c "${__D_DEBUG}" "${@}"
}
# Prints passed parameters unconditionally with custom debug
# formatting. Useful for either more complicated debugging logic using
# pkg_debug_packages or for non-package-specific debugging situations.
#
# local -a dpkgs=()
# pkg_debug_packages dpkgs
# local pkg
# for pkg in "${dpkgs[@]}"; do pkg_debug_print_c "${pkg}" 'debug message'
#
# Params:
#
# 1 - comma-separated package names
# @ - parameters to print
function pkg_debug_print_c() {
local d_debug=${1}
info "DEBUG(${d_debug}): ${*}"
}
# Prints passed lines unconditionally with custom debug formatting.
# Useful for either more complicated debugging logic using
# pkg_debug_packages or for non-package-specific debugging situations.
#
# local -a dpkgs=() lines=( 'debug' 'message; )
# pkg_debug_packages dpkgs
# local pkg
# for pkg in "${dpkgs[@]}"; do pkg_debug_print_lines_c "${pkg}" "${lines[@]}"
#
# Params:
#
# 1 - comma-separated package names
# @ - lines to print
function pkg_debug_print_lines_c() {
local d_debug=${1}
info_lines "${@/#/"DEBUG(${d_debug}): "}"
}
# Prints current stacktrace.
function debug_stacktrace() {
local -i idx=0 last_idx=${#FUNCNAME[@]}
((last_idx--))
while [[ idx -lt last_idx ]]; do
info "at ${FUNCNAME[idx]}, invoked by ${FUNCNAME[$((idx + 1))]} in ${BASH_SOURCE[idx + 1]}:${BASH_LINENO[idx]}"
((++idx))
done
}
fi

View File

@ -0,0 +1,2 @@
Shellcheck is being pointed here when processing source bash
directives for generated files.

View File

@ -0,0 +1,68 @@
local -a GIT_ENV_VARS ARCHES WHICH REPORTS
local SDK_PKGS BOARD_PKGS
local SYNC_SCRIPT PKG_LIST_SORT_SCRIPT
GIT_ENV_VARS=(
GIT_{AUTHOR,COMMITTER}_{NAME,EMAIL}
)
SYNC_SCRIPT='/path/to/sync_with_gentoo.sh'
PKG_LIST_SORT_SCRIPT='/path/to/sort_packages_list.py'
ARCHES=( 'amd64' 'arm64' )
WHICH=('old' 'new')
SDK_PKGS='sdk-pkgs'
BOARD_PKGS='board-pkgs'
REPORTS=( "${SDK_PKGS}" "${BOARD_PKGS}" )
local SCRIPTS OLD_STATE NEW_STATE OLD_STATE_BRANCH NEW_STATE_BRANCH
local PORTAGE_STABLE_SUFFIX OLD_PORTAGE_STABLE NEW_PORTAGE_STABLE REPORTS_DIR
local NEW_STATE_PACKAGES_LIST AUX_DIR
local COREOS_OVERLAY_SUFFIX OLD_COREOS_OVERLAY NEW_COREOS_OVERLAY
SCRIPTS='/path/to/scripts'
OLD_STATE='/path/to/old_state'
NEW_STATE='/path/to/new_state'
OLD_STATE_BRANCH='old-state'
NEW_STATE_BRANCH='new-state'
PORTAGE_STABLE_SUFFIX='sdk_container/src/third_party/portage-stable'
OLD_PORTAGE_STABLE='/path/to/old_state/portage-stable'
NEW_PORTAGE_STABLE='/path/to/new_state/portage-stable'
REPORTS_DIR='/path/to/reports'
COREOS_OVERLAY_SUFFIX='sdk_container/src/third_party/coreos-overlay'
OLD_COREOS_OVERLAY='/path/to/old_state/coreos-overlay'
NEW_COREOS_OVERLAY='/path/to/new_state/coreos-overlay'
NEW_STATE_PACKAGES_LIST="${NEW_STATE}/.github/workflows/portage-stable-packages-list"
AUX_DIR='/path/to/aux'
local 'SDK_IMAGE'
SDK_IMAGE='ghcr.io/flatcar/flatcar-sdk-all:1234.5.6-build-tag'
local -A LISTING_KINDS
LISTING_KINDS=(
['akamai']='oem-akamai_packages.txt'
['ami']='oem-ami_packages.txt'
['azure']='oem-azure_packages.txt'
['containerd']='containerd-flatcar_packages.txt'
['dev']='flatcar_developer_container_packages.txt'
['digitalocean']='oem-digitalocean_packages.txt'
['docker']='docker-flatcar_packages.txt'
['gce']='oem-gce_packages.txt'
['hetzner']='oem-hetzner_packages.txt'
['kubevirt']='oem-kubevirt_packages.txt'
['openstack']='oem-openstack_packages.txt'
['packet']='oem-packet_packages.txt'
['prod']='flatcar_production_image_packages.txt'
['proxmoxve']='oem-proxmoxve_packages.txt'
['qemu']='oem-qemu_packages.txt'
['scaleway']='oem-scaleway_packages.txt'
['sysext-podman']='flatcar-podman_packages.txt'
['sysext-python']='flatcar-python_packages.txt'
['sysext-zfs']='flatcar-zfs_packages.txt'
['vmware']='oem-vmware_packages.txt'
)

View File

@ -0,0 +1,4 @@
FLATCAR_VERSION=1234.5.6+build-tag
FLATCAR_VERSION_ID=1234.5.6
FLATCAR_BUILD_ID="build-tag"
FLATCAR_SDK_VERSION=1234.5.6+build-tag

View File

@ -12,7 +12,10 @@ __GENTOO_VER_SH_INCLUDED__=x
source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
VER_ERE="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$"
VER_ERE_UNBOUNDED="([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?"
VER_ERE='^'"${VER_ERE_UNBOUNDED}"'$'
PKG_ERE_UNBOUNDED="[A-Za-z0-9_][A-Za-z0-9+_.-]*/[A-Za-z0-9_][A-Za-z0-9+_-]*"
# @FUNCTION: _ver_compare_int
# @USAGE: <a> <b>

View File

@ -97,77 +97,23 @@ function package_info_for_board() {
# 1 - directory path
function set_eo() {
local dir=${1}; shift
# rest are architectures
SDK_EO="${dir}/sdk-emerge-output"
BOARD_EO="${dir}/board-emerge-output"
# shellcheck disable=SC2034 # used indirectly in cat_eo_f
SDK_EO_F="${SDK_EO}-filtered"
# shellcheck disable=SC2034 # used indirectly in cat_eo_f
BOARD_EO_F="${BOARD_EO}-filtered"
# shellcheck disable=SC2034 # used indirectly in cat_eo_w
SDK_EO_W="${SDK_EO}-warnings"
# shellcheck disable=SC2034 # used indirectly in cat_eo_w
BOARD_EO_W="${BOARD_EO}-warnings"
}
declare -g EGENCACHE_W="${dir}/egencache-warnings"
declare -g SDK_EO="${dir}/sdk-emerge-output"
declare -g SDK_EO_F="${SDK_EO}-filtered"
declare -g SDK_EO_W="${SDK_EO}-warnings"
declare -g SDK_EO_J="${SDK_EO}-junk"
# Print the contents of file, path of which is stored in a variable of
# a given name.
#
# Params:
#
# 1 - name of the variable
function cat_var() {
local var_name
var_name=${1}; shift
local -n ref="${var_name}"
if [[ -z "${ref+isset}" ]]; then
fail "${var_name} unset"
fi
if [[ ! -e "${ref}" ]]; then
fail "${ref} does not exist"
fi
cat "${ref}"
}
# Print contents of the emerge output of a given kind. Kind can be
# either either sdk or board.
#
# Params:
#
# 1 - kind
function cat_eo() {
local kind
kind=${1}; shift
cat_var "${kind^^}_EO"
}
# Print contents of the filtered emerge output of a given kind. Kind
# can be either either sdk or board. The filtered emerge output
# contains only lines with package information.
#
# Params:
#
# 1 - kind
function cat_eo_f() {
local kind
kind=${1}; shift
cat_var "${kind^^}_EO_F"
}
# Print contents of a file that stores warnings that were printed by
# emerge. The warnings are specific to a kind (sdk or board).
#
# Params:
#
# 1 - kind
function cat_eo_w() {
local kind
kind=${1}; shift
cat_var "${kind^^}_EO_W"
local arch
local board_eo
for arch; do
board_eo=${dir}/${arch}-board-emerge-output
declare -g "${arch^^}_BOARD_EO=${board_eo}"
declare -g "${arch^^}_BOARD_EO_F=${board_eo}-filtered"
declare -g "${arch^^}_BOARD_EO_W=${board_eo}-warnings"
declare -g "${arch^^}_BOARD_EO_J=${board_eo}-junk"
done
}
# JSON output would be more verbose, but probably would not require
@ -193,7 +139,7 @@ FULL_LINE_RE='^'"${STATUS_RE}${SPACES_RE}${PACKAGE_NAME_RE}"'\('"${SPACES_RE}${V
# Filters sdk reports to get the package information.
function filter_sdk_eo() {
cat_eo sdk | xgrep -e "${FULL_LINE_RE}"
cat "${SDK_EO}" | xgrep -e "${FULL_LINE_RE}"
}
# Filters board reports for a given arch to get the package
@ -203,11 +149,12 @@ function filter_sdk_eo() {
#
# 1 - architecture
function filter_board_eo() {
local arch
local arch name
arch=${1}; shift
name=${arch^^}_BOARD_EO
# Replace ${arch}-usr in the output with a generic word BOARD.
cat_eo board | \
cat "${!name}" | \
xgrep -e "${FULL_LINE_RE}" | \
sed -e "s#/build/${arch}-usr/#/build/BOARD/#"
}
@ -215,13 +162,17 @@ function filter_board_eo() {
# Filters sdk reports to get anything but the package information
# (i.e. junk).
function junk_sdk_eo() {
cat_eo sdk | xgrep -v -e "${FULL_LINE_RE}"
cat "${SDK_EO}" | xgrep -v -e "${FULL_LINE_RE}"
}
# Filters board reports to get anything but the package information
# (i.e. junk).
function junk_board_eo() {
cat_eo board | xgrep -v -e "${FULL_LINE_RE}"
local arch name
arch=${1}; shift
name=${arch^^}_BOARD_EO
cat "${!name}" | xgrep -v -e "${FULL_LINE_RE}"
}
# More regexp-like abominations follow.
@ -274,21 +225,6 @@ PKG_REPO_SED_FILTERS=(
-e "s/^${STATUS_RE}${SPACES_RE}\(${PACKAGE_NAME_RE}\)${SPACES_RE}${VER_SLOT_REPO_RE}${SPACES_RE}.*/\1 \3/"
)
# Applies some sed filter over the emerge output of a given kind.
# Results are printed.
#
# Params:
#
# 1 - kind (sdk or board)
# @ - parameters passed to sed
function sed_eo_and_sort() {
local kind
kind=${1}; shift
# rest goes to sed
cat_eo_f "${kind}" | sed "${@}" | sort
}
# Applies some sed filter over the SDK emerge output. Results are
# printed.
#
@ -296,9 +232,7 @@ function sed_eo_and_sort() {
#
# @ - parameters passed to sed
function packages_for_sdk() {
# args are passed to sed_eo_and_sort
sed_eo_and_sort sdk "${@}"
cat "${SDK_EO_F}" | sed "${@}" | sort
}
# Applies some sed filter over the board emerge output. Results are
@ -308,9 +242,12 @@ function packages_for_sdk() {
#
# @ - parameters passed to sed
function packages_for_board() {
# args are passed to sed_eo_and_sort
local arch=${1}; shift
# rest goes to sed
sed_eo_and_sort board "${@}"
local name=${arch^^}_BOARD_EO_F
sed "${@}" "${!name}" | sort
}
# Prints package name, slot and version information for SDK.
@ -334,24 +271,26 @@ function versions_sdk_with_key_values() {
# Prints package name, slot and version information for board.
function versions_board() {
local arch=${1}; shift
local -a sed_opts
sed_opts=(
-e '/to \/build\/BOARD\// ! d'
"${PKG_VER_SLOT_SED_FILTERS[@]}"
)
packages_for_board "${sed_opts[@]}"
packages_for_board "${arch}" "${sed_opts[@]}"
}
# Prints package name, slot, version and key-values information for
# build dependencies of board. Key-values may be something like
# USE="foo bar -baz".
function board_bdeps() {
local arch=${1}; shift
local -a sed_opts
sed_opts=(
-e '/to \/build\/BOARD\// d'
"${PKG_VER_SLOT_KV_SED_FILTERS[@]}"
)
packages_for_board "${sed_opts[@]}"
packages_for_board "${arch}" "${sed_opts[@]}"
}
# Print package name and source repository names information for SDK.
@ -366,24 +305,29 @@ function package_sources_sdk() {
# Print package name and source repository names information for
# board.
function package_sources_board() {
local arch=${1}; shift
local -a sed_opts
sed_opts=(
"${PKG_REPO_SED_FILTERS[@]}"
)
packages_for_board "${sed_opts[@]}"
packages_for_board "${arch}" "${sed_opts[@]}"
}
# Checks if no errors were produced by emerge when generating
# reports. It is assumed that emerge will print a line with "ERROR" in
# it to denote a failure.
function ensure_no_errors() {
local kind
local -a files=( "${SDK_EO_W}" )
local arch name
for kind in sdk board; do
if cat_eo_w "${kind}" | grep --quiet --fixed-strings 'ERROR'; then
fail "there are errors in emerge output warnings files"
fi
for arch; do
name=${arch^^}_BOARD_EO_W
files+=( "${!name}" )
done
if grep --quiet --fixed-strings 'ERROR' "${files[@]}"; then
fail "there are errors in emerge output warnings files"
fi
}
# Stores a path to a package.provided file inside the given root
@ -400,7 +344,6 @@ function get_provided_file() {
path_var_name=${1}; shift
local -n path_ref="${path_var_name}"
# shellcheck disable=SC2034 # reference to external variable
path_ref="${root}/etc/portage/profile/package.provided/ignore_cross_packages"
}
@ -458,10 +401,17 @@ function revert_crossdev_stuff() {
# Checks if the expected reports were generated by emerge.
function ensure_valid_reports() {
local kind var_name
for kind in sdk board; do
var_name="${kind^^}_EO_F"
if [[ ! -s ${!var_name} ]]; then
local -a files=( "${SDK_EO_F}" )
local arch name
for arch; do
name=${arch^^}_BOARD_EO_F
files+=( "${!name}" )
done
local file
for file in "${files[@]}"; do
if [[ ! -s ${file} ]]; then
fail "report files are missing or are empty"
fi
done
@ -484,4 +434,37 @@ function clean_empty_warning_files() {
done
}
function get_num_proc() {
local -n num_proc_ref=${1}; shift
local -i num_proc=1 rv=1
# stolen from portage
[[ rv -eq 0 ]] || { rv=0; num_proc=$(getconf _NPROCESSORS_ONLN 2>/dev/null) || rv=1; }
[[ rv -eq 0 ]] || { rv=0; num_proc=$(sysctl -n hw.ncpu 2>/dev/null) || rv=1; }
# stolen from common.sh
[[ rv -eq 0 ]] || { rv=0; num_proc=$(grep -c "^processor" /proc/cpuinfo 2>/dev/null) || rv=1; }
[[ rv -eq 0 ]] || { rv=0; num_proc=1; }
num_proc_ref=${num_proc}
}
function generate_cache_for() {
local repo=${1}; shift
local -i gcf_num_proc
local load_avg
get_num_proc gcf_num_proc
load_avg=$(bc <<< "${gcf_num_proc} * 0.75")
egencache --repo "${repo}" --jobs="${gcf_num_proc}" --load-average="${load_avg}" --update
}
function copy_cache_to_reports() {
local repo=${1}; shift
local reports_dir=${1}; shift
local repo_dir
repo_dir=$(portageq get_repo_path / "${repo}")
cp -a "${repo_dir}/metadata/md5-cache" "${reports_dir}/${repo}-cache"
}
fi

375
pkg_auto/impl/lcs.sh Normal file
View File

@ -0,0 +1,375 @@
#!/bin/bash
# Implementation of longest common subsequence (LCS) algorithm, with
# memoization and scoring. The algorithm is a base of utilities like
# diff - it finds the common items in two sequences.
#
# The memoization part is about remembering the results of LCS
# computation for shorter sequences, so they can be reused when doing
# computation for longer sequences.
#
# The scoring part is about generalization of the comparison function,
# which normally would return a boolean value describing whether two
# items are equal or not. With scoring, two things change. First is
# that the returned value from the comparison/scoring function is not
# a boolean, but rather an integer describing the degree of equality
# of the items. And second is that with booleans, the winning
# subsequence was the longest one, but with scores is not necessarily
# the longest one, but with the highest total score. This changes the
# algorithm a bit. While the typical LCS algorithm goes like as
# follows (s1 and s2 are sequences, i1 and i2 are indices in their
# respective sequences):
#
#
#
# LCS(s1, s2, i1, i2) -> sequence:
# if (i1 >= len(s1) || i2 >= len(s2)): return ()
# if (s1[i1] == s2[i2]):
# l = LCS(s1, s2, i1 + 1, i2 + 1)
# return (s1[i1], l...)
# else:
# l1 = LCS(s1, s2, i1 + 1, i2)
# l2 = LCS(s1, s2, i1, i2 + 1)
# if (len(l1) > len(l2)): return l1
# return l2
#
#
#
# The score LCS goes more or less like this:
#
#
#
# SLCS(s1, s2, i1, i2) -> tuple(score, sequence):
# if (i1 >= len(s1) || i2 >= len(21)): return (score: 0, sequence: ())
# score = score_func(s1[i1], s2[i2])
# if (score == max_score):
# # matches the "equal" case in LCS above
# l = SLCS(s1, s2, i1 + 1, i2 + 1)
# return (score: score + l.score, sequence: (s1[i1], l.sequence...)
# else if (score == 0):
# # matches the "not equal" case in LCS above
# l1 = SLCS(s1, s2, i1 + 1, i2)
# l2 = SLCS(s1, s2, i1, i2 + 1)
# if (l1.score > l2.score): return l1
# return l2
# else:
# # new "equal, but not quite" case
# l = SLCS(s1, s2, i1 + 1, i2 + 1)
# l.score = score + l.score
# l.sequence = (s1[i1], l.sequence...)
# l1 = SLCS(s1, s2, i1 + 1, i2)
# l2 = SLCS(s1, s2, i1, i2 + 1)
# return tuple_with_max_score(l, l1, l2)
#
#
#
# The difference in the implementation below is that instead of
# starting at index 0 and go up for each sequence, we start at max
# index and go down.
if [[ -z ${__LCS_SH_INCLUDED__:-} ]]; then
__LCS_SH_INCLUDED__=x
source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
# Constants to use for accessing fields in common items.
declare -gri LCS_X1_IDX=0 LCS_X2_IDX=1 LCS_IDX1_IDX=2 LCS_IDX2_IDX=3
# Computes the longest common subsequence of two sequences and stores
# it in the passed array. The common items stored in the array with
# longest common subsequence are actually names of arrays, where each
# array stores an item from the first sequence, an item from the
# second sequence, an index of the first item in first sequence and an
# index of the second item in the second sequence. To access those
# fields, use the LCS_*_IDX constants.
#
# The function optionally takes a name of the score function. If no
# such function is passed, the simple string score function is used
# (gives score 1 if strings are equal, otherwise gives score 0). The
# function should take either one or three parameters. The first
# parameter is always a name of a score integer variable. If only one
# parameter is passed, the function should write the maximum score to
# the score variable. When three parameters are passed, then the
# second and third are items from the sequences passed to lcs_run and
# they should be compared and rated. The function should rate the
# items with zero if they are completely different, with max score if
# they are the same, and with something in between zero and max score
# if they are somewhat equal but not really.
#
# Params:
#
# 1 - a name of an array variable containing the first sequence
# 2 - a name of an array variable containing the second sequence
# 3 - a name of an array variable where the longest common subsequence
# will be stored
# 4 - optional, a name of a score function
#
# Example:
#
# a=( A B C D E F G )
# b=( B C D G K )
# c=()
#
# lcs_run a b c
#
# echo "a: ${a[*]}"
# echo "b: ${b[*]}"
#
# cn=()
# for i in "${c[@]}"; do
# declare -n ref=${i}
# n=${ref[LCS_X1_IDX]}
# unset -n ref
# cn+=( "${n}" )
# done
# echo "c: ${cn[*]}"
# unset "${c[@]}"
function lcs_run() {
local seq1_name=${1}; shift
local seq2_name=${1}; shift
local common_name=${1}; shift
local score_func=__lcs_str_score
if [[ ${#} -gt 0 ]]; then
score_func=${1}; shift
fi
if ! declare -pF "${score_func}" >/dev/null 2>/dev/null; then
fail "${score_func@Q} is not a function"
fi
local -i lr_max_score
"${score_func}" lr_max_score
# lcs_memo_items_set is a set of common item names; the set owns
# the common items
#
# lcs_memo_map is a mapping from a memo key (which encodes indices
# from both sequences) to a pair, being a score and a name of an
# longest common subsequence for the encoded indices, separated
# with semicolon
local -A lcs_memo_map=() lcs_memo_items_set=()
local -a lr_lcs_state=( "${score_func}" lcs_memo_map lcs_memo_items_set "${seq1_name}" "${seq2_name}" "${lr_max_score}" )
local -n seq1=${seq1_name} seq2=${seq2_name}
local -i idx1=$(( ${#seq1[@]} - 1 )) idx2=$(( ${#seq2[@]} - 1 ))
unset -n seq1 seq2
__lcs_recurse lr_lcs_state "${idx1}" "${idx2}"
local -n common_ref=${common_name}
local lr_memo_key=''
__lcs_make_memo_key "${idx1}" "${idx2}" lr_memo_key
local pair=${lcs_memo_map["${lr_memo_key}"]}
local -n memoized_items_ref=${pair#*:}
common_ref=( "${memoized_items_ref[@]}" )
# steal the items from the items set that are a part of desired
# LCS, so they are not freed now, but later, when the LCS is freed
local item
for item in "${common_ref[@]}"; do
unset "lcs_memo_items_set[${item}]"
done
# free the unneeded items
unset "${!lcs_memo_items_set[@]}"
# free all the LCSes, we already have a copy of the one we wanted
local items_var_name memo_key
for memo_key in "${!lcs_memo_map[@]}"; do
pair=${lcs_memo_map["${memo_key}"]}
items_var_name=${pair#*:}
if [[ ${items_var_name} != EMPTY_ARRAY ]]; then
unset "${items_var_name}"
fi
done
}
##
## Details
##
declare -gri __LCS_SCORE_IDX=0 __LCS_MEMO_MAP_IDX=1 __LCS_MEMO_ITEMS_SET_IDX=2 __LCS_SEQ1_IDX=3 __LCS_SEQ2_IDX=4 __LCS_MAX_SCORE_IDX=5
function __lcs_recurse() {
local lcs_state_name=${1}; shift
local -i i1=${1}; shift
local -i i2=${1}; shift
if [[ i1 -lt 0 || i2 -lt 0 ]]; then
return 0
fi
local -n lcs_state=${lcs_state_name}
local -n memo_map_ref=${lcs_state[__LCS_MEMO_MAP_IDX]}
local memo_key=''
__lcs_make_memo_key ${i1} ${i2} memo_key
local pair=${memo_map_ref["${memo_key}"]:-}
if [[ -n ${pair} ]]; then
return 0
fi
unset pair memo_key
unset -n memo_map_ref
local -n seq1_ref=${lcs_state[__LCS_SEQ1_IDX]}
local -n seq2_ref=${lcs_state[__LCS_SEQ2_IDX]}
local x1=${seq1_ref[i1]}
local x2=${seq2_ref[i2]}
unset -n seq2_ref seq1_ref
local -i lr_diff_score
local score_func=${lcs_state[__LCS_SCORE_IDX]}
"${score_func}" lr_diff_score "${x1}" "${x2}"
unset score_func
local -i max_score=${lcs_state[__LCS_MAX_SCORE_IDX]}
if [[ lr_diff_score -gt max_score ]]; then
lr_diff_score=max_score
fi
if [[ lr_diff_score -lt 0 ]]; then
lr_diff_score=0
fi
if [[ lr_diff_score -eq max_score ]]; then
unset max_score
__lcs_recurse "${lcs_state_name}" $((i1 - 1)) $((i2 - 1))
local n
gen_varname __LCS_COMMON n
declare -a -g "${n}=()"
# retrieve memoized result for i1-1 and i2-1 (what we just
# called above), make a copy of it, add the prepared item and
# memoize that copy for i1 and i2; also add the prepared item
# to the set of prepared items
local -n memo_map_ref=${lcs_state[__LCS_MEMO_MAP_IDX]}
local previous_memo_key
__lcs_make_memo_key $((i1 - 1)) $((i2 - 1)) previous_memo_key
local previous_pair=${memo_map_ref["${previous_memo_key}"]:-'0:EMPTY_ARRAY'}
local previous_score=${previous_pair%%:*}
local -n previous_memoized_prepared_items_ref=${previous_pair#*:}
local -n c_ref=${n}
local prepared_item_to_insert
gen_varname __LCS_PREP prepared_item_to_insert
declare -g -a "${prepared_item_to_insert}=( ${x1@Q} ${x2@Q} ${i1@Q} ${i2@Q} )"
c_ref=( "${previous_memoized_prepared_items_ref[@]}" "${prepared_item_to_insert}" )
local memo_key
__lcs_make_memo_key ${i1} ${i2} memo_key
memo_map_ref["${memo_key}"]="$((lr_diff_score + previous_score)):${n}"
local -n memo_items_set=${lcs_state[__LCS_MEMO_ITEMS_SET_IDX]}
memo_items_set["${prepared_item_to_insert}"]=x
elif [[ lr_diff_score -eq 0 ]]; then
unset max_score
__lcs_recurse "${lcs_state_name}" ${i1} $((i2 - 1))
__lcs_recurse "${lcs_state_name}" $((i1 - 1)) ${i2}
# retrieve memoized results for i1 and i2-1 and for i1-1 and
# i2 (what we just called above), and memoize the longer
# result for i1 and i2
local -n memo_map_ref=${lcs_state[__LCS_MEMO_MAP_IDX]}
local lr_memo_key=''
__lcs_make_memo_key ${i1} $((i2 - 1)) lr_memo_key
local previous_pair1=${memo_map_ref["${lr_memo_key}"]:-'0:EMPTY_ARRAY'}
local -i previous_score1=${previous_pair1%%:*}
__lcs_make_memo_key $((i1 - 1)) ${i2} lr_memo_key
local previous_pair2=${memo_map_ref["${lr_memo_key}"]:-'0:EMPTY_ARRAY'}
local -i previous_score2=${previous_pair2%%:*}
__lcs_make_memo_key ${i1} ${i2} lr_memo_key
if [[ previous_score1 -gt previous_score2 ]]; then
memo_map_ref["${lr_memo_key}"]=${previous_pair1}
else
memo_map_ref["${lr_memo_key}"]=${previous_pair2}
fi
else
unset max_score
# 1
__lcs_recurse "${lcs_state_name}" $((i1 - 1)) $((i2 - 1))
# 2
__lcs_recurse "${lcs_state_name}" ${i1} $((i2 - 1))
# 3
__lcs_recurse "${lcs_state_name}" $((i1 - 1)) ${i2}
local lr_mk1 lr_mk2 lr_mk3
__lcs_make_memo_key $((i1 - 1)) $((i2 - 1)) lr_mk1
__lcs_make_memo_key ${i1} $((i2 - 1)) lr_mk2
__lcs_make_memo_key $((i1 - 1)) ${i2} lr_mk3
local -n memo_map_ref=${lcs_state[__LCS_MEMO_MAP_IDX]}
local pair1=${memo_map_ref["${lr_mk1}"]:-'0:EMPTY_ARRAY'}
local pair2=${memo_map_ref["${lr_mk2}"]:-'0:EMPTY_ARRAY'}
local pair3=${memo_map_ref["${lr_mk3}"]:-'0:EMPTY_ARRAY'}
local -i score1=${pair1%%:*}
local -i score2=${pair2%%:*}
local -i score3=${pair3%%:*}
local -i pick # either 1, 2 or 3
score1=$((score1 + lr_diff_score))
if [[ score1 -gt score2 ]]; then
if [[ score1 -gt score3 ]]; then
pick=1
else
pick=3
fi
elif [[ score2 -gt score3 ]]; then
pick=2
else
pick=3
fi
if [[ pick -eq 1 ]]; then
local lr_new_lcs
gen_varname __LCS_COMMON lr_new_lcs
declare -a -g "${lr_new_lcs}=()"
local -n previous_memoized_prepared_items_ref=${pair1#*:}
local -n c_ref=${lr_new_lcs}
local prepared_item_to_insert
gen_varname __LCS_PREP prepared_item_to_insert
declare -g -a "${prepared_item_to_insert}=( ${x1@Q} ${x2@Q} ${i1@Q} ${i2@Q} )"
c_ref=( "${previous_memoized_prepared_items_ref[@]}" "${prepared_item_to_insert}" )
local lr_memo_key
__lcs_make_memo_key ${i1} ${i2} lr_memo_key
memo_map_ref["${lr_memo_key}"]="${score1}:${lr_new_lcs}"
local -n memo_items_set=${lcs_state[__LCS_MEMO_ITEMS_SET_IDX]}
memo_items_set["${prepared_item_to_insert}"]=x
else
local -n picked_pair="pair${pick}"
local lr_memo_key=''
__lcs_make_memo_key ${i1} ${i2} lr_memo_key
memo_map_ref["${lr_memo_key}"]=${picked_pair}
fi
fi
}
function __lcs_make_memo_key() {
local i1=${1}; shift
local i2=${1}; shift
local -n ref=${1}; shift
local key="x${i1}x${i2}x"
key=${key//-/_}
ref=${key}
}
function __lcs_str_score() {
local -n score_ref=${1}; shift
score_ref=1
[[ ${#} -eq 0 || ${1} = "${2}" ]] || score_ref=0
}
fi

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -133,7 +133,6 @@ function mvm_declare() {
storage_map_ref=()
local -n mvm_ref=${mvm_var_name}
# shellcheck disable=SC2034 # it's a reference to external variable
mvm_ref=(
['name']="${mvm_var_name}"
['constructor']="${constructor}"
@ -193,7 +192,6 @@ function __mvm_mvc_name() {
mvc_name_var_name=${1}; shift
local -n mvc_name_ref=${mvc_name_var_name}
# shellcheck disable=SC2034 # it's a reference to external variable
mvc_name_ref="mvm_${name}_mvc_${counter}"
}
@ -246,10 +244,8 @@ function mvm_c_get_extra() {
local extras_map_var_name
extras_map_var_name=${mvm['extras']}
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n extras_map_ref=${extras_map_var_name}
# shellcheck disable=SC2034 # it's a reference to external variable
extra_ref=${extras_map_ref["${extra}"]:-}
}
@ -273,10 +269,8 @@ function mvm_c_get() {
local storage_map_var_name
storage_map_var_name=${mvm['storage']}
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n storage_map_ref=${storage_map_var_name}
# shellcheck disable=SC2034 # it's a reference to external variable
value_ref=${storage_map_ref["${key}"]:-}
}
@ -290,7 +284,6 @@ function __mvm_c_make_new_mvc() {
name=${mvm['name']}
counter=${mvm['counter']}
storage_map_var_name=${mvm['storage']}
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n storage_map_ref=${storage_map_var_name}
__mvm_mvc_name "${name}" "${counter}" "${mvc_name_var_name}"
@ -348,7 +341,6 @@ function mvm_c_remove() {
local storage_map_var_name
storage_map_var_name=${mvm['storage']}
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n storage_map_ref=${storage_map_var_name}
if [[ -z ${storage_map_ref["${key}"]:-} ]]; then
@ -387,7 +379,6 @@ function mvm_c_iterate() {
local storage_map_var_name helper
storage_map_var_name=${mvm['storage']}
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n storage_map_ref=${storage_map_var_name}
helper=${mvm['iteration_helper']}
@ -467,7 +458,6 @@ function mvm_mvc_array_destructor() {
function mvm_mvc_array_adder() {
local array_var_name
array_var_name=${1}; shift
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n array_ref=${array_var_name}
array_ref+=( "${@}" )
@ -481,7 +471,6 @@ function mvm_mvc_array_iteration_helper() {
callback=${1}; shift
# rest are extra args passed to cb
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n array_ref=${array_var_name}
"${callback}" "${@}" "${key}" "${array_var_name}" "${array_ref[@]}"
}
@ -512,11 +501,9 @@ function mvm_mvc_map_destructor() {
function mvm_mvc_map_adder() {
local map_var_name
map_var_name=${1}; shift
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n map_ref=${map_var_name}
while [[ ${#} -gt 1 ]]; do
# shellcheck disable=SC2034 # it's a reference to external variable
map_ref["${1}"]=${2}
shift 2
done
@ -532,7 +519,6 @@ function mvm_mvc_set_constructor() {
declare -g -A "${set_var_name}"
# shellcheck disable=SC2178 # shellcheck does not grok refs
local -n set_ref=${set_var_name}
set_ref=()
}
@ -548,7 +534,6 @@ function mvm_mvc_set_adder() {
local set_var_name
set_var_name=${1}; shift
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n set_ref=${set_var_name}
while [[ ${#} -gt 0 ]]; do
set_ref["${1}"]=x
@ -565,7 +550,6 @@ function mvm_mvc_set_iteration_helper() {
callback=${1}; shift
# rest are extra args passed to cb
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n set_ref=${set_var_name}
"${callback}" "${@}" "${key}" "${set_var_name}" "${!set_ref[@]}"
}

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,6 @@ function get_repo_from_profile_path() {
path=${1}; shift
local -n repo_dir_ref=${1}; shift
# shellcheck disable=SC2034 # it's a reference to external variable
repo_dir_ref="${path%/profiles/*}"
}
@ -78,7 +77,6 @@ function repo_path_to_name() {
path=${1}; shift
local -n name_ref=${1}; shift
# shellcheck disable=SC2034 # it's a reference to external variable
name_ref=${repo_data_r["${path}"]:-'<unknown>'}
}
@ -138,7 +136,6 @@ function process_profile() {
done <"${parent_file}"
fi
# shellcheck disable=SC2034 # it's a reference to external variable
children_ref=( "${children[@]}" )
}
@ -152,7 +149,6 @@ function get_profile_name() {
repo_path=${repo_data["${repo_name}"]}
profile_name=${profile_path#"${repo_path}/profiles/"}
# shellcheck disable=SC2034 # it's a reference to external variable
profile_name_ref="${profile_name}"
}

View File

@ -3,6 +3,9 @@
if [[ -z ${__UTIL_SH_INCLUDED__:-} ]]; then
__UTIL_SH_INCLUDED__=x
declare -gra EMPTY_ARRAY=()
declare -grA EMPTY_MAP=()
# Works like dirname, but without spawning new processes.
#
# Params:
@ -34,7 +37,6 @@ function dirname_out() {
dir_ref='.'
return 0
fi
# shellcheck disable=SC2034 # it's a reference to external variable
dir_ref=${dn}
}
@ -65,7 +67,6 @@ function basename_out() {
cleaned_up=${cleaned_up//+(\/)/\/}
# keep last component
dn=${cleaned_up##*/}
# shellcheck disable=SC2034 # it's a reference to external variable
base_ref=${dn}
}
@ -83,7 +84,6 @@ THIS=$(realpath "${THIS}")
THIS_DIR=$(realpath "${THIS_DIR}")
dirname_out "${BASH_SOURCE[0]}" PKG_AUTO_IMPL_DIR
PKG_AUTO_IMPL_DIR=$(realpath "${PKG_AUTO_IMPL_DIR}")
# shellcheck disable=SC2034 # may be used by scripts sourcing this file
PKG_AUTO_DIR=$(realpath "${PKG_AUTO_IMPL_DIR}/..")
# Prints an info line.
@ -162,7 +162,6 @@ function join_by() {
printf -v "${output_var_name}" '%s' "${first}" "${@/#/${delimiter}}";
else
local -n output_ref=${output_var_name}
# shellcheck disable=SC2034 # it's a reference to external variable
output_ref=''
fi
}
@ -204,7 +203,6 @@ function strip_out() {
t=${l}
t=${t/#+([[:space:]])}
t=${t/%+([[:space:]])}
# shellcheck disable=SC2034 # it's a reference to external variable
out_ref=${t}
}
@ -214,10 +212,8 @@ function strip_out() {
#
# 1 - name of an array variable, where the architectures will be stored
function get_valid_arches() {
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n arches_ref=${1}; shift
# shellcheck disable=SC2034 # it's a reference to external variable
arches_ref=( 'amd64' 'arm64' )
}
@ -232,7 +228,6 @@ function get_valid_arches() {
# 2 - separator string
# @ - strings
function all_pairs() {
# shellcheck disable=SC2178 # shellcheck doesn't grok references to arrays
local -n pairs_ref=${1}; shift
local sep=${1}; shift
@ -250,4 +245,92 @@ function all_pairs() {
done
}
# Does the set operation on two passed sets - both set differences and
# an intersection.
#
# Params:
#
# 1 - name of the first set variable
# 2 - name of the second set variable
# 3 - name of the set variable that will contain elements that exist
# in first set, but not the second
# 4 - name of the set variable that will contain elements that exist
# in second set, but not the first
# 5 - name of the set variable that will contain elements that exist
# in both first and second sets
function sets_split() {
local -n first_set_ref=${1}; shift
local -n second_set_ref=${1}; shift
local -n only_in_first_set_ref=${1}; shift
local -n only_in_second_set_ref=${1}; shift
local -n common_set_ref=${1}; shift
only_in_first_set_ref=()
only_in_second_set_ref=()
common_set_ref=()
local item mark
for item in "${!first_set_ref[@]}"; do
mark=${second_set_ref["${item}"]:-}
if [[ -z ${mark} ]]; then
only_in_first_set_ref["${item}"]=x
else
common_set_ref["${item}"]=x
fi
done
for item in "${!second_set_ref[@]}"; do
mark=${first_set_ref["${item}"]:-}
if [[ -z ${mark} ]]; then
only_in_second_set_ref["${item}"]=x
fi
done
}
declare -gi __UTIL_SH_COUNTER=0
# Generates a globally unique name for a variable. Can be given a
# prefix to override the default __PA_VAR one.
#
# Params:
#
# (optional) a prefix
# 1 - name of a variable, where the generated name will be stored
function gen_varname() {
local prefix='__PA_VAR' # pa = pkg-auto
if [[ ${#} -gt 1 ]]; then
# we passed a prefix
prefix=${1}; shift
fi
local -n name_ref=${1}; shift
name_ref="${prefix}_${__UTIL_SH_COUNTER}"
__UTIL_SH_COUNTER=$((__UTIL_SH_COUNTER + 1))
}
# Declares variables with a given initializer.
#
# Params:
#
# @: flags passed to declare, followed by variable names, followed by
# an initializer
function struct_declare() {
local -a args=()
while [[ $# -gt 0 ]]; do
if [[ ${1} != -* ]]; then
break
fi
args+=( "${1}" )
shift
done
if [[ ${#} -lt 2 ]]; then
fail "bad use of struct_declare"
fi
local definition=${*: -1}
set -- "${@:1:$((${#} - 1))}"
set -- "${@/%/=${definition}}"
declare "${args[@]}" "${@}"
}
fi

View File

@ -1,33 +1,34 @@
#!/bin/bash
##
## Gathers information about SDK and board packages. Also collects
## info about actual build deps of board packages, which may be useful
## for verifying if SDK provides those.
## Gathers information about SDK packages and board packages for each
## passed architecture. Also collects info about actual build deps of
## board packages, which may be useful for verifying if SDK provides
## those.
##
## Reports generated:
## sdk-pkgs - contains package information for SDK
## sdk-pkgs-kv - contains package information with key values (USE, PYTHON_TARGETS, CPU_FLAGS_X86) for SDK
## board-pkgs - contains package information for board for chosen architecture
## board-bdeps - contains package information with key values (USE, PYTHON_TARGETS, CPU_FLAGS_X86) of board build dependencies
## ${arch}-board-pkgs - contains package information for board for chosen architecture
## ${arch}-board-bdeps - contains package information with key values (USE, PYTHON_TARGETS, CPU_FLAGS_X86) of board build dependencies
## sdk-profiles - contains a list of profiles used by the SDK, in evaluation order
## board-profiles - contains a list of profiles used by the board for the chosen architecture, in evaluation order
## ${arch}-board-profiles - contains a list of profiles used by the board for the chosen architecture, in evaluation order
## sdk-package-repos - contains package information with their repos for SDK
## board-package-repos - contains package information with their repos for board
## ${arch}-board-package-repos - contains package information with their repos for board
## sdk-emerge-output - contains raw emerge output for SDK being a base for other reports
## board-emerge-output - contains raw emerge output for board being a base for other reports
## ${arch}-board-emerge-output - contains raw emerge output for board being a base for other reports
## sdk-emerge-output-filtered - contains only lines with package information for SDK
## board-emerge-output-filtered - contains only lines with package information for board
## ${arch}-board-emerge-output-filtered - contains only lines with package information for board
## sdk-emerge-output-junk - contains only junk lines for SDK
## board-emerge-output-junk - contains only junk lines for board
## ${arch}-board-emerge-output-junk - contains only junk lines for board
## *-warnings - warnings printed by emerge or other tools
##
## Parameters:
## -h: this help
##
## Positional:
## 1 - architecture (amd64 or arm64)
## 2 - reports directory
## 1 - reports directory
## # - architectures (currently only amd64 or arm64 are valid)
##
set -euo pipefail
@ -54,49 +55,71 @@ while [[ ${#} -gt 0 ]]; do
esac
done
if [[ ${#} -ne 2 ]]; then
fail 'Expected two parameters: board architecture and reports directory'
if [[ ${#} -lt 2 ]]; then
fail 'Expected at least two parameters: reports directory and one or more board architectures'
fi
arch=${1}; shift
reports_dir=${1}; shift
# rest are architectures
mkdir -p "${reports_dir}"
set_eo "${reports_dir}"
set_eo "${reports_dir}" "${@}"
echo 'Running egencache for portage-stable'
generate_cache_for 'portage-stable' 2>"${EGENCACHE_W}"
echo 'Running egencache for coreos-overlay'
generate_cache_for 'coreos-overlay' 2>>"${EGENCACHE_W}"
echo 'Copying portage-stable cache to reports'
copy_cache_to_reports 'portage-stable' "${reports_dir}" 2>>"${EGENCACHE_W}"
echo 'Copying coreos-overlay cache to reports'
copy_cache_to_reports 'coreos-overlay' "${reports_dir}" 2>>"${EGENCACHE_W}"
echo 'Running pretend-emerge to get complete report for SDK'
package_info_for_sdk >"${SDK_EO}" 2>"${SDK_EO_W}"
echo 'Running pretend-emerge to get complete report for board'
package_info_for_board "${arch}" >"${BOARD_EO}" 2>"${BOARD_EO_W}"
for arch; do
be=${arch^^}_BOARD_EO
bew=${arch^^}_BOARD_EO_W
echo "Running pretend-emerge to get complete report for ${arch} board"
package_info_for_board "${arch}" >"${!be}" 2>"${!bew}"
done
ensure_no_errors
ensure_no_errors "${@}"
echo 'Separating emerge info from junk in SDK emerge output'
filter_sdk_eo >"${SDK_EO_F}" 2>>"${SDK_EO_W}"
junk_sdk_eo >"${SDK_EO}-junk" 2>>"${SDK_EO_W}"
echo 'Separating emerge info from junk in board emerge output'
filter_board_eo "${arch}" >"${BOARD_EO_F}" 2>>"${BOARD_EO_W}"
junk_board_eo >"${BOARD_EO}-junk" 2>>"${BOARD_EO_W}"
junk_sdk_eo >"${SDK_EO_J}" 2>>"${SDK_EO_W}"
for arch; do
bej=${arch^^}_BOARD_EO_J
bef=${arch^^}_BOARD_EO_F
bew=${arch^^}_BOARD_EO_W
echo "Separating emerge info from junk in ${arch} board emerge output"
filter_board_eo "${arch}" >"${!bef}" 2>>"${!bew}"
junk_board_eo "${arch}" >"${!bej}" 2>>"${!bew}"
done
ensure_valid_reports
ensure_valid_reports "${@}"
echo 'Generating SDK packages listing'
versions_sdk >"${reports_dir}/sdk-pkgs" 2>"${reports_dir}/sdk-pkgs-warnings"
echo 'Generating SDK packages listing with key-values (USE, PYTHON_TARGETS CPU_FLAGS_X86, etc)'
versions_sdk_with_key_values >"${reports_dir}/sdk-pkgs-kv" 2>"${reports_dir}/sdk-pkgs-kv-warnings"
echo 'Generating board packages listing'
versions_board >"${reports_dir}/board-pkgs" 2>"${reports_dir}/board-pkgs-warnings"
echo 'Generating board packages bdeps listing'
board_bdeps >"${reports_dir}/board-bdeps" 2>"${reports_dir}/board-bdeps-warnings"
echo 'Generating SDK profiles evaluation list'
ROOT=/ "${PKG_AUTO_IMPL_DIR}/print_profile_tree.sh" -ni -nh >"${reports_dir}/sdk-profiles" 2>"${reports_dir}/sdk-profiles-warnings"
echo 'Generating board profiles evaluation list'
ROOT="/build/${arch}-usr" "${PKG_AUTO_IMPL_DIR}/print_profile_tree.sh" -ni -nh >"${reports_dir}/board-profiles" 2>"${reports_dir}/board-profiles-warnings"
echo 'Generating SDK package source information'
package_sources_sdk >"${reports_dir}/sdk-package-repos" 2>"${reports_dir}/sdk-package-repos-warnings"
echo 'Generating board package source information'
package_sources_board >"${reports_dir}/board-package-repos" 2>"${reports_dir}/board-package-repos-warnings"
for arch; do
echo "Generating ${arch} board packages listing"
versions_board "${arch}" >"${reports_dir}/${arch}-board-pkgs" 2>"${reports_dir}/${arch}-board-pkgs-warnings"
echo "Generating ${arch} board packages bdeps listing"
board_bdeps "${arch}" >"${reports_dir}/${arch}-board-bdeps" 2>"${reports_dir}/${arch}-board-bdeps-warnings"
echo "Generating ${arch} board profiles evaluation list"
ROOT="/build/${arch}-usr" "${PKG_AUTO_IMPL_DIR}/print_profile_tree.sh" -ni -nh >"${reports_dir}/${arch}-board-profiles" 2>"${reports_dir}/${arch}-board-profiles-warnings"
echo "Generating ${arch} board package source information"
package_sources_board "${arch}" >"${reports_dir}/${arch}-board-package-repos" 2>"${reports_dir}/${arch}-board-package-repos-warnings"
done
echo "Cleaning empty warning files"
clean_empty_warning_files "${reports_dir}"