#!/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}"]:-''} } 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