flatcar-scripts/pkg_auto/impl/print_profile_tree.sh
Krzesimir Nowak 0d06b737ac pkg-auto: Disable shellcheck reference warnings
Two warnings, SC2034 and SC2178, pop up very often with the references
- shellcheck handles them poorly and produces a ton of bogus warnings
about them. Silence the warnings and drop most of the "shellcheck
disable" clauses.
2025-04-29 09:43:21 +02:00

271 lines
7.1 KiB
Bash
Executable File

#!/bin/bash
##
## Prints profile information in form of an inheritance tree and/or
## evaluation order.
##
## Parameters:
## -h: this help
## -ni: no inheritance tree
## -ne: no evaluation order
## -nh: no headers
##
## Environment variables:
## ROOT
##
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
: "${ROOT:=/}"
print_inheritance_tree=x
print_evaluation_order=x
print_headers=x
while [[ ${#} -gt 0 ]]; do
case ${1} in
-h)
print_help
exit 0
;;
-ni)
print_inheritance_tree=
;;
-ne)
print_evaluation_order=
;;
-nh)
print_headers=
;;
*)
fail "unknown flag ${1}"
;;
esac
shift
done
all_repo_names=()
read -a all_repo_names -r < <(portageq get_repos "${ROOT}")
declare -A repo_data repo_data_r
# name to path
repo_data=()
# path to name
repo_data_r=()
for repo_name in "${all_repo_names[@]}"; do
repo_path=$(portageq get_repo_path "${ROOT}" "${repo_name}")
repo_path=$(realpath "${repo_path}")
repo_data["${repo_name}"]="${repo_path}"
repo_data_r["${repo_path}"]="${repo_name}"
done
unset all_repo_names
function get_repo_from_profile_path() {
local path
path=${1}; shift
local -n repo_dir_ref=${1}; shift
repo_dir_ref="${path%/profiles/*}"
}
function repo_path_to_name() {
local path
path=${1}; shift
local -n name_ref=${1}; shift
name_ref=${repo_data_r["${path}"]:-'<unknown>'}
}
function repeat_string() {
local str ntimes out_str_var_name
str=${1}; shift
ntimes=${1}; shift
out_str_var_name=${1}; shift
local -n out_str_ref="${out_str_var_name}"
if [[ ${ntimes} -eq 0 ]]; then
out_str_ref=""
return 0
elif [[ ${ntimes} -eq 1 ]]; then
out_str_ref="${str}"
return 0
fi
local add_one
add_one=$((ntimes % 2))
repeat_string "${str}${str}" $((ntimes / 2)) "${out_str_var_name}"
if [[ add_one -gt 0 ]]; then
out_str_ref+="${str}"
fi
}
function process_profile() {
local repo_name profile_path
repo_name=${1}; shift
profile_path=${1}; shift
local -n children_ref=${1}; shift
local parent_file line pp_new_repo_name new_profile_path pp_new_repo_path
local -a children
parent_file="${profile_path}/parent"
children=()
if [[ -e ${parent_file} ]]; then
while read -r line; do
if [[ ${line} = *:* ]]; then
pp_new_repo_name=${line%%:*}
if [[ -z ${pp_new_repo_name} ]]; then
pp_new_repo_name=${repo_name}
fi
pp_new_repo_path=${repo_data["${pp_new_repo_name}"]}
new_profile_path="${pp_new_repo_path}/profiles/${line#*:}"
children+=( "${pp_new_repo_name}" "${new_profile_path}" )
elif [[ ${line} = /* ]]; then
pp_new_repo_path=
get_repo_from_profile_path "${line}" pp_new_repo_path
pp_new_repo_name=
repo_path_to_name "${pp_new_repo_path}" pp_new_repo_name
children+=( "${pp_new_repo_name}" "${line}" )
else
pp_new_repo_path=$(realpath "${profile_path}/${line}")
children+=( "${repo_name}" "${pp_new_repo_path}" )
fi
done <"${parent_file}"
fi
children_ref=( "${children[@]}" )
}
function get_profile_name() {
local repo_name profile_path
repo_name="${1}"; shift
profile_path="${1}"; shift
local -n profile_name_ref=${1}; shift
local repo_path profile_name
repo_path=${repo_data["${repo_name}"]}
profile_name=${profile_path#"${repo_path}/profiles/"}
profile_name_ref="${profile_name}"
}
make_profile_path="${ROOT%/}/etc/portage/make.profile"
top_profile_dir_path=$(realpath "${make_profile_path}")
top_repo_path=
get_repo_from_profile_path "${top_profile_dir_path}" top_repo_path
top_repo_name=
repo_path_to_name "${top_repo_path}" top_repo_name
if [[ -n ${print_inheritance_tree} ]]; then
set -- '0' "${top_repo_name}" "${top_profile_dir_path}"
profile_tree=()
while [[ ${#} -gt 2 ]]; do
indent=${1}; shift
repo_name=${1}; shift
profile_path=${1}; shift
lines=
fork=
if [[ ${indent} -gt 0 ]]; then
if [[ ${indent} -gt 1 ]]; then
repeat_string '| ' $((indent - 1)) lines
fi
fork='+-'
fi
g_profile_name=
get_profile_name "${repo_name}" "${profile_path}" g_profile_name
profile_tree+=( "${lines}${fork}${repo_name}:${g_profile_name}" )
g_profile_children=()
process_profile "${repo_name}" "${profile_path}" g_profile_children
new_profiles=()
new_indent=$((indent + 1))
pc_idx=0
while [[ $((pc_idx + 1)) -lt "${#g_profile_children[@]}" ]]; do
new_repo_name=${g_profile_children["${pc_idx}"]}
new_profile_path=${g_profile_children[$((pc_idx + 1))]}
new_profiles+=( "${new_indent}" "${new_repo_name}" "${new_profile_path}" )
pc_idx=$((pc_idx + 2))
done
set -- "${new_profiles[@]}" "${@}"
done
if [[ -n ${print_headers} ]]; then
echo
echo 'profile inheritance tree:'
echo
fi
for line in "${profile_tree[@]}"; do
echo "${line}"
done
fi
if [[ -n ${print_evaluation_order} ]]; then
set -- "${top_repo_name}" "${top_profile_dir_path}" '0'
profile_eval=()
while [[ ${#} -gt 2 ]]; do
repo_name=${1}; shift
profile_path=${1}; shift
num_parents=${1}; shift
# each parent is a repo name and profile path, so two items for each parent
num_parent_items=$((num_parents * 2))
parents=( "${@:1:${num_parent_items}}" )
shift "${num_parent_items}"
g_profile_children=()
process_profile "${repo_name}" "${profile_path}" g_profile_children
new_args=()
if [[ ${#g_profile_children[@]} -eq 0 ]]; then
to_evaluate=( "${repo_name}" "${profile_path}" "${parents[@]}" )
te_idx=0
while [[ $((te_idx + 1)) -lt "${#to_evaluate[@]}" ]]; do
new_repo_name=${to_evaluate["${te_idx}"]}
new_profile_path=${to_evaluate[$((te_idx + 1))]}
g_new_profile_name=
get_profile_name "${new_repo_name}" "${new_profile_path}" g_new_profile_name
profile_eval+=( "${new_repo_name}:${g_new_profile_name}" )
te_idx=$((te_idx + 2))
done
else
last_idx=$(( ${#g_profile_children[@]} - 2 ))
pc_idx=0
while [[ $((pc_idx + 1)) -lt "${#g_profile_children[@]}" ]]; do
new_repo_name=${g_profile_children["${pc_idx}"]}
new_profile_path=${g_profile_children[$((pc_idx + 1))]}
new_args+=( "${new_repo_name}" "${new_profile_path}" )
if [[ pc_idx -eq last_idx ]]; then
new_args+=( $((num_parents + 1)) "${repo_name}" "${profile_path}" "${parents[@]}" )
else
new_args+=( 0 )
fi
pc_idx=$((pc_idx + 2))
done
fi
set -- "${new_args[@]}" "${@}"
done
if [[ -n ${print_headers} ]]; then
echo
echo 'profile evaluation order:'
echo
fi
for line in "${profile_eval[@]}"; do
echo "${line}"
done
fi