mirror of
https://github.com/flatcar/scripts.git
synced 2025-08-11 06:56:58 +02:00
They were showing up as "docker" or "containerd" in the reports, which is confusing. "sysext-docker" or "sysext-containerd" makes it clear.
3149 lines
106 KiB
Bash
3149 lines
106 KiB
Bash
#!/bin/bash
|
|
|
|
#
|
|
# TODO:
|
|
#
|
|
# - Generate a report about missing build deps of board packages in
|
|
# sdk. These reports can be generated by processing sdk-pkgs-kv and
|
|
# board-bdeps reports, I think.
|
|
#
|
|
# - Mount Gentoo repo into the SDK container and set up emerge to use
|
|
# Gentoo as a primary repo, and portage-stable and coreos-overlay as
|
|
# overlays. That way if an updated package pulls in a new package we
|
|
# can notice it when it comes from Gentoo (emerge reports also
|
|
# source repo like sys-libs/glibc-2.35-r5::gentoo or something like
|
|
# this). This would make this script more robust.
|
|
#
|
|
# - Instead of having a list of packages to update, rather update them
|
|
# all in a single commit and have a list of exclusions. The reason
|
|
# is that, at this point, almost all of the packages in
|
|
# portage-stable are automatically updated, exclusions being usually
|
|
# temporary, so it would be better to have a short file with
|
|
# temporary exclusions rather than a long file with some commented
|
|
# out entries. This probably would render the sort_packages_list.py
|
|
# script unnecessary. On the other hand, the current mode of
|
|
# operation may be still useful for the coreos-overlay packages,
|
|
# because none of them are under automation (some are, though, under
|
|
# an ad-hoc automation via github actions).
|
|
#
|
|
# - Handle package appearance or disappearance. Currently, when a
|
|
# package ends up being unused (so it exists, but is not picked up,
|
|
# because some other package stopped depending on it) or removed,
|
|
# the package ends up in the manual-work-needed file. This probably
|
|
# could be handled as an entry in the summary stubs about being
|
|
# dropped.
|
|
#
|
|
# - Find unused packages and eclasses.
|
|
#
|
|
# - The rename handling should probably also change all instances of
|
|
# the old name everywhere outside portage-stable, otherwise emerge
|
|
# may fail when some our ebuild still uses the old name, maybe.
|
|
#
|
|
|
|
# Needed to be enabled here to parse some globs inside the functions.
|
|
shopt -s extglob
|
|
# Saner defaults.
|
|
shopt -s nullglob
|
|
shopt -s dotglob
|
|
|
|
if [[ -z ${__PKG_AUTO_LIB_SH_INCLUDED__:-} ]]; then
|
|
__PKG_AUTO_LIB_SH_INCLUDED__=x
|
|
|
|
source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
|
|
source "${PKG_AUTO_IMPL_DIR}/cleanups.sh"
|
|
source "${PKG_AUTO_IMPL_DIR}/debug.sh"
|
|
source "${PKG_AUTO_IMPL_DIR}/gentoo_ver.sh"
|
|
source "${PKG_AUTO_IMPL_DIR}/md5_cache_diff_lib.sh"
|
|
|
|
# Sets up the workdir using the passed config. The config can be
|
|
# created basing on the config_template file or using the
|
|
# generate_config script.
|
|
#
|
|
# The path to the workdir can be empty - the function will then create
|
|
# a temporary directory.
|
|
#
|
|
# This also sets the WORKDIR global variable, allowing other function
|
|
# to be invoked.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to the workdir
|
|
# 2 - path to the config file
|
|
function setup_workdir_with_config() {
|
|
local workdir file
|
|
workdir=${1}; shift
|
|
config_file=${1}; shift
|
|
|
|
local cfg_scripts cfg_aux cfg_reports cfg_old_base cfg_new_base cfg_sdk_image_override
|
|
local -a cfg_cleanups cfg_debug_packages
|
|
|
|
# some defaults
|
|
cfg_old_base='origin/main'
|
|
cfg_new_base=''
|
|
cfg_cleanups=('ignore')
|
|
cfg_sdk_image_override=''
|
|
cfg_debug_packages=()
|
|
|
|
local line key value swwc_stripped var_name arch
|
|
while read -r line; do
|
|
strip_out "${line%%:*}" swwc_stripped
|
|
key=${swwc_stripped}
|
|
strip_out "${line#*:}" swwc_stripped
|
|
value=${swwc_stripped}
|
|
if [[ -z ${value} ]]; then
|
|
fail "empty value for ${key} in config"
|
|
fi
|
|
case ${key} in
|
|
scripts|aux|reports)
|
|
var_name="cfg_${key//-/_}"
|
|
local -n var_ref=${var_name}
|
|
var_ref=$(realpath "${value}")
|
|
unset -n var_ref
|
|
;;
|
|
old-base|new-base|sdk-image-override)
|
|
var_name="cfg_${key//-/_}"
|
|
local -n var_ref=${var_name}
|
|
var_ref=${value}
|
|
unset -n var_ref
|
|
;;
|
|
cleanups|debug-packages)
|
|
var_name="cfg_${key//-/_}"
|
|
mapfile -t "${var_name}" <<<"${value//,/$'\n'}"
|
|
;;
|
|
esac
|
|
done < <(cat_meaningful "${config_file}")
|
|
if [[ -z "${cfg_new_base}" ]]; then
|
|
cfg_new_base=${cfg_old_base}
|
|
fi
|
|
for key in scripts aux reports; do
|
|
var_name="cfg_${key//-/_}"
|
|
if [[ -z "${!var_name}" ]]; then
|
|
fail "${key} was not specified in config"
|
|
fi
|
|
done
|
|
|
|
setup_cleanups "${cfg_cleanups[@]}"
|
|
setup_workdir "${workdir}"
|
|
add_cleanup "rm -f ${WORKDIR@Q}/config"
|
|
cp -a "${config_file}" "${WORKDIR}/config"
|
|
setup_worktrees_in_workdir "${cfg_scripts}" "${cfg_old_base}" "${cfg_new_base}" "${cfg_reports}" "${cfg_aux}"
|
|
if [[ -n ${cfg_sdk_image_override} ]]; then
|
|
override_sdk_image_name "${cfg_sdk_image_override}"
|
|
fi
|
|
pkg_debug_add "${cfg_debug_packages[@]}"
|
|
}
|
|
|
|
# Goes over the list of automatically updated packages and synces them
|
|
# with packages from Gentoo repo. Cleans up missing packages.
|
|
#
|
|
# The function can only be called after the workdir has been set up
|
|
# with setup_workdir_with_config.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - a path to the Gentoo repo
|
|
function perform_sync_with_gentoo() {
|
|
local gentoo
|
|
gentoo=$(realpath "${1}"); shift
|
|
|
|
run_sync "${gentoo}"
|
|
handle_missing_in_scripts
|
|
handle_missing_in_gentoo "${gentoo}"
|
|
}
|
|
|
|
# Generates package update reports. Duh.
|
|
#
|
|
# The function can only be called after the workdir has been set up
|
|
# with setup_workdir_with_config.
|
|
#
|
|
# The location of the reports is specified in the config that was
|
|
# passed to setup_workdir_with_config.
|
|
function generate_package_update_reports() {
|
|
generate_sdk_reports
|
|
handle_gentoo_sync
|
|
}
|
|
|
|
# Saves the new state to a git branch in scripts.
|
|
#
|
|
# The function can only be called after the workdir has been set up
|
|
# with setup_workdir_with_config.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the new branch
|
|
function save_new_state() {
|
|
local branch_name
|
|
branch_name=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
info "saving new state to branch ${branch_name}"
|
|
git -C "${SCRIPTS}" branch --force "${branch_name}" "${NEW_STATE_BRANCH}"
|
|
}
|
|
|
|
#
|
|
#
|
|
# Implementation details, do not use directly in scripts sourcing this file.
|
|
#
|
|
#
|
|
|
|
# Creates a workdir, the path to which is stored in WORKDIR global
|
|
# variable.
|
|
#
|
|
# 1 - predefined work directory path (optional)
|
|
function setup_workdir() {
|
|
local workdir
|
|
workdir=${1:-}
|
|
if [[ -z "${workdir}" ]]; then
|
|
workdir=$(mktemp --tmpdir --directory 'pkg-auto-workdir.XXXXXXXX')
|
|
else
|
|
if [[ -e ${workdir} ]] && [[ ! -d ${workdir} ]]; then
|
|
fail "Expected ${workdir@Q} to be a directory"
|
|
fi
|
|
if [[ -d ${workdir} ]] && ! dir_is_empty "${workdir}"; then
|
|
fail "Expected ${workdir@Q} to be an empty directory"
|
|
fi
|
|
fi
|
|
|
|
declare -g WORKDIR
|
|
WORKDIR=$(realpath "${workdir}")
|
|
add_cleanup "rmdir ${WORKDIR@Q}"
|
|
mkdir -p "${WORKDIR}"
|
|
|
|
setup_initial_globals_file
|
|
}
|
|
|
|
# Sets up worktrees for the old and new state inside WORKDIR. Creates
|
|
# the globals file inside WORKDIR.
|
|
#
|
|
# 1 - path to scripts repo
|
|
# 2 - base for the old state worktree (e.g. origin/main)
|
|
# 3 - base for the new state worktree (e.g. origin/main)
|
|
# 4 - path to reports directory
|
|
function setup_worktrees_in_workdir() {
|
|
local scripts old_base new_base reports_dir aux_dir
|
|
scripts=${1}; shift
|
|
old_base=${1}; shift
|
|
new_base=${1}; shift
|
|
reports_dir=${1}; shift
|
|
aux_dir=${1}; shift
|
|
|
|
local old_state new_state
|
|
old_state="${WORKDIR}/old_state"
|
|
new_state="${WORKDIR}/new_state"
|
|
|
|
# create reports directory now - there may be some developer
|
|
# warnings afoot
|
|
mkdir -p "${reports_dir}"
|
|
|
|
setup_worktree "${scripts}" "${old_base}" "old-state-${RANDOM}" "${old_state}"
|
|
setup_worktree "${scripts}" "${new_base}" "new-state-${RANDOM}" "${new_state}"
|
|
extend_globals_file "${scripts}" "${old_state}" "${new_state}" "${reports_dir}" "${aux_dir}"
|
|
}
|
|
|
|
# Adds an overridden SDK image name to the globals file.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - image name
|
|
function override_sdk_image_name() {
|
|
local image_name=${1}; shift
|
|
|
|
append_to_globals "SDK_IMAGE=${image_name@Q}"
|
|
}
|
|
|
|
# Appends passed lines to the globals file.
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - lines to append
|
|
function append_to_globals() {
|
|
local globals_file
|
|
globals_file="${WORKDIR}/globals"
|
|
if [[ ! -e "${globals_file}" ]]; then
|
|
fail "globals not set yet in workdir"
|
|
fi
|
|
|
|
lines_to_file "${globals_file}" "${@}"
|
|
}
|
|
|
|
# Processes the update files in portage-stable and coreos-overlay to
|
|
# figure out potential package renames. The results are stored in the
|
|
# passed map.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of a map variable; will be a mapping of old package name to
|
|
# new package name
|
|
function process_profile_updates_directory() {
|
|
local from_to_map_var_name=${1}; shift
|
|
|
|
local -a ppud_ordered_names
|
|
get_ordered_update_filenames ppud_ordered_names
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local bf ps_f co_f pkg f line old new
|
|
local -a fields
|
|
local -A from_to_f=()
|
|
mvm_declare ppud_to_from_set_mvm mvm_mvc_set
|
|
for bf in "${ppud_ordered_names[@]}"; do
|
|
# coreos-overlay updates may overwrite updates from
|
|
# portage-stable, but only from the file of the same name
|
|
ps_f=${NEW_PORTAGE_STABLE}/profiles/updates/${bf}
|
|
co_f=${NEW_COREOS_OVERLAY}/profiles/updates/${bf}
|
|
for f in "${ps_f}" "${co_f}"; do
|
|
if [[ ! -f ${f} ]]; then
|
|
continue
|
|
fi
|
|
while read -r line; do
|
|
if [[ ${line} != 'move '* ]]; then
|
|
# other possibility is "slotmove" - we don't care
|
|
# about those.
|
|
continue
|
|
fi
|
|
mapfile -t fields <<<"${line// /$'\n'}"
|
|
if [[ ${#fields[@]} -ne 3 ]]; then
|
|
fail_lines \
|
|
"Malformed line ${line@Q} in updates file ${f@Q}." \
|
|
"The line should have 3 fields, has ${#fields[*]}."
|
|
fi
|
|
from_to_f["${fields[1]}"]=${fields[2]}
|
|
done <"${f}"
|
|
done
|
|
for old in "${!from_to_f[@]}"; do
|
|
new=${from_to_f["${old}"]}
|
|
update_rename_maps "${from_to_map_var_name}" ppud_to_from_set_mvm "${old}" "${new}"
|
|
done
|
|
done
|
|
|
|
mvm_unset ppud_to_from_set_mvm
|
|
}
|
|
|
|
# Gets a merged and ordered list of update files from portage-stable
|
|
# and coreos-overlay and stores the in the passed array. The files
|
|
# have names like Q1-2018, Q1-2023, Q2-2019 and so on. We need to sort
|
|
# them by year, then by quarter.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of a array variable where the ordered names will be stored
|
|
function get_ordered_update_filenames() {
|
|
local ordered_names_var_name=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -A names_set=()
|
|
local f
|
|
|
|
for f in "${NEW_PORTAGE_STABLE}/profiles/updates/"* "${NEW_COREOS_OVERLAY}/profiles/updates/"*; do
|
|
names_set["${f##*/}"]=x
|
|
done
|
|
|
|
mapfile -t "${ordered_names_var_name}" < <(printf '%s\n' "${!names_set[@]}" | sort --field-separator=- --key=2n --key=1n)
|
|
}
|
|
|
|
# Updates the rename map with the new "old to new package rename". It
|
|
# tries to be smart about the rename sequences (though not sure if
|
|
# this is necessary, really). If in older update file package foo was
|
|
# renamed to bar and in current update file the bar package is renamed
|
|
# to quux, then this function adds an entry about the "bar to quux"
|
|
# rename, but also updates the older entry about "foo to bar" rename
|
|
# to "foo to quux" rename.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the renames map variable; should be a mapping of old to
|
|
# new names
|
|
# 2 - name of the set mvm variable; should be a mapping of new name to
|
|
# a set of old names (a reverse mapping to the renames map)
|
|
# 3 - old name
|
|
# 4 - new name
|
|
function update_rename_maps() {
|
|
local -n ft_map_ref=${1}; shift
|
|
local tf_set_mvm_var_name=${1}; shift
|
|
local old_name=${1}; shift
|
|
local new_name=${1}; shift
|
|
|
|
local prev_new_name=${ft_map_ref["${old_name}"]:-}
|
|
|
|
if [[ -n ${prev_new_name} ]] && [[ ${prev_new_name} != "${new_name}" ]]; then
|
|
fail_lines \
|
|
"Invalid package rename from ${old_name@Q} to ${new_name@Q}." \
|
|
"There was already a rename from ${old_name@Q} to ${prev_new_name@Q}."
|
|
fi
|
|
|
|
local -a new_set=()
|
|
|
|
local urm_set_var_name
|
|
mvm_get "${tf_set_mvm_var_name}" "${old_name}" urm_set_var_name
|
|
if [[ -n ${urm_set_var_name} ]]; then
|
|
local -n old_set_ref=${urm_set_var_name}
|
|
new_set+=( "${!old_set_ref[@]}" )
|
|
unset -n old_set_ref
|
|
fi
|
|
new_set+=( "${old_name}" )
|
|
mvm_add "${tf_set_mvm_var_name}" "${new_name}" "${new_set[@]}"
|
|
local old
|
|
|
|
for old in "${new_set[@]}"; do
|
|
ft_map_ref["${old}"]=${new_name}
|
|
done
|
|
unset -n ft_map_ref
|
|
}
|
|
|
|
# Sets up a worktree and necessary cleanups.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to the git repo
|
|
# 2 - name of a branch to be used as a base of a new worktree branch
|
|
# 3 - name of the new worktree branch
|
|
# 4 - path where the new worktree will be created
|
|
function setup_worktree() {
|
|
local repo base branch worktree_dir
|
|
repo=${1}; shift
|
|
base=${1}; shift
|
|
branch=${1}; shift
|
|
worktree_dir=${1}; shift
|
|
|
|
add_cleanup \
|
|
"git -C ${worktree_dir@Q} reset --hard HEAD" \
|
|
"git -C ${worktree_dir@Q} clean -ffdx" \
|
|
"git -C ${repo@Q} worktree remove ${worktree_dir@Q}" \
|
|
"git -C ${repo@Q} branch -D ${branch@Q}"
|
|
|
|
git -C "${repo}" worktree add -b "${branch}" "${worktree_dir}" "${base}"
|
|
}
|
|
|
|
# Creates an initial globals file. It's initial because it contains
|
|
# data known up-front, so mostly things that are defined in one place
|
|
# to avoid repeating them everywhere.
|
|
#
|
|
# More stuff will be added later to the globals file based on config
|
|
# or else.
|
|
function setup_initial_globals_file() {
|
|
local sync_script pkg_list_sort_script
|
|
sync_script="${PKG_AUTO_IMPL_DIR}/sync_with_gentoo.sh"
|
|
pkg_list_sort_script="${PKG_AUTO_IMPL_DIR}/sort_packages_list.py"
|
|
|
|
local globals_file
|
|
globals_file="${WORKDIR}/globals"
|
|
|
|
local -a sigf_arches
|
|
get_valid_arches sigf_arches
|
|
|
|
add_cleanup "rm -f ${globals_file@Q}"
|
|
cat <<EOF >"${globals_file}"
|
|
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=${sync_script@Q}
|
|
PKG_LIST_SORT_SCRIPT=${pkg_list_sort_script@Q}
|
|
|
|
ARCHES=( ${sigf_arches[*]@Q} )
|
|
WHICH=('old' 'new')
|
|
SDK_PKGS='sdk-pkgs'
|
|
BOARD_PKGS='board-pkgs'
|
|
REPORTS=( "\${SDK_PKGS}" "\${BOARD_PKGS}" )
|
|
EOF
|
|
}
|
|
|
|
# Extend the globals file with information from config and other
|
|
# information derived from it.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to scripts repository
|
|
# 2 - path to scripts worktree with old state
|
|
# 3 - path to scripts worktree with new state
|
|
# 4 - path to reports directory
|
|
# 5 - path to aux directory
|
|
function extend_globals_file() {
|
|
local scripts old_state new_state reports_dir aux_dir
|
|
scripts=${1}; shift
|
|
old_state=${1}; shift
|
|
new_state=${1}; shift
|
|
reports_dir=${1}; shift
|
|
aux_dir=${1}; shift
|
|
|
|
local globals_file
|
|
globals_file="${WORKDIR}/globals"
|
|
if [[ ! -e "${globals_file}" ]]; then
|
|
fail 'an initial version of globals file should already exist'
|
|
fi
|
|
|
|
local old_state_branch new_state_branch
|
|
old_state_branch=$(git -C "${old_state}" rev-parse --abbrev-ref HEAD)
|
|
new_state_branch=$(git -C "${new_state}" rev-parse --abbrev-ref HEAD)
|
|
|
|
local portage_stable_suffix old_portage_stable new_portage_stable
|
|
portage_stable_suffix='sdk_container/src/third_party/portage-stable'
|
|
old_portage_stable="${old_state}/${portage_stable_suffix}"
|
|
new_portage_stable="${new_state}/${portage_stable_suffix}"
|
|
|
|
local coreos_overlay_suffix old_coreos_overlay new_coreos_overlay
|
|
coreos_overlay_suffix='sdk_container/src/third_party/coreos-overlay'
|
|
old_coreos_overlay="${old_state}/${coreos_overlay_suffix}"
|
|
new_coreos_overlay="${new_state}/${coreos_overlay_suffix}"
|
|
|
|
cat <<EOF >>"${globals_file}"
|
|
|
|
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=${scripts@Q}
|
|
OLD_STATE=${old_state@Q}
|
|
NEW_STATE=${new_state@Q}
|
|
OLD_STATE_BRANCH=${old_state_branch@Q}
|
|
NEW_STATE_BRANCH=${new_state_branch@Q}
|
|
PORTAGE_STABLE_SUFFIX=${portage_stable_suffix@Q}
|
|
OLD_PORTAGE_STABLE=${old_portage_stable@Q}
|
|
NEW_PORTAGE_STABLE=${new_portage_stable@Q}
|
|
REPORTS_DIR=${reports_dir@Q}
|
|
|
|
COREOS_OVERLAY_SUFFIX=${coreos_overlay_suffix@Q}
|
|
OLD_COREOS_OVERLAY=${old_coreos_overlay@Q}
|
|
NEW_COREOS_OVERLAY=${new_coreos_overlay@Q}
|
|
|
|
NEW_STATE_PACKAGES_LIST="\${NEW_STATE}/.github/workflows/portage-stable-packages-list"
|
|
|
|
AUX_DIR=${aux_dir@Q}
|
|
EOF
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${globals_file}"
|
|
|
|
local last_nightly_version_id last_nightly_build_id
|
|
# shellcheck source=for-shellcheck/version.txt
|
|
last_nightly_version_id=$(source "${NEW_STATE}/sdk_container/.repo/manifests/version.txt"; printf '%s' "${FLATCAR_VERSION_ID}")
|
|
# shellcheck source=for-shellcheck/version.txt
|
|
last_nightly_build_id=$(source "${NEW_STATE}/sdk_container/.repo/manifests/version.txt"; printf '%s' "${FLATCAR_BUILD_ID}")
|
|
|
|
local -a locals=() definitions=()
|
|
local sdk_image_name sdk_image_var_name=SDK_IMAGE
|
|
sdk_image_name="ghcr.io/flatcar/flatcar-sdk-all:${last_nightly_version_id}-${last_nightly_build_id}"
|
|
locals+=( "${sdk_image_var_name@Q}" )
|
|
definitions+=( "${sdk_image_var_name}=${sdk_image_name@Q}" )
|
|
|
|
append_to_globals \
|
|
'' \
|
|
"local ${locals[*]}" \
|
|
'' \
|
|
"${definitions[@]}"
|
|
|
|
local -A listing_kinds
|
|
local packages_file tag filename stripped old
|
|
|
|
for arch in "${ARCHES[@]}"; do
|
|
for packages_file in "${AUX_DIR}/${arch}/"*_packages.txt; do
|
|
filename=${packages_file##*/}
|
|
stripped=${filename%_packages.txt}
|
|
case ${stripped} in
|
|
'flatcar_developer_container')
|
|
tag='dev'
|
|
;;
|
|
'flatcar_production_image')
|
|
tag='prod'
|
|
;;
|
|
'flatcar-'*)
|
|
tag="sysext-${stripped#flatcar-}"
|
|
;;
|
|
'oem-'*)
|
|
tag=${stripped#oem-}
|
|
;;
|
|
*'-flatcar')
|
|
tag="sysext-${stripped%-flatcar}"
|
|
;;
|
|
*)
|
|
devel_warn "Unknown listing file ${packages_file@Q}"
|
|
continue
|
|
;;
|
|
esac
|
|
old=${listing_kinds["${tag}"]:-}
|
|
if [[ -n ${old} ]]; then
|
|
if [[ ${old} != "${filename}" ]]; then
|
|
devel_warn "Two different packages files (${old@Q} and ${filename@Q} for a single tag ${tag@Q}"
|
|
fi
|
|
else
|
|
listing_kinds["${tag}"]=${filename}
|
|
fi
|
|
done
|
|
done
|
|
|
|
local -a sorted_tags sorted_lines
|
|
mapfile -t sorted_tags < <(printf '%s\n' "${!listing_kinds[@]}" | sort)
|
|
for tag in "${sorted_tags[@]}"; do
|
|
filename=${listing_kinds["${tag}"]}
|
|
sorted_lines+=(" [${tag@Q}]=${filename@Q}")
|
|
done
|
|
|
|
append_to_globals \
|
|
'' \
|
|
'local -A LISTING_KINDS' \
|
|
'' \
|
|
'LISTING_KINDS=(' \
|
|
"${sorted_lines[@]}" \
|
|
')'
|
|
}
|
|
|
|
# Sets up environment variables for some git commands.
|
|
#
|
|
# Make sure to call the following beforehand:
|
|
#
|
|
# local -x "${GIT_ENV_VARS[@]}"
|
|
#
|
|
# The GIT_ENV_VARS array comes from the globals file.
|
|
function setup_git_env() {
|
|
local bot_name bot_email role what
|
|
|
|
bot_name='Flatcar Buildbot'
|
|
bot_email='buildbot@flatcar-linux.org'
|
|
for role in AUTHOR COMMITTER; do
|
|
for what in name email; do
|
|
local -n var_ref="GIT_${role}_${what^^}"
|
|
local -n value_ref="bot_${what}"
|
|
var_ref=${value_ref}
|
|
unset -n value_ref
|
|
unset -n var_ref
|
|
done
|
|
done
|
|
}
|
|
|
|
# Goes over the packages list and synces them with the passed Gentoo
|
|
# repo.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to the Gentoo repo
|
|
function run_sync() {
|
|
local gentoo
|
|
gentoo=${1}; shift
|
|
|
|
local -a missing_in_scripts missing_in_gentoo
|
|
missing_in_scripts=()
|
|
missing_in_gentoo=()
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -x "${GIT_ENV_VARS[@]}"
|
|
setup_git_env
|
|
|
|
local -a packages_to_update
|
|
packages_to_update=()
|
|
|
|
local package
|
|
while read -r package; do
|
|
if [[ ! -e "${NEW_PORTAGE_STABLE}/${package}" ]]; then
|
|
# If this happens, it means that the package was moved to overlay
|
|
# or dropped, the list ought to be updated.
|
|
missing_in_scripts+=("${package}")
|
|
continue
|
|
fi
|
|
if [[ ! -e "${gentoo}/${package}" ]]; then
|
|
# If this happens, it means that the package was obsoleted or moved
|
|
# in Gentoo. The obsoletion needs to be handled in the case-by-case
|
|
# manner, while move should be handled by doing the same move
|
|
# in portage-stable. The build should not break because of the move,
|
|
# because most likely it's already reflected in the profiles/updates
|
|
# directory.
|
|
missing_in_gentoo+=("${package}")
|
|
continue
|
|
fi
|
|
packages_to_update+=( "${package}" )
|
|
done < <(cat_meaningful "${NEW_STATE_PACKAGES_LIST}")
|
|
env --chdir="${NEW_PORTAGE_STABLE}" "${SYNC_SCRIPT}" -b -- "${gentoo}" "${packages_to_update[@]}"
|
|
|
|
save_missing_in_scripts "${missing_in_scripts[@]}"
|
|
save_missing_in_gentoo "${missing_in_gentoo[@]}"
|
|
}
|
|
|
|
# A helper function that prints the contents of a file skipping empty
|
|
# lines and lines starting with a hash.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to a file to print
|
|
function cat_meaningful() {
|
|
local file
|
|
file=${1}; shift
|
|
|
|
xgrep '^[^#]' "${file}"
|
|
}
|
|
|
|
# Saves a list of package names to a file and adds a cleanup for
|
|
# it. The names can be loaded again with load_simple_package_list.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to a file where package names will be stored
|
|
# @ - the package names
|
|
function save_simple_package_list() {
|
|
local file
|
|
file=${1}; shift
|
|
# rest are packages
|
|
|
|
add_cleanup "rm -f ${file@Q}"
|
|
if [[ ${#} -eq 0 ]]; then
|
|
truncate --size=0 "${file}"
|
|
else
|
|
printf '%s\n' "${@}" >"${file}"
|
|
fi
|
|
}
|
|
|
|
# Loads a list of packages saved previously with
|
|
# save_simple_package_list.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to a file where packages were stored
|
|
# 2 - name of an array variable; will contain package names
|
|
function load_simple_package_list() {
|
|
local file packages_var_name
|
|
file=${1}; shift
|
|
packages_var_name=${1}; shift
|
|
|
|
mapfile -t "${packages_var_name}" <"${file}"
|
|
}
|
|
|
|
# General function for saving missing packages. Takes care of creating
|
|
# a directory for the listing.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to a directory which will contain the listing
|
|
# 2 - name of the listing file
|
|
function save_missing_packages() {
|
|
local dir file
|
|
dir=${1}; shift
|
|
file=${1}; shift
|
|
|
|
create_cleanup_dir "${dir}"
|
|
save_simple_package_list "${dir}/${file}" "${@}"
|
|
}
|
|
|
|
# Creates a directory and adds a cleanup if the directory was missing.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to the directory
|
|
function create_cleanup_dir() {
|
|
local dir
|
|
dir=${1}; shift
|
|
if [[ ! -d "${dir}" ]]; then
|
|
add_cleanup "rmdir ${dir@Q}"
|
|
mkdir "${dir}"
|
|
fi
|
|
}
|
|
|
|
# Saves a list of package names that we missing in scripts repo (which
|
|
# means that we were asked to sync a package that isn't in scripts to
|
|
# begin with).
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - package names
|
|
function save_missing_in_scripts() {
|
|
save_missing_packages "${WORKDIR}/missing_in_scripts" "saved_list" "${@}"
|
|
}
|
|
|
|
# Saves a list of package names that we missing in Gentoo repo (which
|
|
# means that we were asked to sync a possibly obsolete or renamed
|
|
# package).
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - package names
|
|
function save_missing_in_gentoo() {
|
|
save_missing_packages "${WORKDIR}/missing_in_gentoo" "saved_list" "${@}"
|
|
}
|
|
|
|
# Loads a list of package names that were missing in scripts repo.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of an array variable; will contain package names
|
|
function load_missing_in_scripts() {
|
|
local packages_var_name
|
|
packages_var_name=${1}; shift
|
|
|
|
load_simple_package_list "${WORKDIR}/missing_in_scripts/saved_list" "${packages_var_name}"
|
|
}
|
|
|
|
# Loads a list of package names that were missing in Gentoo repo.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of an array variable; will contain package names
|
|
function load_missing_in_gentoo() {
|
|
local packages_var_name
|
|
packages_var_name=${1}; shift
|
|
|
|
load_simple_package_list "${WORKDIR}/missing_in_gentoo/saved_list" "${packages_var_name}"
|
|
}
|
|
|
|
# Handles package names that were missing in scripts by dropping them
|
|
# from the listing of packages that should be updated automatically.
|
|
function handle_missing_in_scripts() {
|
|
local -a hmis_missing_in_scripts
|
|
hmis_missing_in_scripts=()
|
|
load_missing_in_scripts hmis_missing_in_scripts
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
if [[ ${#hmis_missing_in_scripts[@]} -eq 0 ]]; then
|
|
return 0;
|
|
fi
|
|
|
|
# Remove missing in scripts entries from package automation
|
|
local dir
|
|
dir="${WORKDIR}/missing_in_scripts"
|
|
create_cleanup_dir "${dir}"
|
|
local missing_re
|
|
join_by missing_re '\|' "${missing_in_scripts[@]}"
|
|
add_cleanup "rm -f ${dir@Q}/pkg_list"
|
|
xgrep --invert-match --line-regexp --fixed-strings --regexp="${missing_re}" "${NEW_STATE_PACKAGES_LIST}" >"${dir}/pkg_list"
|
|
"${PKG_LIST_SORT_SCRIPT}" "${dir}/pkg_list" >"${NEW_STATE_PACKAGES_LIST}"
|
|
|
|
local -x "${GIT_ENV_VARS[@]}"
|
|
setup_git_env
|
|
|
|
git -C "${NEW_STATE}" add "${NEW_STATE_PACKAGES_LIST}"
|
|
git -C "${NEW_STATE}" commit --quiet --message '.github: Drop missing packages from automation'
|
|
info_lines 'dropped missing packages from automation' "${missing_in_scripts[@]/#/- }"
|
|
}
|
|
|
|
# Helper function to print lines to a file clobbering the old
|
|
# contents.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to the file
|
|
# @ - lines to print
|
|
function lines_to_file_truncate() {
|
|
truncate --size=0 "${1}"
|
|
lines_to_file "${@}"
|
|
}
|
|
|
|
# Helper function to append lines to a file.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to the file
|
|
# @ - lines to print
|
|
function lines_to_file() {
|
|
printf '%s\n' "${@:2}" >>"${1}"
|
|
}
|
|
|
|
# Adds lines to "manual work needed" file in reports.
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - lines to add
|
|
function manual() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
pkg_debug_lines 'manual work needed:' "${@}"
|
|
lines_to_file "${REPORTS_DIR}/manual-work-needed" "${@}"
|
|
}
|
|
|
|
# Adds lines to "warnings" file in reports. Should be used to report
|
|
# some issues with the processed packages.
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - lines to add
|
|
function pkg_warn() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
pkg_debug_lines 'pkg warn:' "${@}"
|
|
lines_to_file "${REPORTS_DIR}/warnings" "${@}"
|
|
}
|
|
|
|
# Adds lines to "developer warnings" file in reports. Should be used
|
|
# to report some failed assumption in the automation, or bugs.
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - lines to add
|
|
function devel_warn() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
pkg_debug_lines 'developer warn:' "${@}"
|
|
lines_to_file "${REPORTS_DIR}/developer-warnings" "${@}"
|
|
}
|
|
|
|
# Handles package names that were missing from Gentoo by either
|
|
# renaming and syncing them if a rename exists or by adding the
|
|
# package to the "manual work needed" file.
|
|
function handle_missing_in_gentoo() {
|
|
local gentoo
|
|
gentoo=${1}; shift
|
|
|
|
local -a hmig_missing_in_gentoo
|
|
hmig_missing_in_gentoo=()
|
|
load_missing_in_gentoo hmig_missing_in_gentoo
|
|
|
|
if [[ ${#hmig_missing_in_gentoo[@]} -eq 0 ]]; then
|
|
return 0;
|
|
fi
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -A hmig_rename_map=()
|
|
process_profile_updates_directory hmig_rename_map
|
|
|
|
local -a renamed_from renamed_to
|
|
renamed_from=()
|
|
renamed_to=()
|
|
|
|
local -x "${GIT_ENV_VARS[@]}"
|
|
setup_git_env
|
|
|
|
local missing new_name hmig_old_basename hmig_new_basename ebuild ebuild_version_ext new_ebuild_filename
|
|
for missing in "${hmig_missing_in_gentoo[@]}"; do
|
|
new_name=${hmig_rename_map["${missing}"]:-}
|
|
if [[ -z "${new_name}" ]]; then
|
|
manual "- package ${missing} is gone from Gentoo and no rename found"
|
|
continue
|
|
fi
|
|
mkdir -p "${NEW_PORTAGE_STABLE}/${new_name%/*}"
|
|
git -C "${NEW_STATE}" mv "${NEW_PORTAGE_STABLE}/${missing}" "${NEW_PORTAGE_STABLE}/${new_name}"
|
|
basename_out "${missing}" hmig_old_basename
|
|
basename_out "${new_name}" hmig_new_basename
|
|
if [[ "${hmig_old_basename}" != "${hmig_new_basename}" ]]; then
|
|
for ebuild in "${NEW_PORTAGE_STABLE}/${new_name}/${hmig_old_basename}-"*'.ebuild'; do
|
|
# 1.2.3-r4.ebuild
|
|
ebuild_version_ext=${ebuild##*/"${hmig_old_basename}-"}
|
|
new_ebuild_filename="${hmig_new_basename}-${ebuild_version_ext}"
|
|
git -C "${NEW_STATE}" mv "${ebuild}" "${NEW_PORTAGE_STABLE}/${new_name}/${new_ebuild_filename}"
|
|
done
|
|
fi
|
|
git -C "${NEW_STATE}" commit --quiet --message "${new_name}: Renamed from ${missing}"
|
|
info "renamed ${missing} to ${new_name}"
|
|
renamed_from+=("${missing}")
|
|
renamed_to+=("${new_name}")
|
|
done
|
|
|
|
if [[ ${#renamed_from[@]} -eq 0 ]]; then
|
|
return 0
|
|
fi
|
|
|
|
env --chdir="${NEW_PORTAGE_STABLE}" "${SYNC_SCRIPT}" -b -- "${gentoo}" "${renamed_to[@]}"
|
|
|
|
local dir renamed_re
|
|
dir="${WORKDIR}/missing_in_gentoo"
|
|
create_cleanup_dir "${dir}"
|
|
join_by renamed_re '\|' "${renamed_from[@]}"
|
|
add_cleanup "rm -f ${dir@Q}/pkg_list"
|
|
{
|
|
xgrep --invert-match --line-regexp --regexp="${renamed_re}" "${NEW_STATE_PACKAGES_LIST}"
|
|
printf '%s\n' "${renamed_to[@]}"
|
|
} >"${dir}/pkg_list"
|
|
"${PKG_LIST_SORT_SCRIPT}" "${dir}/pkg_list" >"${NEW_STATE_PACKAGES_LIST}"
|
|
git -C "${NEW_STATE}" add "${NEW_STATE_PACKAGES_LIST}"
|
|
git -C "${NEW_STATE}" commit --quiet --message '.github: Update package names in automation'
|
|
info 'updated packages names in automation'
|
|
}
|
|
|
|
# Process the package listings stored in the aux directory to find out
|
|
# the package tags that describe the kind of image the package is used
|
|
# in (base image, developer container, sysext image, etc.)
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - a name to an array mvm variable; will be a mapping of a package
|
|
# name to an array of tags
|
|
function process_listings() {
|
|
local pkg_to_tags_mvm_var_name
|
|
pkg_to_tags_mvm_var_name=${1}
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
#mvm_debug_enable pl_pkg_to_tags_set_mvm
|
|
mvm_declare pl_pkg_to_tags_set_mvm mvm_mvc_set
|
|
|
|
local arch kind file listing pkg
|
|
for arch in "${ARCHES[@]}"; do
|
|
for kind in "${!LISTING_KINDS[@]}"; do
|
|
file=${LISTING_KINDS["${kind}"]}
|
|
listing="${AUX_DIR}/${arch}/${file}"
|
|
if [[ ! -e "${listing}" ]]; then
|
|
# some listings are arch-specific, so they will be
|
|
# missing for other arches
|
|
continue
|
|
fi
|
|
# lines are like as follows:
|
|
#
|
|
# acct-group/adm-0-r2::portage-stable
|
|
while read -r pkg; do
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "processing listing ${arch}/${file}: adding tag ${kind^^}"
|
|
pkg_debug_disable
|
|
mvm_add pl_pkg_to_tags_set_mvm "${pkg}" "${kind^^}"
|
|
# VER_ERE_UNBOUNDED and PKG_ERE_UNBOUNDED come from gentoo_ver.sh
|
|
done < <(sed -E -e 's#^('"${PKG_ERE_UNBOUNDED}"')-'"${VER_ERE_UNBOUNDED}"'::.*#\1#' "${listing}")
|
|
done
|
|
done
|
|
|
|
mvm_iterate pl_pkg_to_tags_set_mvm set_mvm_to_array_mvm_cb "${pkg_to_tags_mvm_var_name}"
|
|
mvm_unset pl_pkg_to_tags_set_mvm
|
|
#mvm_debug_disable pl_pkg_to_tags_set_mvm
|
|
local -a pl_debug_pkgs pl_tags_array_name
|
|
pkg_debug_packages pl_debug_pkgs
|
|
for pkg in "${pl_debug_pkgs[@]}"; do
|
|
mvm_get "${pkg_to_tags_mvm_var_name}" "${pkg}" pl_tags_array_name
|
|
local -n tags_ref=${pl_tags_array_name:-EMPTY_ARRAY}
|
|
pkg_debug_print_c "${pkg}" "tags stored in ${pkg_to_tags_mvm_var_name}: ${tags_ref[*]}"
|
|
unset -n tags_ref
|
|
done
|
|
}
|
|
|
|
# A callback to mvm_iterate that turns a set mvm to an array mvm. It
|
|
# makes sure that the tag for the production image (or base image) is
|
|
# always first in the array.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the array mvm variable that will be filled (extra arg of
|
|
# the callback)
|
|
# 2 - name of the package
|
|
# 3 - name of the set variable holding tags
|
|
# @ - tags
|
|
function set_mvm_to_array_mvm_cb() {
|
|
local pkg_to_tags_mvm_var_name pkg
|
|
pkg_to_tags_mvm_var_name=${1}; shift
|
|
pkg=${1}; shift
|
|
local -n set_ref=${1}; shift
|
|
# rest are set items
|
|
|
|
local removed
|
|
removed=''
|
|
local -a prod_item
|
|
prod_item=()
|
|
if [[ -n ${set_ref['PROD']:-} ]]; then
|
|
prod_item+=('PROD')
|
|
unset "set_ref['PROD']"
|
|
removed=x
|
|
fi
|
|
local -a sorted_items
|
|
mapfile -t sorted_items < <(printf '%s\n' "${!set_ref[@]}" | sort)
|
|
if [[ -n ${removed} ]]; then
|
|
set_ref['PROD']=x
|
|
fi
|
|
|
|
mvm_add "${pkg_to_tags_mvm_var_name}" "${pkg}" "${prod_item[@]}" "${sorted_items[@]}"
|
|
}
|
|
|
|
# Generate package reports inside SDKs for all arches and states. In
|
|
# case of failure, whatever reports where generated so far will be
|
|
# stored in salvaged-reports subdirectory of the reports directory.
|
|
# Otherwise they will end up in reports-from-sdk subdirectory.
|
|
function generate_sdk_reports() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
add_cleanup "rmdir ${WORKDIR@Q}/pkg-reports"
|
|
mkdir "${WORKDIR}/pkg-reports"
|
|
|
|
if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep --quiet --line-regexp --fixed-strings "${SDK_IMAGE}"; then
|
|
fail "No SDK image named ${SDK_IMAGE@Q} available locally, pull it before running this script"
|
|
fi
|
|
|
|
local sdk_run_kind state_var_name sdk_run_state state_branch_var_name sdk_run_state_branch
|
|
local pkg_auto_copy rv
|
|
local sdk_reports_dir top_dir dir entry full_path
|
|
local -a dir_queue all_dirs all_files
|
|
|
|
for sdk_run_kind in "${WHICH[@]}"; do
|
|
state_var_name="${sdk_run_kind^^}_STATE"
|
|
sdk_run_state="${!state_var_name}_sdk_run"
|
|
state_branch_var_name="${sdk_run_kind^^}_STATE_BRANCH"
|
|
sdk_run_state_branch="${!state_branch_var_name}-sdk-run"
|
|
|
|
add_cleanup \
|
|
"git -C ${sdk_run_state@Q} reset --hard HEAD" \
|
|
"git -C ${sdk_run_state@Q} clean -ffdx" \
|
|
"git -C ${SCRIPTS@Q} worktree remove ${sdk_run_state@Q}" \
|
|
"git -C ${SCRIPTS@Q} branch -D ${sdk_run_state_branch@Q}"
|
|
git -C "${SCRIPTS}" \
|
|
worktree add -b "${sdk_run_state_branch}" "${sdk_run_state}" "${!state_branch_var_name}"
|
|
|
|
pkg_auto_copy=$(mktemp --tmpdir="${WORKDIR}" --directory "pkg-auto-copy.XXXXXXXX")
|
|
add_cleanup "rm -rf ${pkg_auto_copy@Q}"
|
|
cp -a "${PKG_AUTO_DIR}"/* "${pkg_auto_copy}"
|
|
local -a run_sdk_container_args=(
|
|
-C "${SDK_IMAGE}"
|
|
-n "pkg-${sdk_run_kind}"
|
|
-U
|
|
-m "${pkg_auto_copy}:/mnt/host/source/src/scripts/pkg_auto"
|
|
--rm
|
|
./pkg_auto/inside_sdk_container.sh pkg-reports "${ARCHES[@]}"
|
|
)
|
|
rv=0
|
|
env --chdir "${sdk_run_state}" ./run_sdk_container "${run_sdk_container_args[@]}" || rv=${?}
|
|
unset run_sdk_container_args
|
|
if [[ ${rv} -ne 0 ]]; then
|
|
local salvaged_dir
|
|
salvaged_dir="${REPORTS_DIR}/salvaged-reports"
|
|
{
|
|
info "run_sdk_container finished with exit status ${rv}, printing the warnings below for a clue"
|
|
info
|
|
for file in "${sdk_run_state}/pkg-reports/"*'-warnings'; do
|
|
info "from ${file}:"
|
|
echo
|
|
cat "${file}"
|
|
echo
|
|
done
|
|
info
|
|
info 'whatever reports generated by the failed run are saved in'
|
|
info "${salvaged_dir@Q} directory"
|
|
info
|
|
} >&2
|
|
rm -rf "${salvaged_dir}"
|
|
cp -a "${sdk_run_state}/pkg-reports" "${salvaged_dir}"
|
|
unset salvaged_dir
|
|
fail "copying done, stopping now"
|
|
fi
|
|
sdk_reports_dir="${WORKDIR}/pkg-reports/${sdk_run_kind}"
|
|
top_dir="${sdk_run_state}/pkg-reports"
|
|
dir_queue=( "${top_dir}" )
|
|
all_dirs=()
|
|
all_files=()
|
|
while [[ ${#dir_queue[@]} -gt 0 ]]; do
|
|
dir=${dir_queue[0]}
|
|
dir_queue=( "${dir_queue[@]:1}" )
|
|
entry=${dir#"${top_dir}"}
|
|
if [[ -z ${entry} ]]; then
|
|
all_dirs=( "${sdk_reports_dir}" "${all_dirs[@]}" )
|
|
else
|
|
entry=${entry#/}
|
|
all_dirs=( "${sdk_reports_dir}/${entry}" "${all_dirs[@]}" )
|
|
fi
|
|
for full_path in "${dir}/"*; do
|
|
if [[ -d ${full_path} ]]; then
|
|
dir_queue+=( "${full_path}" )
|
|
else
|
|
entry=${full_path##"${top_dir}/"}
|
|
all_files+=( "${sdk_reports_dir}/${entry}" )
|
|
fi
|
|
done
|
|
done
|
|
add_cleanup \
|
|
"rm -f ${all_files[*]@Q}" \
|
|
"rmdir ${all_dirs[*]@Q}"
|
|
mv "${sdk_run_state}/pkg-reports" "${sdk_reports_dir}"
|
|
done
|
|
|
|
cp -a "${WORKDIR}/pkg-reports" "${REPORTS_DIR}/reports-from-sdk"
|
|
}
|
|
|
|
source "${PKG_AUTO_IMPL_DIR}/mvm.sh"
|
|
|
|
# pkginfo mvm is a map mvm that has the following Go-like type:
|
|
#
|
|
# map[pkg]map[slot]version
|
|
#
|
|
# pkg, slot and version are strings
|
|
|
|
# Generate a name for pkginfo mvm based on passed information.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - which state it refers to (old or new)
|
|
# 2 - architecture
|
|
# 3 - which report (board packages or SDK packages)
|
|
# 4 - name of a variable that will contain the name
|
|
function pkginfo_name() {
|
|
local which arch report
|
|
|
|
which=${1}; shift
|
|
arch=${1}; shift
|
|
report=${1}; shift
|
|
local -n pi_name_ref=${1}; shift
|
|
|
|
pi_name_ref="pkginfo_${which}_${arch}_${report//-/_}_pimap_mvm"
|
|
}
|
|
|
|
# Constructor callback used by mvm_declare for pkginfo mvms.
|
|
function pkginfo_constructor() {
|
|
mvm_mvc_map_constructor "${@}"
|
|
}
|
|
|
|
# Destructor callback used by mvm_declare for pkginfo mvms.
|
|
function pkginfo_destructor() {
|
|
mvm_mvc_map_destructor "${@}"
|
|
}
|
|
|
|
# Adder callback used by mvm_declare for pkginfo mvms.
|
|
function pkginfo_adder() {
|
|
local -n map_ref=${1}; shift
|
|
|
|
local mark
|
|
while [[ ${#} -gt 1 ]]; do
|
|
mark=${map_ref["${1}"]:-}
|
|
if [[ -n "${mark}" ]]; then
|
|
fail "multiple versions for a single slot for a package in a single report"
|
|
fi
|
|
map_ref["${1}"]=${2}
|
|
shift 2
|
|
done
|
|
}
|
|
|
|
# Creates a pkginfo mvm.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - which state it refers to (old or new)
|
|
# 2 - architecture
|
|
# 3 - which report (board packages or SDK packages)
|
|
# 4 - name of a variable that will contain the name of the created
|
|
# pkginfo mvm
|
|
function pkginfo_declare() {
|
|
local which arch report pi_name_var_name
|
|
which=${1}; shift
|
|
arch=${1}; shift
|
|
report=${1}; shift
|
|
pi_name_var_name=${1}; shift
|
|
|
|
pkginfo_name "${which}" "${arch}" "${report}" "${pi_name_var_name}"
|
|
|
|
local -a extras
|
|
extras=(
|
|
'which' "${which}"
|
|
'arch' "${arch}"
|
|
'report' "${report}"
|
|
)
|
|
|
|
mvm_declare "${!pi_name_var_name}" pkginfo -- "${extras[@]}"
|
|
}
|
|
|
|
# Destroys a pkginfo mvm.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - which state it refers to (old or new)
|
|
# 2 - architecture
|
|
# 3 - which report (board packages or SDK packages)
|
|
function pkginfo_unset() {
|
|
local which arch report
|
|
which=${1}; shift
|
|
arch=${1}; shift
|
|
report=${1}; shift
|
|
|
|
local piu_pi_name
|
|
pkginfo_name "${which}" "${arch}" "${report}" piu_pi_name
|
|
|
|
mvm_unset "${piu_pi_name}"
|
|
}
|
|
|
|
# Processes the report file associated to the passed pkginfo mvm. The
|
|
# pkginfo mvm is filled with info about packages, slots and
|
|
# versions. Additional information is put into passed package set and
|
|
# package to slots set mvm.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the pkginfo mvm variable
|
|
# 2 - name of the set variable, will contain packages in the report
|
|
# 3 - name of the set mvm variable, will contain a map of package to
|
|
# slots
|
|
function pkginfo_process_file() {
|
|
mvm_call "${1}" pkginfo_c_process_file "${@:2}"
|
|
}
|
|
|
|
# Helper function for pkginfo_process_file, used by mvm_call.
|
|
function pkginfo_c_process_file() {
|
|
local pkg_slots_set_mvm_var_name
|
|
local -n pkg_set_ref=${1}; shift
|
|
pkg_slots_set_mvm_var_name=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local which arch report
|
|
mvm_c_get_extra 'which' which
|
|
mvm_c_get_extra 'arch' arch
|
|
mvm_c_get_extra 'report' report
|
|
|
|
local report_file
|
|
case ${report}:${arch} in
|
|
"${SDK_PKGS}:arm64")
|
|
# short-circuit it, there's no arm64 sdk
|
|
return 0
|
|
;;
|
|
"${SDK_PKGS}:amd64")
|
|
report_file="${WORKDIR}/pkg-reports/${which}/${report}"
|
|
;;
|
|
"${BOARD_PKGS}:"*)
|
|
report_file="${WORKDIR}/pkg-reports/${which}/${arch}-${report}"
|
|
;;
|
|
*)
|
|
local c=${report}:${arch}
|
|
devel_warn "unknown report-architecture combination (${c@Q})"
|
|
return 0
|
|
esac
|
|
|
|
local pkg version_slot throw_away v s
|
|
while read -r pkg version_slot throw_away; do
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "${which} ${arch} ${report}: ${version_slot}"
|
|
v=${version_slot%%:*}
|
|
s=${version_slot##*:}
|
|
mvm_c_add "${pkg}" "${s}" "${v}"
|
|
pkg_set_ref["${pkg}"]='x'
|
|
mvm_add "${pkg_slots_set_mvm_var_name}" "${pkg}" "${s}"
|
|
pkg_debug_disable
|
|
done <"${report_file}"
|
|
}
|
|
|
|
# Gets a profile of the pkginfo mvm. The "profile" is a confusing
|
|
# misnomer as it has nothing to do with Gentoo profiles, but rather a
|
|
# description of the pkginfo (which is a which-arch-report triplet)
|
|
# that is used for reporting.
|
|
function pkginfo_profile() {
|
|
mvm_call "${1}" pkginfo_c_profile "${@:2}"
|
|
}
|
|
|
|
# Helper function for pkginfo_profile, used by mvm_call.
|
|
function pkginfo_c_profile() {
|
|
local profile_var_name
|
|
profile_var_name=${1}; shift
|
|
|
|
local which arch report
|
|
mvm_c_get_extra 'which' which
|
|
mvm_c_get_extra 'arch' arch
|
|
mvm_c_get_extra 'report' report
|
|
|
|
printf -v "${profile_var_name}" '%s-%s-%s' "${which}" "${arch}" "${report}"
|
|
}
|
|
|
|
# Creates pkginfo maps for all the reports and processes the
|
|
# reports. Additional information is stored in passed packages array
|
|
# and packages to slots set mvm variables.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the array variable, will contain sorted packages from
|
|
# all the reports
|
|
# 2 - name of the set mvm variable, will contain a map of package to
|
|
# slots
|
|
function read_reports() {
|
|
local all_pkgs_var_name pkg_slots_set_mvm_var_name
|
|
all_pkgs_var_name=${1}; shift
|
|
pkg_slots_set_mvm_var_name=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -A rr_all_packages_set
|
|
rr_all_packages_set=()
|
|
|
|
local arch which report rr_pimap_mvm_var_name
|
|
for arch in "${ARCHES[@]}"; do
|
|
for which in "${WHICH[@]}"; do
|
|
for report in "${REPORTS[@]}"; do
|
|
pkginfo_declare "${which}" "${arch}" "${report}" rr_pimap_mvm_var_name
|
|
pkginfo_process_file "${rr_pimap_mvm_var_name}" rr_all_packages_set "${pkg_slots_set_mvm_var_name}"
|
|
done
|
|
done
|
|
done
|
|
|
|
mapfile -t "${all_pkgs_var_name}" < <(printf '%s\n' "${!rr_all_packages_set[@]}" | sort)
|
|
}
|
|
|
|
# Destroys the pkginfo maps for all the reports.
|
|
function unset_report_mvms() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local arch which report
|
|
for arch in "${ARCHES[@]}"; do
|
|
for which in "${WHICH[@]}"; do
|
|
for report in "${REPORTS[@]}"; do
|
|
pkginfo_unset "${which}" "${arch}" "${report}"
|
|
done
|
|
done
|
|
done
|
|
}
|
|
|
|
# Finds out the highest and the lowest version from the passed versions.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of a variable where the min version will be stored
|
|
# 2 - name of a variable where the min version will be stored
|
|
# @ - the versions
|
|
function ver_min_max() {
|
|
local -n min_ref=${1}; shift
|
|
local -n max_ref=${1}; shift
|
|
|
|
local min max v
|
|
min=''
|
|
max=''
|
|
for v; do
|
|
if [[ -z ${min} ]] || ver_test "${v}" -lt "${min}"; then
|
|
min=${v}
|
|
fi
|
|
if [[ -z ${max} ]] || ver_test "${v}" -gt "${max}"; then
|
|
max=${v}
|
|
fi
|
|
done
|
|
min_ref=${min}
|
|
max_ref=${max}
|
|
}
|
|
|
|
# Does consistency checks on two profiles for a package using an
|
|
# additional map for slots information for a package. Checks if common
|
|
# slots for the package in both profiles are using the same
|
|
# versions. This is to catch version discrepancies that sometimes
|
|
# happen when e.g. a package gets stabilized for one arch, but not for
|
|
# the other.
|
|
#
|
|
# While at it, store package, slot and version range information into
|
|
# the passed map.
|
|
#
|
|
# 1 - package
|
|
# 2 - name of the pkginfo mvm for profile 1
|
|
# 3 - name of the pkginfo mvm for profile 2
|
|
# 4 - name of the pkg to slots to version range map mvm # TODO: This should be the last parameter
|
|
# 5 - name of the pkg to all slots set mvm
|
|
function consistency_check_for_package() {
|
|
local pkg pi1_pimap_mvm_var_name pi2_pimap_mvm_var_name pkg_slot_verminmax_map_mvm_var_name pkg_slots_set_mvm_var_name
|
|
pkg=${1}; shift
|
|
pi1_pimap_mvm_var_name=${1}; shift
|
|
pi2_pimap_mvm_var_name=${1}; shift
|
|
pkg_slot_verminmax_map_mvm_var_name=${1}; shift
|
|
pkg_slots_set_mvm_var_name=${1}; shift
|
|
|
|
local ccfp_slot_version1_map_var_name ccfp_slot_version2_map_var_name
|
|
mvm_get "${pi1_pimap_mvm_var_name}" "${pkg}" ccfp_slot_version1_map_var_name
|
|
mvm_get "${pi2_pimap_mvm_var_name}" "${pkg}" ccfp_slot_version2_map_var_name
|
|
|
|
local -A empty_map
|
|
empty_map=()
|
|
|
|
local -n slot_version1_map_ref=${ccfp_slot_version1_map_var_name:-empty_map}
|
|
local -n slot_version2_map_ref=${ccfp_slot_version2_map_var_name:-empty_map}
|
|
|
|
local ccfp_slots_set_var_name
|
|
mvm_get "${pkg_slots_set_mvm_var_name}" "${pkg}" ccfp_slots_set_var_name
|
|
local -n slots_set_ref=${ccfp_slots_set_var_name}
|
|
|
|
local -a profile_1_slots profile_2_slots common_slots
|
|
profile_1_slots=()
|
|
profile_2_slots=()
|
|
common_slots=()
|
|
|
|
local ccfp_profile_1 ccfp_profile_2
|
|
pkginfo_profile "${pi1_pimap_mvm_var_name}" ccfp_profile_1
|
|
pkginfo_profile "${pi2_pimap_mvm_var_name}" ccfp_profile_2
|
|
|
|
local s v1 v2 ccfp_min ccfp_max mm
|
|
pkg_debug "all slots iterated over: ${!slots_set_ref[*]}"
|
|
for s in "${!slots_set_ref[@]}"; do
|
|
v1=${slot_version1_map_ref["${s}"]:-}
|
|
v2=${slot_version2_map_ref["${s}"]:-}
|
|
pkg_debug "v1: ${v1}, v2: ${v2}"
|
|
|
|
if [[ -n ${v1} ]] && [[ -n ${v2} ]]; then
|
|
pkg_debug "${s} is a common slot for ${ccfp_profile_1} and ${ccfp_profile_2}"
|
|
common_slots+=( "${s}" )
|
|
if [[ ${v1} != "${v2}" ]]; then
|
|
pkg_warn \
|
|
"- version mismatch:" \
|
|
" - package: ${pkg}" \
|
|
" - slot: ${s}" \
|
|
" - profile 1: ${ccfp_profile_1}" \
|
|
" - version: ${v1}" \
|
|
" - profile 1: ${ccfp_profile_2}" \
|
|
" - version: ${v2}"
|
|
fi
|
|
ver_min_max ccfp_min ccfp_max "${v1}" "${v2}"
|
|
mm="${ccfp_min}:${ccfp_max}"
|
|
elif [[ -n ${v1} ]]; then
|
|
# only side1 has the slot
|
|
pkg_debug "${s} is a slot only in ${ccfp_profile_1}"
|
|
profile_1_slots+=( "${s}" )
|
|
mm="${v1}:${v1}"
|
|
elif [[ -n ${v2} ]]; then
|
|
# only side 2 has the slot
|
|
pkg_debug "${s} is a slot only in ${ccfp_profile_2}"
|
|
profile_2_slots+=( "${s}" )
|
|
mm="${v2}:${v2}"
|
|
else
|
|
pkg_debug "${s} is a slot absent from both ${ccfp_profile_1} and ${ccfp_profile_2}"
|
|
continue
|
|
fi
|
|
|
|
mvm_add "${pkg_slot_verminmax_map_mvm_var_name}" "${pkg}" "${s}" "${mm}"
|
|
done
|
|
pkg_debug "common slots: ${common_slots[*]}"
|
|
pkg_debug "profile 1 slots: ${profile_1_slots[*]}"
|
|
pkg_debug "profile 2 slots: ${profile_2_slots[*]}"
|
|
local s1 s2
|
|
if [[ ${#common_slots[@]} -gt 0 ]]; then
|
|
if [[ ${#profile_1_slots[@]} -gt 0 ]] || [[ ${#profile_2_slots[@]} -gt 0 ]]; then
|
|
pkg_warn \
|
|
"- suspicious:" \
|
|
" - package: ${pkg}" \
|
|
" - profile 1: ${ccfp_profile_1}" \
|
|
" - profile 2: ${ccfp_profile_2}" \
|
|
" - common slots: ${common_slots[*]}" \
|
|
" - slots only in profile 1: ${profile_1_slots[*]}" \
|
|
" - slots only in profile 2: ${profile_2_slots[*]}" \
|
|
" - what: there are slots that exist only on one profile while both profiles also have some common slots"
|
|
fi
|
|
elif [[ ${#profile_1_slots[@]} -eq 1 ]] && [[ ${#profile_2_slots[@]} -eq 1 ]]; then
|
|
s1=${profile_1_slots[0]}
|
|
s2=${profile_2_slots[0]}
|
|
v1=${slot_version1_map_ref["${s1}"]:-}
|
|
v2=${slot_version2_map_ref["${s2}"]:-}
|
|
if [[ ${v1} != "${v2}" ]]; then
|
|
pkg_warn \
|
|
"- version mismatch:" \
|
|
" - package ${pkg}" \
|
|
" - profile 1: ${ccfp_profile_1}" \
|
|
" - slot: ${profile_1_slots[0]}" \
|
|
" - version: ${v1}" \
|
|
" - profile 2: ${ccfp_profile_2}" \
|
|
" - slot: ${profile_2_slots[0]}" \
|
|
" - version: ${v2}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Do consistency checks for the following pairs of profiles for a passed state:
|
|
#
|
|
# ${arch} sdk <-> ${arch} board
|
|
# ${arch1} board <-> ${arch2} board
|
|
# ${arch1} sdk <-> ${arch2} sdk
|
|
#
|
|
# While at it, store package, slot and version range information into
|
|
# the passed map.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - which state should be checked (old or new)
|
|
# 2 - name of an array variable that contains all the package names
|
|
# 3 - name of the pkg to all slots set mvm variable
|
|
# 4 - name of the pkg to slot to version range map mvm variable
|
|
function consistency_checks() {
|
|
local which pkg_slots_set_mvm_var_name pkg_slot_verminmax_mvm_var_name
|
|
which=${1}; shift
|
|
local -n all_pkgs_ref=${1}; shift
|
|
pkg_slots_set_mvm_var_name=${1}; shift
|
|
pkg_slot_verminmax_mvm_var_name=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local cc_pimap_mvm_1_var_name cc_pimap_mvm_2_var_name pkg
|
|
local -a all_mvm_names=()
|
|
local arch name
|
|
# ${arch} SDK <-> ${arch} board
|
|
for arch in "${ARCHES[@]}"; do
|
|
# currently we only have amd64 SDK, so skip others
|
|
if [[ ${arch} != 'amd64' ]]; then
|
|
continue
|
|
fi
|
|
pkginfo_name "${which}" "${arch}" "${SDK_PKGS}" cc_pimap_mvm_1_var_name
|
|
pkginfo_name "${which}" "${arch}" "${BOARD_PKGS}" cc_pimap_mvm_2_var_name
|
|
name="cc_${arch}_sdk_board_pkg_slot_verminmax_map_mvm"
|
|
all_mvm_names+=( "${name}" )
|
|
mvm_declare "${name}" mvm_mvc_map
|
|
for pkg in "${all_pkgs_ref[@]}"; do
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "${which} ${arch} sdk <-> ${arch} board"
|
|
consistency_check_for_package "${pkg}" "${cc_pimap_mvm_1_var_name}" "${cc_pimap_mvm_2_var_name}" "${name}" "${pkg_slots_set_mvm_var_name}"
|
|
pkg_debug_disable
|
|
done
|
|
done
|
|
|
|
# We want to check consistency between each pair of arches.
|
|
local -a cc_all_arch_pairs
|
|
all_pairs cc_all_arch_pairs ':' "${ARCHES[@]}"
|
|
|
|
local pair arch1 arch2
|
|
# ${arch1} board <-> ${arch2} board
|
|
for pair in "${cc_all_arch_pairs[@]}"; do
|
|
arch1=${pair%:*}
|
|
arch2=${pair#*:}
|
|
pkginfo_name "${which}" "${arch1}" "${BOARD_PKGS}" cc_pimap_mvm_1_var_name
|
|
pkginfo_name "${which}" "${arch2}" "${BOARD_PKGS}" cc_pimap_mvm_2_var_name
|
|
name="cc_${arch1}_${arch2}_board_pkg_slot_verminmax_map_mvm"
|
|
all_mvm_names+=( "${name}" )
|
|
mvm_declare "${name}" mvm_mvc_map
|
|
for pkg in "${all_pkgs_ref[@]}"; do
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "${which} ${arch1} board <-> ${arch2} board"
|
|
consistency_check_for_package "${pkg}" "${cc_pimap_mvm_1_var_name}" "${cc_pimap_mvm_2_var_name}" "${name}" "${pkg_slots_set_mvm_var_name}"
|
|
pkg_debug_disable
|
|
done
|
|
done
|
|
|
|
# ${arch1} sdk <-> ${arch2} sdk
|
|
for pair in "${cc_all_arch_pairs[@]}"; do
|
|
arch1=${pair%:*}
|
|
arch2=${pair#*:}
|
|
# We currently only have amd64 SDK, so this loop will
|
|
# effectively iterate zero times. When we get the arm64 SDK
|
|
# too, this if could be dropped. Getting the listing of arm64
|
|
# packages inside amd64 SDK is going to be problem to solve,
|
|
# though.
|
|
if [[ ${arch1} != 'amd64' ]] || [[ ${arch2} != 'amd64' ]]; then
|
|
continue
|
|
fi
|
|
pkginfo_name "${which}" "${arch1}" "${SDK_PKGS}" cc_pimap_mvm_1_var_name
|
|
pkginfo_name "${which}" "${arch2}" "${SDK_PKGS}" cc_pimap_mvm_2_var_name
|
|
name="cc_${arch1}_${arch2}_sdk_pkg_slot_verminmax_map_mvm"
|
|
all_mvm_names+=( "${name}" )
|
|
mvm_declare "${name}" mvm_mvc_map
|
|
for pkg in "${all_pkgs_ref[@]}"; do
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "${which} ${arch1} sdk <-> ${arch2} sdk"
|
|
consistency_check_for_package "${pkg}" "${cc_pimap_mvm_1_var_name}" "${cc_pimap_mvm_2_var_name}" "${name}" "${pkg_slots_set_mvm_var_name}"
|
|
pkg_debug_disable
|
|
done
|
|
done
|
|
|
|
local cc_slots_set_var_name s cc_min cc_max verminmax
|
|
local -A empty_map=()
|
|
local -a verminmax_map_var_names verminmaxes
|
|
local cc_slot_verminmax_map_var_name
|
|
for pkg in "${all_pkgs_ref[@]}"; do
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "${which} verminmax stuff"
|
|
verminmax_map_var_names=()
|
|
for name in "${all_mvm_names[@]}"; do
|
|
mvm_get "${name}" "${pkg}" cc_slot_verminmax_map_var_name
|
|
verminmax_map_var_names+=("${cc_slot_verminmax_map_var_name}")
|
|
done
|
|
if pkg_debug_enabled; then
|
|
for name in "${verminmax_map_var_names[@]}"; do
|
|
local -n slot_verminmax_map_ref=${name:-empty_map}
|
|
pkg_debug_print "all slots in ${name}: ${!slot_verminmax_map_ref[*]}"
|
|
pkg_debug_print "all vmms in ${name}: ${slot_verminmax_map_ref[*]}"
|
|
unset -n slot_verminmax_map_ref
|
|
done
|
|
fi
|
|
mvm_get "${pkg_slots_set_mvm_var_name}" "${pkg}" cc_slots_set_var_name
|
|
local -n slots_set_ref=${cc_slots_set_var_name}
|
|
pkg_debug "all slots iterated over: ${!slots_set_ref[*]}"
|
|
for s in "${!slots_set_ref[@]}"; do
|
|
verminmaxes=()
|
|
for name in "${verminmax_map_var_names[@]}"; do
|
|
local -n slot_verminmax_map_ref=${name:-empty_map}
|
|
verminmax=${slot_verminmax_map_ref["${s}"]:-}
|
|
if [[ -n ${verminmax} ]]; then
|
|
verminmaxes+=( "${verminmax}" )
|
|
fi
|
|
unset -n slot_verminmax_map_ref
|
|
done
|
|
if [[ ${#verminmaxes[@]} -gt 1 ]]; then
|
|
ver_min_max cc_min cc_max "${verminmaxes[@]%%:*}" "${verminmaxes[@]##*:}"
|
|
verminmax="${cc_min}:${cc_max}"
|
|
elif [[ ${#verminmaxes[@]} -eq 1 ]]; then
|
|
verminmax=${verminmaxes[0]}
|
|
else
|
|
continue
|
|
fi
|
|
pkg_debug "adding vmm ${verminmax} for slot ${s}"
|
|
mvm_add "${pkg_slot_verminmax_mvm_var_name}" "${pkg}" "${s}" "${verminmax}"
|
|
done
|
|
unset -n slots_set_ref
|
|
pkg_debug_disable
|
|
done
|
|
for name in "${all_mvm_names[@]}"; do
|
|
mvm_unset "${name}"
|
|
done
|
|
}
|
|
|
|
# Read a report describing from which repo the package came and store
|
|
# in the passed map.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of a map variable, will contain a mapping of package name
|
|
# to repository name
|
|
function read_package_sources() {
|
|
local -n package_sources_map_ref=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -a files=()
|
|
local which arch
|
|
for which in "${WHICH[@]}"; do
|
|
files+=( "${WORKDIR}/pkg-reports/${which}/sdk-package-repos" )
|
|
for arch in "${ARCHES[@]}"; do
|
|
files+=( "${WORKDIR}/pkg-reports/${which}/${arch}-board-package-repos" )
|
|
done
|
|
done
|
|
|
|
local file pkg repo saved_repo
|
|
for file in "${files[@]}"; do
|
|
while read -r pkg repo; do
|
|
saved_repo=${package_sources_map_ref["${pkg}"]:-}
|
|
if [[ -n ${saved_repo} ]]; then
|
|
if [[ ${saved_repo} != "${repo}" ]]; then
|
|
pkg_warn \
|
|
'- different repos used for the package:' \
|
|
" - package: ${pkg}" \
|
|
' - repos:' \
|
|
" - ${saved_repo}" \
|
|
" - ${repo}"
|
|
fi
|
|
else
|
|
package_sources_map_ref["${pkg}"]=${repo}
|
|
fi
|
|
done <"${file}"
|
|
done
|
|
}
|
|
|
|
# This monstrosity takes renames map and package tags information,
|
|
# reads the reports, does consistency checks and uses the information
|
|
# from previous steps to write out package differences between the old
|
|
# and new state into the reports directory.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the renames map variable
|
|
# 2 - name of the package tags map mvm variable
|
|
function handle_package_changes() {
|
|
local pkg_to_tags_mvm_var_name
|
|
local -n renamed_old_to_new_map_ref=${1}; shift
|
|
pkg_to_tags_mvm_var_name=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -a hpc_all_pkgs
|
|
hpc_all_pkgs=()
|
|
|
|
# map[package]map[slot]interface{}
|
|
mvm_declare hpc_pkg_slots_set_mvm mvm_mvc_set
|
|
read_reports hpc_all_pkgs hpc_pkg_slots_set_mvm
|
|
|
|
# map[package]map[slot]string (string being "min version:max version")
|
|
mvm_declare hpc_old_pkg_slot_verminmax_map_mvm mvm_mvc_map
|
|
mvm_declare hpc_new_pkg_slot_verminmax_map_mvm mvm_mvc_map
|
|
consistency_checks old hpc_all_pkgs hpc_pkg_slots_set_mvm hpc_old_pkg_slot_verminmax_map_mvm
|
|
consistency_checks new hpc_all_pkgs hpc_pkg_slots_set_mvm hpc_new_pkg_slot_verminmax_map_mvm
|
|
|
|
unset_report_mvms
|
|
|
|
# TODO: when we handle moving packages between repos, then there
|
|
# should be two maps, for old and new state
|
|
local -A hpc_package_sources_map
|
|
hpc_package_sources_map=()
|
|
read_package_sources hpc_package_sources_map
|
|
|
|
mkdir -p "${REPORTS_DIR}/updates"
|
|
|
|
local -a old_pkgs new_pkgs
|
|
old_pkgs=()
|
|
new_pkgs=()
|
|
|
|
# The following loop fills the old_pkgs and new_pkgs arrays sorted
|
|
# package names, where old package name at index I has it's new
|
|
# counterpart at the same index. For the most part, both old and
|
|
# new names will be the same, since the renames are rather rare.
|
|
|
|
# map[package]index
|
|
local -A added_pkg_to_index_map=()
|
|
local pkg other
|
|
for pkg in "${hpc_all_pkgs[@]}"; do
|
|
other=${renamed_old_to_new_map_ref["${pkg}"]:-}
|
|
if [[ -n "${other}" ]]; then
|
|
# There seem be a rename from ${pkg} to ${other}
|
|
pkg_debug_enable "${pkg}" "${other}"
|
|
pkg_debug "${pkg} renamed to ${other}"
|
|
pkg_debug_disable
|
|
local other_idx
|
|
other_idx=${added_pkg_to_index_map["${other}"]:-}
|
|
if [[ -n ${other_idx} ]]; then
|
|
# Looks like we have already processed the ${other}
|
|
# name. In this case, both old_pkgs[${other_idx}] and
|
|
# new_pkgs[${other_idx}] should just be
|
|
# ${other}. Since ${pkg} is the old name (${other} is
|
|
# new), we update old_pkgs to hold the old name. Just
|
|
# make sure that old_pkgs indeed had the new name
|
|
# first.
|
|
local other_old
|
|
other_old=${old_pkgs["${other_idx}"]}
|
|
if [[ ${other_old} = "${other}" ]]; then
|
|
old_pkgs["${other_idx}"]=${pkg}
|
|
else
|
|
manual \
|
|
'- there seem to be two old packages in our repos that are supposed to be renamed to the same name:' \
|
|
" - old package 1: ${pkg}" \
|
|
" - old package 2: ${other_old}" \
|
|
" - new package: ${other}"
|
|
fi
|
|
unset other_idx other_old
|
|
continue
|
|
else
|
|
unset other_idx
|
|
fi
|
|
|
|
# Looks like we haven't processed the ${other} name yet,
|
|
# it probably will come up later, which will be taken care
|
|
# of by the "pkg_debug 'handled already through some
|
|
# rename'" part below, after else.
|
|
|
|
local pkg_idx
|
|
# doesn't matter if it's length of new_pkgs or old_pkgs,
|
|
# both are assumed to have the same length
|
|
pkg_idx=${#old_pkgs[@]}
|
|
old_pkgs+=("${pkg}")
|
|
new_pkgs+=("${other}")
|
|
added_pkg_to_index_map["${pkg}"]=${pkg_idx}
|
|
added_pkg_to_index_map["${other}"]=${pkg_idx}
|
|
unset pkg_idx
|
|
else
|
|
pkg_debug_enable "${pkg}"
|
|
if [[ -n ${added_pkg_to_index_map["${pkg}"]:-} ]]; then
|
|
pkg_debug 'handled already through some rename'
|
|
else
|
|
pkg_debug "${pkg} is not renamed"
|
|
local pkg_idx
|
|
# doesn't matter if it's length of new_pkgs or old_pkgs,
|
|
# both are assumed to have the same length
|
|
pkg_idx=${#old_pkgs[@]}
|
|
old_pkgs+=("${pkg}")
|
|
new_pkgs+=("${pkg}")
|
|
added_pkg_to_index_map["${pkg}"]=${pkg_idx}
|
|
fi
|
|
pkg_debug_disable
|
|
fi
|
|
done
|
|
unset added_pkg_to_index_map
|
|
|
|
# The loop below goes over the pairs of old and new package
|
|
# names. For each name there will be some checks done (like does
|
|
# this package even exist). Each name in the pair has a set of
|
|
# used slots associated with it (the most common situation is that
|
|
# each have just one slot, but there are some packages that we
|
|
# have multiple slots installed, like
|
|
# app-text/docbook-xml-dtd). Some of the slots will appear in both
|
|
# old and new package name, sometimes there will be slots
|
|
# available only in the old state or only in the new state. Each
|
|
# slot for each package name has an associated min version and max
|
|
# version. So for common slots we usually compare min version for
|
|
# old package with max version for new package. Any
|
|
# inconsistencies with the versions should be reported by
|
|
# now. There are some edge cases with the slots that are not
|
|
# handled by the automation - in such cases there will be a
|
|
# "manual action needed" report.
|
|
|
|
local pkg_idx=0
|
|
local old_name new_name old_repo new_repo
|
|
local hpc_old_slots_set_var_name hpc_new_slots_set_var_name
|
|
local hpc_old_slot_verminmax_map_var_name hpc_new_slot_verminmax_map_var_name
|
|
local s hpc_old_s hpc_new_s
|
|
local old_verminmax new_verminmax
|
|
local old_version new_version
|
|
local hpc_cmp_result
|
|
local -A hpc_only_old_slots_set hpc_only_new_slots_set hpc_common_slots_set
|
|
local -a lines
|
|
local hpc_update_dir
|
|
local -A empty_map_or_set
|
|
local hpc_changed hpc_slot_changed hpc_update_dir_non_slot hpc_category_dir
|
|
local which slots_set_var_name_var_name slot_verminmax_map_var_name_var_name filtered_slots_set_var_name verminmax
|
|
local -A hpc_old_filtered_slots_set hpc_new_filtered_slots_set
|
|
empty_map_or_set=()
|
|
while [[ ${pkg_idx} -lt ${#old_pkgs[@]} ]]; do
|
|
old_name=${old_pkgs["${pkg_idx}"]}
|
|
new_name=${new_pkgs["${pkg_idx}"]}
|
|
if [[ ${old_name} = "${new_name}" ]]; then
|
|
info "handling update of ${new_name}"
|
|
else
|
|
info "handling update of ${new_name} (renamed from ${old_name})"
|
|
fi
|
|
pkg_debug_enable "${old_name}" "${new_name}"
|
|
pkg_debug 'handling updates'
|
|
pkg_idx=$((pkg_idx + 1))
|
|
old_repo=${hpc_package_sources_map["${old_name}"]:-}
|
|
new_repo=${hpc_package_sources_map["${new_name}"]:-}
|
|
if [[ -z ${old_repo} ]]; then
|
|
pkg_warn \
|
|
'- package not in old state' \
|
|
" - old package: ${old_name}" \
|
|
" - new package: ${new_name}"
|
|
pkg_debug_disable
|
|
continue
|
|
fi
|
|
if [[ -z ${new_repo} ]]; then
|
|
pkg_warn \
|
|
'- package not in new state' \
|
|
" - old package: ${old_name}" \
|
|
" - new package: ${new_name}"
|
|
pkg_debug_disable
|
|
continue
|
|
fi
|
|
if [[ ${old_repo} != "${new_repo}" ]]; then
|
|
# This is pretty much an arbitrary limitation and I don't
|
|
# remember any more why we have it.
|
|
pkg_warn \
|
|
'- package has moved between repos? unsupported for now' \
|
|
" - old package and repo: ${old_name} ${old_repo}" \
|
|
" - new package and repo: ${new_name} ${new_repo}"
|
|
pkg_debug_disable
|
|
continue
|
|
fi
|
|
if [[ ${new_repo} != 'portage-stable' ]]; then
|
|
# coreos-overlay packages will need a separate handling
|
|
pkg_debug 'not a portage-stable package'
|
|
pkg_debug_disable
|
|
continue
|
|
fi
|
|
|
|
mvm_get hpc_pkg_slots_set_mvm "${old_name}" hpc_old_slots_set_var_name
|
|
mvm_get hpc_pkg_slots_set_mvm "${new_name}" hpc_new_slots_set_var_name
|
|
: "${hpc_old_slots_set_var_name:=empty_map_or_set}"
|
|
: "${hpc_new_slots_set_var_name:=empty_map_or_set}"
|
|
mvm_get hpc_old_pkg_slot_verminmax_map_mvm "${old_name}" hpc_old_slot_verminmax_map_var_name
|
|
mvm_get hpc_new_pkg_slot_verminmax_map_mvm "${new_name}" hpc_new_slot_verminmax_map_var_name
|
|
: "${hpc_old_slot_verminmax_map_var_name:=empty_map_or_set}"
|
|
: "${hpc_new_slot_verminmax_map_var_name:=empty_map_or_set}"
|
|
local -n old_slot_verminmax_map_ref=${hpc_old_slot_verminmax_map_var_name}
|
|
local -n new_slot_verminmax_map_ref=${hpc_new_slot_verminmax_map_var_name}
|
|
|
|
# Filter out slots for old and new package name that comes out
|
|
# without versions. This may happen, because we collect all
|
|
# slot names for the package name, without differentiating
|
|
# whether such a slot existed in the old state or still exists
|
|
# in the new state. If slot didn't exist in either one then it
|
|
# will come without version information. Such a slot is
|
|
# dropped. An example would be an update of sys-devel/binutils
|
|
# from 2.42 to 2.43. Each binutils version has a separate slot
|
|
# which is named after the version. So the slots set would be
|
|
# (2.42 2.43). Slot "2.42" does not exist in the new state any
|
|
# more, "2.43" does not yet exist in the old state. So those
|
|
# slots for those states will be dropped. Thus filtered slots
|
|
# set for the old state will only contain 2.42, while for the
|
|
# new state - only 2.43.
|
|
for which in old new; do
|
|
slots_set_var_name_var_name="hpc_${which}_slots_set_var_name"
|
|
slot_verminmax_map_var_name_var_name="hpc_${which}_slot_verminmax_map_var_name"
|
|
filtered_slots_set_var_name="hpc_${which}_filtered_slots_set"
|
|
local -n which_slots_set_ref=${!slots_set_var_name_var_name}
|
|
local -n which_slot_verminmax_map_ref=${!slot_verminmax_map_var_name_var_name}
|
|
local -n which_filtered_slots_set_ref=${filtered_slots_set_var_name}
|
|
pkg_debug "all unfiltered slots for ${which} name: ${!which_slots_set_ref[*]}"
|
|
which_filtered_slots_set_ref=()
|
|
for s in "${!which_slots_set_ref[@]}"; do
|
|
verminmax=${which_slot_verminmax_map_ref["${s}"]:-}
|
|
if [[ -n ${verminmax} ]]; then
|
|
which_filtered_slots_set_ref["${s}"]=x
|
|
fi
|
|
done
|
|
pkg_debug "all filtered slots for ${which} name: ${!which_filtered_slots_set_ref[*]}"
|
|
unset -n which_filtered_slots_set_ref
|
|
unset -n which_slot_verminmax_map_ref
|
|
unset -n which_slots_set_ref
|
|
done
|
|
|
|
hpc_only_old_slots_set=()
|
|
hpc_only_new_slots_set=()
|
|
hpc_common_slots_set=()
|
|
sets_split \
|
|
hpc_old_filtered_slots_set hpc_new_filtered_slots_set \
|
|
hpc_only_old_slots_set hpc_only_new_slots_set hpc_common_slots_set
|
|
pkg_debug "all common slots: ${!hpc_common_slots_set[*]}"
|
|
pkg_debug "slots only for old name: ${!hpc_only_old_slots_set[*]}"
|
|
pkg_debug "slots only for new name: ${!hpc_only_new_slots_set[*]}"
|
|
|
|
update_dir_non_slot "${new_name}" hpc_update_dir_non_slot
|
|
mkdir -p "${hpc_update_dir_non_slot}"
|
|
|
|
generate_non_ebuild_diffs "${OLD_PORTAGE_STABLE}" "${NEW_PORTAGE_STABLE}" "${old_name}" "${new_name}"
|
|
generate_full_diffs "${OLD_PORTAGE_STABLE}" "${NEW_PORTAGE_STABLE}" "${old_name}" "${new_name}"
|
|
generate_package_mention_reports "${NEW_STATE}" "${old_name}" "${new_name}"
|
|
|
|
hpc_changed=
|
|
pkg_debug 'going over common slots'
|
|
for s in "${!hpc_common_slots_set[@]}"; do
|
|
old_verminmax=${old_slot_verminmax_map_ref["${s}"]:-}
|
|
new_verminmax=${new_slot_verminmax_map_ref["${s}"]:-}
|
|
pkg_debug "slot: ${s}, vmm old: ${old_verminmax}, vmm new: ${new_verminmax}"
|
|
if [[ -z "${old_verminmax}" ]] || [[ -z "${new_verminmax}" ]]; then
|
|
devel_warn \
|
|
"- no minmax info available for old and/or new:" \
|
|
" - old package: ${old_name}" \
|
|
" - slot: ${s}" \
|
|
" - minmax: ${old_verminmax}" \
|
|
" - new package: ${new_name}" \
|
|
" - slot: ${s}" \
|
|
" - minmax: ${new_verminmax}"
|
|
continue
|
|
fi
|
|
update_dir "${new_name}" "${s}" "${s}" hpc_update_dir
|
|
mkdir -p "${hpc_update_dir}"
|
|
old_version=${old_verminmax%%:*}
|
|
new_version=${new_verminmax##*:}
|
|
gentoo_ver_cmp_out "${new_version}" "${old_version}" hpc_cmp_result
|
|
case ${hpc_cmp_result} in
|
|
"${GV_GT}")
|
|
handle_pkg_update "${pkg_to_tags_mvm_var_name}" "${old_name}" "${new_name}" "${s}" "${s}" "${old_version}" "${new_version}"
|
|
hpc_changed=x
|
|
;;
|
|
"${GV_EQ}")
|
|
hpc_slot_changed=
|
|
handle_pkg_as_is "${pkg_to_tags_mvm_var_name}" "${old_name}" "${new_name}" "${s}" "${s}" "${old_version}" hpc_slot_changed
|
|
if [[ -z ${hpc_slot_changed} ]]; then
|
|
rm -rf "${hpc_update_dir}"
|
|
else
|
|
hpc_changed=x
|
|
fi
|
|
;;
|
|
"${GV_LT}")
|
|
handle_pkg_downgrade "${pkg_to_tags_mvm_var_name}" "${old_name}" "${new_name}" "${s}" "${s}" "${old_version}" "${new_version}"
|
|
hpc_changed=x
|
|
;;
|
|
esac
|
|
done
|
|
# A "sys-devel/binutils update" case - one old slot and one
|
|
# new slot, but different from each other.
|
|
if [[ ${#hpc_only_old_slots_set[@]} -eq 1 ]] && [[ ${#hpc_only_new_slots_set[@]} -eq 1 ]]; then
|
|
get_first_from_set hpc_only_old_slots_set hpc_old_s
|
|
old_verminmax=${old_slot_verminmax_map_ref["${hpc_old_s}"]:-}
|
|
get_first_from_set hpc_only_new_slots_set hpc_new_s
|
|
new_verminmax=${new_slot_verminmax_map_ref["${hpc_new_s}"]:-}
|
|
pkg_debug "jumping from slot ${hpc_old_s} (vmm: ${old_verminmax}) to slot ${hpc_new_s} (vmm: ${new_verminmax})"
|
|
if [[ -z "${old_verminmax}" ]] || [[ -z "${new_verminmax}" ]]; then
|
|
devel_warn \
|
|
"- no verminmax info available for old and/or new:" \
|
|
" - old package: ${old_name}" \
|
|
" - slot: ${hpc_old_s}" \
|
|
" - minmax: ${old_verminmax}" \
|
|
" - new package: ${new_name}" \
|
|
" - slot: ${hpc_new_s}" \
|
|
" - minmax: ${new_verminmax}"
|
|
else
|
|
update_dir "${new_name}" "${hpc_old_s}" "${hpc_new_s}" hpc_update_dir
|
|
mkdir -p "${hpc_update_dir}"
|
|
old_version=${old_verminmax%%:*}
|
|
new_version=${new_verminmax##*:}
|
|
gentoo_ver_cmp_out "${new_version}" "${old_version}" hpc_cmp_result
|
|
case ${hpc_cmp_result} in
|
|
"${GV_GT}")
|
|
handle_pkg_update "${pkg_to_tags_mvm_var_name}" "${old_name}" "${new_name}" "${hpc_old_s}" "${hpc_new_s}" "${old_version}" "${new_version}"
|
|
hpc_changed=x
|
|
;;
|
|
"${GV_EQ}")
|
|
hpc_slot_changed=
|
|
handle_pkg_as_is "${pkg_to_tags_mvm_var_name}" "${old_name}" "${new_name}" "${hpc_old_s}" "${hpc_new_s}" "${old_version}" hpc_slot_changed
|
|
if [[ -z ${hpc_slot_changed} ]]; then
|
|
rm -rf "${hpc_update_dir}"
|
|
else
|
|
hpc_changed=x
|
|
fi
|
|
;;
|
|
"${GV_LT}")
|
|
handle_pkg_downgrade "${pkg_to_tags_mvm_var_name}" "${old_name}" "${new_name}" "${hpc_old_s}" "${hpc_new_s}" "${old_version}" "${new_version}"
|
|
hpc_changed=x
|
|
;;
|
|
esac
|
|
fi
|
|
elif [[ ${#hpc_only_old_slots_set[@]} -gt 0 ]] || [[ ${#hpc_only_new_slots_set[@]} -gt 0 ]]; then
|
|
pkg_debug 'complicated slots situation, needs manual intervention'
|
|
lines=(
|
|
'- handle package update:'
|
|
' - old package name:'
|
|
" - name: ${old_name}"
|
|
' - slots:'
|
|
)
|
|
for s in "${!hpc_old_filtered_slots_set[@]}"; do
|
|
old_verminmax=${old_slot_verminmax_map_ref["${s}"]:-}
|
|
lines+=(" - ${s}, minmax: ${old_verminmax}")
|
|
done
|
|
lines+=(
|
|
' - new package name:'
|
|
" - name: ${new_name}"
|
|
' - slots:'
|
|
)
|
|
for s in "${!hpc_new_filtered_slots_set[@]}"; do
|
|
new_verminmax=${new_slot_verminmax_map_ref["${s}"]:-}
|
|
lines+=(" - ${s}, minmax: ${new_verminmax}")
|
|
done
|
|
manual "${lines[@]}"
|
|
fi
|
|
unset -n new_slot_verminmax_map_ref old_slot_verminmax_map_ref
|
|
# if nothing changed, drop the entire update directory for the
|
|
# package, and possibly the parent directory if it became
|
|
# empty (parent directory being a category directory, like
|
|
# sys-apps)
|
|
if [[ -z ${hpc_changed} ]]; then
|
|
pkg_debug 'no changes, dropping reports'
|
|
rm -rf "${hpc_update_dir_non_slot}"
|
|
dirname_out "${hpc_update_dir_non_slot}" hpc_category_dir
|
|
if dir_is_empty "${hpc_category_dir}"; then
|
|
rmdir "${hpc_category_dir}"
|
|
fi
|
|
fi
|
|
pkg_debug_disable
|
|
done
|
|
|
|
mvm_unset hpc_new_pkg_slot_verminmax_map_mvm
|
|
mvm_unset hpc_old_pkg_slot_verminmax_map_mvm
|
|
mvm_unset hpc_pkg_slots_set_mvm
|
|
}
|
|
|
|
# Gets the first item from the passed set.
|
|
#
|
|
# Mostly intended to "unwrap" a single-element set.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the set variable
|
|
# 2 - name of the variable where the element will be stored
|
|
function get_first_from_set() {
|
|
local -n set_ref=${1}; shift
|
|
local -n return_ref=${1}; shift
|
|
|
|
local item
|
|
for item in "${!set_ref[@]}"; do
|
|
return_ref=${item}
|
|
return 0
|
|
done
|
|
return_ref=''
|
|
}
|
|
|
|
# Write information to reports directory about the package update
|
|
# (meaning specifically that the new version is greater than the old
|
|
# one).
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the package tags set mvm variable
|
|
# 2 - old package name
|
|
# 3 - new package name
|
|
# 4 - old package slot
|
|
# 5 - new package slot
|
|
# 6 - old version
|
|
# 7 - new version
|
|
function handle_pkg_update() {
|
|
local pkg_to_tags_mvm_var_name old_pkg new_pkg old_s new_s old new
|
|
pkg_to_tags_mvm_var_name=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
old_s=${1}; shift
|
|
new_s=${1}; shift
|
|
old=${1}; shift
|
|
new=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local old_no_r new_no_r
|
|
old_no_r=${old%-r+([0-9])}
|
|
new_no_r=${new%-r+([0-9])}
|
|
|
|
local pkg_name
|
|
pkg_name=${new_pkg#*/}
|
|
local -a lines
|
|
lines=( "0:from ${old} to ${new}")
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
lines+=( "0:renamed from ${old_pkg}" )
|
|
fi
|
|
generate_ebuild_diff "${OLD_PORTAGE_STABLE}" "${NEW_PORTAGE_STABLE}" "${old_pkg}" "${new_pkg}" "${old_s}" "${new_s}" "${old}" "${new}"
|
|
|
|
local hpu_update_dir hpu_update_dir_non_slot
|
|
update_dir_non_slot "${new_pkg}" hpu_update_dir_non_slot
|
|
update_dir "${new_pkg}" "${old_s}" "${new_s}" hpu_update_dir
|
|
|
|
local diff_report_name
|
|
gen_varname diff_report_name
|
|
diff_report_declare "${diff_report_name}"
|
|
generate_cache_diff_report "${diff_report_name}" "${WORKDIR}/pkg-reports/old/portage-stable-cache" "${WORKDIR}/pkg-reports/new/portage-stable-cache" "${old_pkg}" "${new_pkg}" "${old}" "${new}"
|
|
|
|
local -n diff_report_ref=${diff_report_name}
|
|
local -n diff_lines_ref=${diff_report_ref[${DR_LINES_IDX}]}
|
|
lines+=( "${diff_lines_ref[@]}" )
|
|
unset -n diff_lines_ref
|
|
unset -n diff_report_ref
|
|
diff_report_unset "${diff_report_name}"
|
|
|
|
if [[ -s "${hpu_update_dir}/ebuild.diff" ]]; then
|
|
lines+=( '0:TODO: review ebuild.diff' )
|
|
fi
|
|
if [[ -s "${hpu_update_dir_non_slot}/other.diff" ]]; then
|
|
lines+=( '0:TODO: review other.diff' )
|
|
fi
|
|
lines+=( '0:TODO: review occurences' )
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
lines+=( '0:TODO: review occurences-for-old-name' )
|
|
fi
|
|
|
|
local -a hpu_tags
|
|
tags_for_pkg "${pkg_to_tags_mvm_var_name}" "${new_pkg}" hpu_tags
|
|
|
|
if ver_test "${new_no_r}" -gt "${old_no_r}"; then
|
|
# version bump
|
|
generate_changelog_entry_stub "${pkg_name}" "${new_no_r}" "${hpu_tags[@]}"
|
|
lines+=( '0:release notes: TODO' )
|
|
fi
|
|
|
|
generate_summary_stub "${new_pkg}" "${hpu_tags[@]}" -- "${lines[@]}"
|
|
}
|
|
|
|
# Write information to reports directory about the modified package
|
|
# (meaning specifically that the new version is equal than the old
|
|
# one).
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the package tags set mvm variable
|
|
# 2 - old package name
|
|
# 3 - new package name
|
|
# 4 - old package slot
|
|
# 5 - new package slot
|
|
# 6 - version
|
|
# 7 - name of a "bool" variable where info is stored if relevant files
|
|
# has changed (empty means nothing changed, non-empty means
|
|
# something has changed)
|
|
function handle_pkg_as_is() {
|
|
local pkg_to_tags_mvm_var_name old_pkg new_pkg old_s new_s v
|
|
pkg_to_tags_mvm_var_name=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
old_s=${1}; shift
|
|
new_s=${1}; shift
|
|
v=${1}; shift
|
|
local -n changed_ref=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local hpai_update_dir
|
|
update_dir "${new_pkg}" "${old_s}" "${new_s}" hpai_update_dir
|
|
|
|
local pkg_name
|
|
pkg_name=${new_pkg#/}
|
|
local -a lines
|
|
lines=( "0:still at ${v}" )
|
|
|
|
local renamed
|
|
renamed=
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
lines+=( "0:renamed from ${old_pkg}" )
|
|
renamed=x
|
|
fi
|
|
generate_ebuild_diff "${OLD_PORTAGE_STABLE}" "${NEW_PORTAGE_STABLE}" "${old_pkg}" "${new_pkg}" "${old_s}" "${new_s}" "${v}" "${v}"
|
|
local hpai_update_dir_non_slot hpai_update_dir
|
|
update_dir_non_slot "${new_pkg}" hpai_update_dir_non_slot
|
|
update_dir "${new_pkg}" "${old_s}" "${new_s}" hpai_update_dir
|
|
local modified
|
|
modified=
|
|
|
|
local diff_report_name
|
|
gen_varname diff_report_name
|
|
diff_report_declare "${diff_report_name}"
|
|
generate_cache_diff_report "${diff_report_name}" "${WORKDIR}/pkg-reports/old/portage-stable-cache" "${WORKDIR}/pkg-reports/new/portage-stable-cache" "${old_pkg}" "${new_pkg}" "${v}" "${v}"
|
|
|
|
local -n diff_report_ref=${diff_report_name}
|
|
local -n diff_lines_ref=${diff_report_ref[${DR_LINES_IDX}]}
|
|
if [[ ${#diff_lines_ref[@]} -gt 0 ]]; then
|
|
lines+=( "${diff_lines_ref[@]}" )
|
|
modified=x
|
|
fi
|
|
unset -n diff_lines_ref
|
|
unset -n diff_report_ref
|
|
diff_report_unset "${diff_report_name}"
|
|
|
|
if [[ -s "${hpai_update_dir}/ebuild.diff" ]]; then
|
|
lines+=( '0:TODO: review ebuild.diff' )
|
|
modified=x
|
|
fi
|
|
if [[ -s "${hpai_update_dir_non_slot}/other.diff" ]]; then
|
|
lines+=( '0:TODO: review other.diff' )
|
|
modified=x
|
|
fi
|
|
if [[ -z ${renamed} ]] && [[ -z ${modified} ]]; then
|
|
# Nothing relevant has changed, return early.
|
|
return 0
|
|
fi
|
|
changed_ref=x
|
|
lines+=( '0:TODO: review occurences' )
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
lines+=( '0:TODO: review occurences-for-old-name' )
|
|
fi
|
|
|
|
local -a hpai_tags
|
|
tags_for_pkg "${pkg_to_tags_mvm_var_name}" "${new_pkg}" hpai_tags
|
|
generate_summary_stub "${new_pkg}" "${hpai_tags[@]}" -- "${lines[@]}"
|
|
}
|
|
|
|
# Write information to reports directory about the package downgrade
|
|
# (meaning specifically that the new version is lower than the old
|
|
# one).
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the package tags set mvm variable
|
|
# 2 - old package name
|
|
# 3 - new package name
|
|
# 4 - old package slot
|
|
# 5 - new package slot
|
|
# 6 - old version
|
|
# 7 - new version
|
|
function handle_pkg_downgrade() {
|
|
local pkg_to_tags_mvm_var_name old_pkg new_pkg old_s new_s old new
|
|
pkg_to_tags_mvm_var_name=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
old_s=${1}; shift
|
|
new_s=${1}; shift
|
|
old=${1}; shift
|
|
new=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local old_no_r new_no_r
|
|
old_no_r=${old%-r+([0-9])}
|
|
new_no_r=${new%-r+([0-9])}
|
|
|
|
local pkg_name
|
|
pkg_name=${new_pkg#*/}
|
|
local -a lines
|
|
lines=( "0:downgraded from ${old} to ${new}" )
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
lines+=( "0:renamed from ${old_pkg}" )
|
|
fi
|
|
generate_ebuild_diff "${OLD_PORTAGE_STABLE}" "${NEW_PORTAGE_STABLE}" "${old_pkg}" "${new_pkg}" "${old_s}" "${new_s}" "${old}" "${new}"
|
|
|
|
local hpd_update_dir hpd_update_dir_non_slot
|
|
update_dir_non_slot "${new_pkg}" hpd_update_dir_non_slot
|
|
update_dir "${new_pkg}" "${old_s}" "${new_s}" hpd_update_dir
|
|
|
|
local diff_report_name
|
|
gen_varname diff_report_name
|
|
diff_report_declare "${diff_report_name}"
|
|
generate_cache_diff_report "${diff_report_name}" "${WORKDIR}/pkg-reports/old/portage-stable-cache" "${WORKDIR}/pkg-reports/new/portage-stable-cache" "${old_pkg}" "${new_pkg}" "${old}" "${new}"
|
|
|
|
local -n diff_report_ref=${diff_report_name}
|
|
local -n diff_lines_ref=${diff_report_ref[${DR_LINES_IDX}]}
|
|
lines+=( "${diff_lines_ref[@]}" )
|
|
unset -n diff_lines_ref
|
|
unset -n diff_report_ref
|
|
diff_report_unset "${diff_report_name}"
|
|
|
|
if [[ -s "${hpd_update_dir}/ebuild.diff" ]]; then
|
|
lines+=( '0:TODO: review ebuild.diff' )
|
|
fi
|
|
if [[ -s "${hpd_update_dir_non_slot}/other.diff" ]]; then
|
|
lines+=( '0:TODO: review other.diff' )
|
|
fi
|
|
lines+=( '0:TODO: review occurences' )
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
lines+=( '0:TODO: review occurences-for-old-name' )
|
|
fi
|
|
|
|
local -a hpd_tags
|
|
tags_for_pkg "${pkg_to_tags_mvm_var_name}" "${new_pkg}" hpd_tags
|
|
|
|
if ver_test "${new_no_r}" -lt "${old_no_r}"; then
|
|
# version bump
|
|
generate_changelog_entry_stub "${pkg_name}" "${new_no_r}" "${hpd_tags[@]}"
|
|
lines+=( "0:release notes: TODO" )
|
|
fi
|
|
|
|
generate_summary_stub "${new_pkg}" "${hpd_tags[@]}" -- "${lines[@]}"
|
|
}
|
|
|
|
# Retrieves tags for a package.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - name of the package tags set mvm variable
|
|
# 2 - package name
|
|
# 3 - name of the array variable, where the tags will be stored
|
|
function tags_for_pkg() {
|
|
local pkg_to_tags_mvm_var_name pkg
|
|
pkg_to_tags_mvm_var_name=${1}; shift
|
|
pkg=${1}; shift
|
|
local -n tags_ref=${1}; shift
|
|
|
|
local tfp_tags_var_name
|
|
mvm_get "${pkg_to_tags_mvm_var_name}" "${pkg}" tfp_tags_var_name
|
|
|
|
pkg_debug_enable "${pkg}"
|
|
pkg_debug "checking for tags in ${pkg_to_tags_mvm_var_name}"
|
|
if [[ -z ${tfp_tags_var_name} ]]; then
|
|
pkg_debug "no tags available"
|
|
tags_ref=()
|
|
else
|
|
local -n tags_in_mvm_ref=${tfp_tags_var_name}
|
|
tags_ref=( "${tags_in_mvm_ref[@]}" )
|
|
pkg_debug "tags available: ${tags_in_mvm_ref[*]}"
|
|
fi
|
|
pkg_debug_disable
|
|
}
|
|
|
|
# Adds a changelog stub to changelog file in reports directory.
|
|
#
|
|
# Params:
|
|
# 1 - package name (shortened, without the category)
|
|
# 2 - version
|
|
# @ - package tags
|
|
function generate_changelog_entry_stub() {
|
|
local pkg_name v
|
|
pkg_name=${1}; shift
|
|
v=${1}; shift
|
|
# rest are tags
|
|
|
|
local -a applied_tags=()
|
|
for tag; do
|
|
case ${tag} in
|
|
PROD)
|
|
applied_tags+=( 'base' )
|
|
;;
|
|
*)
|
|
# add lower-cased tag
|
|
applied_tags+=( "${tag,,}" )
|
|
;;
|
|
esac
|
|
done
|
|
local gces_tags=''
|
|
if [[ ${#applied_tags[@]} -gt 0 ]]; then
|
|
join_by gces_tags ', ' "${applied_tags[@]}"
|
|
else
|
|
# no tags, it means it's an SDK package
|
|
gces_tags='SDK'
|
|
fi
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
printf '%s %s: %s ([%s](TODO))\n' '-' "${gces_tags}" "${pkg_name}" "${v}" >>"${REPORTS_DIR}/updates/changelog_stubs"
|
|
}
|
|
|
|
# Adds a stub to the summary file in reports directory.
|
|
#
|
|
# Params:
|
|
# 1 - package
|
|
# @ - tags followed by double dash followed by lines to append to the
|
|
# file
|
|
function generate_summary_stub() {
|
|
local pkg
|
|
pkg=${1}; shift
|
|
# rest are tags separated followed by double dash followed by lines
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -a tags
|
|
tags=()
|
|
while [[ ${#} -gt 0 ]]; do
|
|
if [[ ${1} = '--' ]]; then
|
|
shift
|
|
break
|
|
fi
|
|
tags+=( "${1}" )
|
|
shift
|
|
done
|
|
# rest are lines
|
|
|
|
{
|
|
printf '%s %s:' '-' "${pkg}"
|
|
if [[ ${#tags[@]} -gt 0 ]]; then
|
|
printf ' [%s]' "${tags[@]}"
|
|
fi
|
|
printf '\n'
|
|
local indent_line indent line
|
|
for indent_line; do
|
|
indent=${indent_line%%:*}
|
|
line=${indent_line#*:}
|
|
if [[ ${indent} -gt 0 ]]; then
|
|
printf -- ' %.0s' $(seq 1 "${indent}")
|
|
fi
|
|
printf ' - %s\n' "${line}"
|
|
done
|
|
printf '\n'
|
|
} >>"${REPORTS_DIR}/updates/summary_stubs"
|
|
}
|
|
|
|
# Generate diffs between directories in old state and new state for a
|
|
# package.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to portage-stable in old state
|
|
# 2 - path to portage-stable in new state
|
|
# 3 - old package name
|
|
# 4 - new package name
|
|
function generate_full_diffs() {
|
|
local old_ps new_ps old_pkg new_pkg
|
|
old_ps=${1}; shift
|
|
new_ps=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
|
|
local old_path new_path
|
|
old_path="${old_ps}/${old_pkg}"
|
|
new_path="${new_ps}/${new_pkg}"
|
|
|
|
local gfd_update_dir
|
|
update_dir_non_slot "${new_pkg}" gfd_update_dir
|
|
|
|
local -a common_diff_opts=(
|
|
--recursive
|
|
--unified=3
|
|
)
|
|
xdiff "${common_diff_opts[@]}" --new-file "${old_path}" "${new_path}" >"${gfd_update_dir}/full.diff"
|
|
xdiff "${common_diff_opts[@]}" --brief "${old_path}" "${new_path}" >"${gfd_update_dir}/brief-summary"
|
|
}
|
|
|
|
# Generate a diff between non-ebuild, non-Manifest files for old and
|
|
# new package.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to portage-stable in old state
|
|
# 2 - path to portage-stable in new state
|
|
# 3 - old package name
|
|
# 4 - new package name
|
|
function generate_non_ebuild_diffs() {
|
|
local old_ps new_ps old_pkg new_pkg
|
|
old_ps=${1}; shift
|
|
new_ps=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
|
|
local old_path new_path
|
|
old_path="${old_ps}/${old_pkg}"
|
|
new_path="${new_ps}/${new_pkg}"
|
|
|
|
local gned_update_dir
|
|
update_dir_non_slot "${new_pkg}" gned_update_dir
|
|
|
|
local -a diff_opts=(
|
|
--recursive
|
|
--unified=3
|
|
# Show contents of deleted or added files too.
|
|
--new-file
|
|
# Ignore ebuilds and the Manifest file.
|
|
--exclude='*.ebuild'
|
|
--exclude='Manifest'
|
|
)
|
|
xdiff "${diff_opts[@]}" "${old_path}" "${new_path}" >"${gned_update_dir}/other.diff"
|
|
}
|
|
|
|
# Generate a diff between specific ebuilds for old and new package.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to portage-stable in old state
|
|
# 2 - path to portage-stable in new state
|
|
# 3 - old package name
|
|
# 4 - new package name
|
|
# 5 - old package slot
|
|
# 6 - new package slot
|
|
# 7 - old package version
|
|
# 8 - new package version
|
|
function generate_ebuild_diff() {
|
|
local old_ps new_ps old_pkg new_pkg old_s new_s old new
|
|
old_ps=${1}; shift
|
|
new_ps=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
old_s=${1}; shift
|
|
new_s=${1}; shift
|
|
old=${1}; shift
|
|
new=${1}; shift
|
|
|
|
local old_pkg_name new_pkg_name
|
|
old_pkg_name=${old_pkg#*/}
|
|
new_pkg_name=${new_pkg#*/}
|
|
|
|
local old_path new_path
|
|
old_path="${old_ps}/${old_pkg}/${old_pkg_name}-${old}.ebuild"
|
|
new_path="${new_ps}/${new_pkg}/${new_pkg_name}-${new}.ebuild"
|
|
|
|
local ged_update_dir
|
|
update_dir "${new_pkg}" "${old_s}" "${new_s}" ged_update_dir
|
|
xdiff --unified=3 "${old_path}" "${new_path}" >"${ged_update_dir}/ebuild.diff"
|
|
}
|
|
|
|
function generate_cache_diff_report() {
|
|
local diff_report_var_name=${1}; shift
|
|
local old_cache_dir=${1}; shift
|
|
local new_cache_dir=${1}; shift
|
|
local old_pkg=${1}; shift
|
|
local new_pkg=${1}; shift
|
|
local old=${1}; shift
|
|
local new=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local old_entry=${old_cache_dir}/${old_pkg}-${old}
|
|
local new_entry=${new_cache_dir}/${new_pkg}-${new}
|
|
|
|
local old_cache_name new_cache_name
|
|
gen_varname old_cache_name
|
|
gen_varname new_cache_name
|
|
cache_file_declare "${old_cache_name}" "${new_cache_name}"
|
|
parse_cache_file "${old_cache_name}" "${old_entry}" "${ARCHES[@]}"
|
|
parse_cache_file "${new_cache_name}" "${new_entry}" "${ARCHES[@]}"
|
|
|
|
diff_cache_data "${old_cache_name}" "${new_cache_name}" "${diff_report_var_name}"
|
|
|
|
cache_file_unset "${old_cache_name}" "${new_cache_name}"
|
|
}
|
|
|
|
# Generate a report with information where the old and new packages
|
|
# are mentioned in entire scripts repository. May result in two
|
|
# separate reports if the package got renamed.
|
|
#
|
|
# 1 - path to scripts repo
|
|
# 2 - old package name
|
|
# 3 - new package name
|
|
function generate_package_mention_reports() {
|
|
local scripts old_pkg new_pkg
|
|
scripts=${1}; shift
|
|
old_pkg=${1}; shift
|
|
new_pkg=${1}; shift
|
|
|
|
local gpr_update_dir
|
|
update_dir_non_slot "${new_pkg}" gpr_update_dir
|
|
|
|
generate_mention_report_for_package "${scripts}" "${new_pkg}" >"${gpr_update_dir}/occurences"
|
|
|
|
if [[ ${old_pkg} != "${new_pkg}" ]]; then
|
|
generate_mention_report_for_package "${scripts}" "${old_pkg}" >"${gpr_update_dir}/occurences-for-old-name"
|
|
fi
|
|
}
|
|
|
|
# Generate a report with information where the package is mentioned in
|
|
# entire scripts repository.
|
|
#
|
|
# 1 - path to scripts repo
|
|
# 3 - package name
|
|
function generate_mention_report_for_package() {
|
|
local scripts pkg
|
|
scripts=${1}; shift
|
|
pkg=${1}; shift
|
|
|
|
local ps co
|
|
ps='sdk_container/src/third_party/portage-stable'
|
|
co='sdk_container/src/third_party/coreos-overlay'
|
|
|
|
yell "${pkg} in overlay profiles"
|
|
grep_pkg "${scripts}" "${pkg}" "${co}/profiles"
|
|
|
|
yell "${pkg} in Gentoo profiles"
|
|
grep_pkg "${scripts}" "${pkg}" "${ps}/profiles"
|
|
|
|
# shellcheck disable=SC2164 # we use set -e, so the script will exit if it fails
|
|
pushd "${scripts}/${co}" >/dev/null
|
|
|
|
yell "${pkg} in env overrides"
|
|
cat_entries "coreos/config/env/${pkg}"@(|-+([0-9])*)
|
|
|
|
yell "${pkg} in user patches"
|
|
local dir
|
|
for dir in "coreos/user-patches/${pkg}"@(|-+([0-9])*); do
|
|
echo "BEGIN DIRECTORY: ${dir}"
|
|
cat_entries "${dir}"/*
|
|
echo "END DIRECTORY: ${dir}"
|
|
done
|
|
|
|
# shellcheck disable=SC2164 # we use set -e, so the script will exit if it fails
|
|
popd >/dev/null
|
|
|
|
yell "${pkg} in overlay (outside profiles)"
|
|
grep_pkg "${scripts}" "${pkg}" "${co}" ":(exclude)${co}/profiles"
|
|
|
|
yell "${pkg} in Gentoo (outside profiles)"
|
|
grep_pkg "${scripts}" "${pkg}" "${ps}" ":(exclude)${ps}/profiles"
|
|
|
|
yell "${pkg} in scripts (outside overlay and Gentoo)"
|
|
grep_pkg "${scripts}" "${pkg}" ":(exclude)${ps}" ":(exclude)${co}"
|
|
}
|
|
|
|
# Gets a toplevel update reports directory for a package. This is
|
|
# where occurences and non-ebuild diffs are stored.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - package name
|
|
# 2 - name of a variable where the path will be stored
|
|
function update_dir_non_slot() {
|
|
local pkg
|
|
pkg=${1}; shift
|
|
local -n dir_ref=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
dir_ref="${REPORTS_DIR}/updates/${pkg}"
|
|
}
|
|
|
|
# Gets a slot specific update reports directory for a package. This is
|
|
# where ebuild diffs are stored.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - package name
|
|
# 2 - old slot
|
|
# 3 - new slot
|
|
# 4 - name of a variable where the path will be stored
|
|
function update_dir() {
|
|
local pkg old_s new_s
|
|
pkg=${1}; shift
|
|
old_s=${1}; shift
|
|
new_s=${1}; shift
|
|
local -n dir_ref=${1}; shift
|
|
|
|
# slots may have slashes in them - replace them with "-slash-"
|
|
local slot_dir
|
|
if [[ ${old_s} = "${new_s}" ]]; then
|
|
slot_dir=${old_s//\//-slash-}
|
|
else
|
|
slot_dir="${old_s//\//-slash-}-to-${new_s//\//-slash-}"
|
|
fi
|
|
|
|
local ud_non_slot_dir
|
|
update_dir_non_slot "${pkg}" ud_non_slot_dir
|
|
dir_ref="${ud_non_slot_dir}/${slot_dir}"
|
|
}
|
|
|
|
# Greps for a package name in selected directories of the passed
|
|
# repo. It prints, so the invocation needs to be captured.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to scripts repo
|
|
# 2 - package name
|
|
# @ - directories in the repo to limit the search for
|
|
function grep_pkg() {
|
|
local scripts pkg
|
|
scripts=${1}; shift
|
|
pkg=${1}; shift
|
|
# rest are directories
|
|
|
|
GIT_PAGER='' git -C "${scripts}" grep "${pkg}"'\(-[0-9]\|[^a-zA-Z0-9_-]\|$\)' -- "${@}" || :
|
|
}
|
|
|
|
# Prints the passed files preceding and following with BEGIN ENTRY and
|
|
# END ENTRY markers.
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - the files to print
|
|
function cat_entries() {
|
|
for entry; do
|
|
echo "BEGIN ENTRY: ${entry}"
|
|
cat "${entry}"
|
|
echo "END ENTRY: ${entry}"
|
|
done
|
|
}
|
|
|
|
# Reads the listings and renames, handles updates of both packages and
|
|
# non-packages (eclasses, licenses, profiles, etc.)
|
|
function handle_gentoo_sync() {
|
|
#mvm_debug_enable hgs_pkg_to_tags_mvm
|
|
mvm_declare hgs_pkg_to_tags_mvm
|
|
process_listings hgs_pkg_to_tags_mvm
|
|
|
|
local -A hgs_renames_old_to_new_map=()
|
|
process_profile_updates_directory hgs_renames_old_to_new_map
|
|
|
|
handle_package_changes hgs_renames_old_to_new_map hgs_pkg_to_tags_mvm
|
|
|
|
mvm_unset hgs_pkg_to_tags_mvm
|
|
#mvm_debug_disable hgs_pkg_to_tags_mvm
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local old_head new_head
|
|
old_head=$(git -C "${OLD_STATE}" rev-parse HEAD)
|
|
new_head=$(git -C "${NEW_STATE}" rev-parse HEAD)
|
|
|
|
local -A non_package_updates_set
|
|
non_package_updates_set=()
|
|
local path in_ps category
|
|
if [[ "${old_head}" != "${new_head}" ]]; then
|
|
while read -r path; do
|
|
if [[ ${path} != "${PORTAGE_STABLE_SUFFIX}/"* ]]; then
|
|
continue
|
|
fi
|
|
in_ps=${path#"${PORTAGE_STABLE_SUFFIX}/"}
|
|
category=${in_ps%%/*}
|
|
case "${category}" in
|
|
eclass)
|
|
if [[ ${in_ps} != 'eclass/'+([^/])'.eclass' ]]; then
|
|
fail "unexpected updated file inside eclass directory: '${path}'"
|
|
fi
|
|
non_package_updates_set["${in_ps}"]=x
|
|
;;
|
|
licenses|metadata|profiles|scripts)
|
|
non_package_updates_set["${category}"]=x
|
|
;;
|
|
virtual|*-*)
|
|
# Package update, already handled
|
|
:
|
|
;;
|
|
*)
|
|
fail "unexpected updated file '${path}'"
|
|
;;
|
|
esac
|
|
done < <(git -C "${NEW_STATE}" diff-tree --no-commit-id --name-only -r "${old_head}" "${new_head}")
|
|
fi
|
|
|
|
local entry
|
|
for entry in "${!non_package_updates_set[@]}"; do
|
|
case "${entry}" in
|
|
eclass/*)
|
|
handle_eclass "${entry}"
|
|
;;
|
|
licenses)
|
|
handle_licenses
|
|
;;
|
|
metadata)
|
|
info "not handling metadata updates, skipping"
|
|
;;
|
|
profiles)
|
|
handle_profiles
|
|
;;
|
|
scripts)
|
|
handle_scripts
|
|
;;
|
|
*)
|
|
fail "unknown non-package update for ${entry}"
|
|
;;
|
|
esac
|
|
done
|
|
sort_summary_stubs
|
|
sort_changelog_stubs
|
|
}
|
|
|
|
# Sorts entries in the summary file if it exists.
|
|
function sort_summary_stubs() {
|
|
if [[ -f "${REPORTS_DIR}/updates/summary_stubs" ]]; then
|
|
sort_like_summary_stubs "${REPORTS_DIR}/updates/summary_stubs"
|
|
fi
|
|
}
|
|
|
|
# Sorts entries in the summary file.
|
|
#
|
|
# Lines look like as follows:
|
|
#
|
|
# -BEGIN-
|
|
# - dev-lang/python: [DEV]
|
|
# - from 3.11.4 to 3.11.5
|
|
# - no changes in ebuild
|
|
# - release notes: TODO
|
|
#
|
|
# - app-emulation/qemu:
|
|
# - from 8.0.3 to 8.0.4
|
|
# - no changes in ebuild
|
|
# - release notes: TODO
|
|
#
|
|
# -END-
|
|
function sort_like_summary_stubs() {
|
|
local f
|
|
f=${1}; shift
|
|
|
|
mvm_declare groups_mvm
|
|
|
|
local -a lines entries
|
|
lines=()
|
|
entries=()
|
|
local -A dups
|
|
dups=()
|
|
|
|
local REPLY line entry sss_lines_name dup_count
|
|
while read -r; do
|
|
if [[ -z ${REPLY} ]]; then
|
|
if [[ ${#lines[@]} -gt 0 ]]; then
|
|
line=${lines[0]}
|
|
entry=${line#-+([[:space:]])}
|
|
entry=${entry%%:*}
|
|
dup_count=${dups["${entry}"]:-0}
|
|
if [[ ${dup_count} -gt 0 ]]; then
|
|
dup_count=$((dup_count + 1))
|
|
mvm_add groups_mvm "${entry}@${dup_count}" "${lines[@]}"
|
|
dups["${entry}"]=${dup_count}
|
|
else
|
|
mvm_get groups_mvm "${entry}" sss_lines_name
|
|
if [[ -n ${sss_lines_name} ]]; then
|
|
local -n lines_ref=${sss_lines_name}
|
|
mvm_add groups_mvm "${entry}@1" "${lines_ref[@]}"
|
|
unset -n lines_ref
|
|
mvm_remove groups_mvm "${entry}"
|
|
mvm_add groups_mvm "${entry}@2" "${lines[@]}"
|
|
dups["${entry}"]=2
|
|
else
|
|
mvm_add groups_mvm "${entry}" "${lines[@]}"
|
|
entries+=( "${entry}" )
|
|
fi
|
|
fi
|
|
lines=()
|
|
fi
|
|
else
|
|
lines+=( "${REPLY}" )
|
|
fi
|
|
done < <(cat "${f}"; echo) # echo for final empty line, just in case
|
|
|
|
if [[ ${#entries[@]} -eq 0 ]]; then
|
|
return 0
|
|
fi
|
|
|
|
local idx
|
|
{
|
|
while read -r line; do
|
|
dup_count=${dups["${line}"]:-0}
|
|
if [[ ${dup_count} -gt 0 ]]; then
|
|
idx=0
|
|
while [[ ${idx} -lt ${dup_count} ]]; do
|
|
idx=$((idx + 1))
|
|
mvm_get groups_mvm "${line}@${idx}" sss_lines_name
|
|
local -n lines_ref=${sss_lines_name}
|
|
printf '%s\n' "${lines_ref[@]}" ''
|
|
unset -n lines_ref
|
|
done
|
|
else
|
|
mvm_get groups_mvm "${line}" sss_lines_name
|
|
local -n lines_ref=${sss_lines_name}
|
|
printf '%s\n' "${lines_ref[@]}" ''
|
|
unset -n lines_ref
|
|
fi
|
|
done < <(printf '%s\n' "${entries[@]}" | csort)
|
|
} >"${f}"
|
|
mvm_unset groups_mvm
|
|
}
|
|
|
|
# Sorts entries in changelog stub if it exists.
|
|
function sort_changelog_stubs() {
|
|
if [[ -f "${REPORTS_DIR}/updates/changelog_stubs" ]]; then
|
|
sort_like_changelog_stubs "${REPORTS_DIR}/updates/changelog_stubs"
|
|
fi
|
|
}
|
|
|
|
# Sorts entries in changelog stub.
|
|
function sort_like_changelog_stubs() {
|
|
local f t
|
|
f=${1}; shift
|
|
t="${f}.tmp"
|
|
csort --output="${t}" "${f}"
|
|
mv -f "${t}" "${f}"
|
|
}
|
|
|
|
# Invokes sort with C locale. Meant to be used in bash pipelines.
|
|
#
|
|
# Params:
|
|
#
|
|
# @ - additional parameters to passed to sort
|
|
function csort() {
|
|
LC_ALL=C sort "${@}"
|
|
}
|
|
|
|
# Handle an eclass update. Basically generate a diff.
|
|
#
|
|
# Params:
|
|
#
|
|
# 1 - path to eclass file within an ebuild repo
|
|
function handle_eclass() {
|
|
local eclass
|
|
eclass=${1}; shift
|
|
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -a lines
|
|
lines=()
|
|
if [[ -e "${OLD_PORTAGE_STABLE}/${eclass}" ]] && [[ -e "${NEW_PORTAGE_STABLE}/${eclass}" ]]; then
|
|
mkdir -p "${REPORTS_DIR}/updates/${eclass}"
|
|
xdiff --unified=3 "${OLD_PORTAGE_STABLE}/${eclass}" "${NEW_PORTAGE_STABLE}/${eclass}" >"${REPORTS_DIR}/updates/${eclass}/eclass.diff"
|
|
lines+=( '0:TODO: review the diff' )
|
|
elif [[ -e "${OLD_PORTAGE_STABLE}/${eclass}" ]]; then
|
|
lines+=( '0:unused, dropped' )
|
|
else
|
|
lines+=( '0:added from Gentoo' )
|
|
fi
|
|
generate_summary_stub "${eclass}" -- "${lines[@]}"
|
|
}
|
|
|
|
# Handle profile changes. Generates three different diffs - changes in
|
|
# relevant profiles (ancestors of the profiles used by board packages
|
|
# and SDK), a full diff between all the profiles, and a list of
|
|
# possibly irrelevant files that has changed too.
|
|
function handle_profiles() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -a files=()
|
|
local which arch
|
|
for which in "${WHICH[@]}"; do
|
|
files+=("${WORKDIR}/pkg-reports/${which}/sdk-profiles")
|
|
for arch in "${ARCHES[@]}"; do
|
|
files+=("${WORKDIR}/pkg-reports/${which}/${arch}-board-profiles")
|
|
done
|
|
done
|
|
local -A profile_dirs_set
|
|
profile_dirs_set=()
|
|
|
|
local line
|
|
while read -r line; do
|
|
profile_dirs_set["${line}"]=x
|
|
done < <(xgrep --no-filename '^portage-stable:' "${files[@]}" | cut -d: -f2-)
|
|
|
|
local -a diff_opts
|
|
diff_opts=(
|
|
--recursive
|
|
--unified=3
|
|
--new-file # treat absent files as empty
|
|
)
|
|
|
|
local out_dir
|
|
out_dir="${REPORTS_DIR}/updates/profiles"
|
|
mkdir -p "${out_dir}"
|
|
|
|
xdiff "${diff_opts[@]}" \
|
|
"${OLD_PORTAGE_STABLE}/profiles" "${NEW_PORTAGE_STABLE}/profiles" >"${out_dir}/full.diff"
|
|
|
|
local relevant
|
|
relevant=''
|
|
local -a relevant_lines possibly_irrelevant_files
|
|
relevant_lines=()
|
|
possibly_irrelevant_files=()
|
|
local REPLY path dir mark
|
|
while read -r; do
|
|
if [[ ${REPLY} = "diff "* ]]; then
|
|
path=${REPLY##*"${NEW_PORTAGE_STABLE}/profiles/"}
|
|
dirname_out "${path}" dir
|
|
relevant=''
|
|
mark=${profile_dirs_set["${dir}"]:-}
|
|
if [[ -n "${mark}" ]]; then
|
|
relevant=x
|
|
else
|
|
case ${dir} in
|
|
.|desc|desc/*|updates|updates/*)
|
|
relevant=x
|
|
;;
|
|
esac
|
|
fi
|
|
if [[ -z ${relevant} ]]; then
|
|
possibly_irrelevant_files+=( "profiles/${path}" )
|
|
fi
|
|
fi
|
|
if [[ -n ${relevant} ]]; then
|
|
relevant_lines+=( "${REPLY}" )
|
|
fi
|
|
done <"${out_dir}/full.diff"
|
|
lines_to_file_truncate "${out_dir}/relevant.diff" "${relevant_lines[@]}"
|
|
lines_to_file_truncate "${out_dir}/possibly-irrelevant-files" "${possibly_irrelevant_files[@]}"
|
|
generate_summary_stub profiles -- '0:TODO: review the diffs'
|
|
}
|
|
|
|
# Handles changes in license directory. Generates brief reports and
|
|
# diffs about dropped, added or modified licenses.
|
|
function handle_licenses() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local -a dropped=() added=() changed=()
|
|
local line hl_stripped
|
|
# Lines are:
|
|
#
|
|
# Only in <PORTAGE_STABLE_X>/licenses: BSL-1.1
|
|
#
|
|
# or
|
|
#
|
|
# Files <PORTAGE_STABLE_1>/licenses/BSL-1.1 and <PORTAGE_STABLE_2>/licenses/BSL-1.1 differ
|
|
while read -r line; do
|
|
if [[ ${line} = 'Only in '* ]]; then
|
|
strip_out "${line##*:}" hl_stripped
|
|
if [[ ${line} = *"${OLD_STATE}"* ]]; then
|
|
dropped+=( "${hl_stripped}" )
|
|
elif [[ ${line} = *"${NEW_STATE}"* ]]; then
|
|
added+=( "${hl_stripped}" )
|
|
else
|
|
devel_warn "- unhandled license change: ${line}"
|
|
fi
|
|
elif [[ ${line} = 'Files '*' differ' ]]; then
|
|
line=${line##"Files ${OLD_PORTAGE_STABLE}/licenses/"}
|
|
line=${line%% *}
|
|
strip_out "${line}" hl_stripped
|
|
changed+=( "${hl_stripped}" )
|
|
else
|
|
devel_warn \
|
|
'- unhandled diff --brief line:' \
|
|
" - ${line}"
|
|
fi
|
|
done < <(xdiff --brief --recursive "${OLD_PORTAGE_STABLE}/licenses" "${NEW_PORTAGE_STABLE}/licenses")
|
|
|
|
local out_dir
|
|
out_dir="${REPORTS_DIR}/updates/licenses"
|
|
mkdir -p "${out_dir}"
|
|
|
|
lines_to_file_truncate \
|
|
"${out_dir}/brief-summary" \
|
|
'- removed:' \
|
|
"${dropped[@]/#/ - }" \
|
|
'- added:' \
|
|
"${added[@]/#/ - }" \
|
|
'- modified:' \
|
|
"${changed[@]/#/ - }"
|
|
truncate --size=0 "${out_dir}/modified.diff"
|
|
|
|
local c
|
|
for c in "${changed[@]}"; do
|
|
xdiff --unified=3 "${OLD_PORTAGE_STABLE}/licenses/${c}" "${NEW_PORTAGE_STABLE}/licenses/${c}" >>"${out_dir}/modified.diff"
|
|
done
|
|
local -a lines
|
|
lines=()
|
|
|
|
local joined
|
|
if [[ ${#dropped[@]} -gt 0 ]]; then
|
|
join_by joined ', ' "${dropped[@]}"
|
|
lines+=( "0:dropped ${joined}" )
|
|
fi
|
|
if [[ ${#added[@]} -gt 0 ]]; then
|
|
join_by joined ', ' "${added[@]}"
|
|
lines+=( "0:added ${joined}" )
|
|
fi
|
|
if [[ ${#changed[@]} -gt 0 ]]; then
|
|
join_by joined ', ' "${changed[@]}"
|
|
lines+=( "0:updated ${joined}" )
|
|
fi
|
|
generate_summary_stub licenses -- "${lines[@]}"
|
|
}
|
|
|
|
# Generates reports about changes inside the scripts directory.
|
|
function handle_scripts() {
|
|
# shellcheck source=for-shellcheck/globals
|
|
source "${WORKDIR}/globals"
|
|
|
|
local out_dir
|
|
out_dir="${REPORTS_DIR}/updates/scripts"
|
|
mkdir -p "${out_dir}"
|
|
|
|
xdiff --unified=3 --recursive "${OLD_PORTAGE_STABLE}/scripts" "${NEW_PORTAGE_STABLE}/scripts" >"${out_dir}/scripts.diff"
|
|
generate_summary_stub scripts -- '0:TODO: review the diffs'
|
|
}
|
|
|
|
fi
|