mirror of
				https://github.com/flatcar/scripts.git
				synced 2025-11-04 02:01:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			471 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			471 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
#!/bin/bash
 | 
						|
 | 
						|
if [[ -z ${__INSIDE_SDK_CONTAINER_LIB_SH_INCLUDED__:-} ]]; then
 | 
						|
__INSIDE_SDK_CONTAINER_LIB_SH_INCLUDED__=x
 | 
						|
 | 
						|
source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
 | 
						|
 | 
						|
# Invokes emerge to get a report about built packages for a given
 | 
						|
# metapackage in the given root that has a portage configuration.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - root filesystem with the portage config
 | 
						|
# @ - packages and metapackages to get the deps from
 | 
						|
function emerge_pretend() {
 | 
						|
    local root
 | 
						|
    root=${1}; shift
 | 
						|
 | 
						|
    # Probably a bunch of those flags are not necessary, but I'm not
 | 
						|
    # touching it - they seem to be working. :)
 | 
						|
    local -a emerge_opts=(
 | 
						|
        --config-root="${root}"
 | 
						|
        --root="${root}"
 | 
						|
        --sysroot="${root}"
 | 
						|
        --pretend
 | 
						|
        --columns
 | 
						|
        --nospinner
 | 
						|
        --oneshot
 | 
						|
        --color n
 | 
						|
        --emptytree
 | 
						|
        --verbose
 | 
						|
        --verbose-conflicts
 | 
						|
        --verbose-slot-rebuilds y
 | 
						|
        --changed-deps y
 | 
						|
        --changed-deps-report y
 | 
						|
        --changed-slot y
 | 
						|
        --changed-use
 | 
						|
        --newuse
 | 
						|
        --complete-graph y
 | 
						|
        --deep
 | 
						|
        --rebuild-if-new-slot y
 | 
						|
        --rebuild-if-unbuilt y
 | 
						|
        --with-bdeps y
 | 
						|
        --dynamic-deps y
 | 
						|
        --update
 | 
						|
        --ignore-built-slot-operator-deps y
 | 
						|
        --selective n
 | 
						|
        --keep-going y
 | 
						|
    )
 | 
						|
    local rv
 | 
						|
    rv=0
 | 
						|
    emerge "${emerge_opts[@]}" "${@}" || rv=${?}
 | 
						|
    if [[ ${rv} -ne 0 ]]; then
 | 
						|
        echo "WARNING: emerge exited with status ${rv}" >&2
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
# Gets package list for SDK.
 | 
						|
function package_info_for_sdk() {
 | 
						|
    local root
 | 
						|
    root='/'
 | 
						|
 | 
						|
    ignore_crossdev_stuff "${root}"
 | 
						|
    # stage4 build of SDK builds coreos-devel/sdk-depends, fsscript
 | 
						|
    # pulls in cross toolchains with crossdev (which we have just
 | 
						|
    # ignored) and dev-lang/rust
 | 
						|
    emerge_pretend "${root}" coreos-devel/sdk-depends dev-lang/rust
 | 
						|
    revert_crossdev_stuff "${root}"
 | 
						|
}
 | 
						|
 | 
						|
# Gets package list for board of a given architecture.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - architecture
 | 
						|
function package_info_for_board() {
 | 
						|
    local arch
 | 
						|
    arch=${1}; shift
 | 
						|
 | 
						|
    local root
 | 
						|
    root="/build/${arch}-usr"
 | 
						|
 | 
						|
    # Ignore crossdev stuff in both SDK root and board root - emerge
 | 
						|
    # may query SDK stuff for the board packages.
 | 
						|
    ignore_crossdev_stuff /
 | 
						|
    ignore_crossdev_stuff "${root}"
 | 
						|
    emerge_pretend "${root}" coreos-devel/board-packages
 | 
						|
    revert_crossdev_stuff "${root}"
 | 
						|
    revert_crossdev_stuff /
 | 
						|
}
 | 
						|
 | 
						|
# Set the directory where the emerge output and the results of
 | 
						|
# processing it will be stored. EO stands for "emerge output"
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - directory path
 | 
						|
function set_eo() {
 | 
						|
    local dir=${1}; shift
 | 
						|
    # rest are architectures
 | 
						|
 | 
						|
    declare -g EGENCACHE_W="${dir}/egencache-warnings"
 | 
						|
    declare -g SDK_EO="${dir}/sdk-emerge-output"
 | 
						|
    declare -g SDK_EO_F="${SDK_EO}-filtered"
 | 
						|
    declare -g SDK_EO_W="${SDK_EO}-warnings"
 | 
						|
    declare -g SDK_EO_J="${SDK_EO}-junk"
 | 
						|
 | 
						|
    local arch
 | 
						|
    local board_eo
 | 
						|
    for arch; do
 | 
						|
        board_eo=${dir}/${arch}-board-emerge-output
 | 
						|
        declare -g "${arch^^}_BOARD_EO=${board_eo}"
 | 
						|
        declare -g "${arch^^}_BOARD_EO_F=${board_eo}-filtered"
 | 
						|
        declare -g "${arch^^}_BOARD_EO_W=${board_eo}-warnings"
 | 
						|
        declare -g "${arch^^}_BOARD_EO_J=${board_eo}-junk"
 | 
						|
    done
 | 
						|
}
 | 
						|
 | 
						|
# JSON output would be more verbose, but probably would not require
 | 
						|
# these abominations below. But, alas, emerge doesn't have that yet.
 | 
						|
 | 
						|
#      status      package name     version slot repo      target (opt)          keyvals          size
 | 
						|
# |--------------| |----------| |#-g1-----------#--#-g2-#| |--|-g------| |-g----------#-#-g-----| |---|
 | 
						|
# [ebuild   R   ~] virtual/rust [1.71.1:0/llvm-16::coreos] to /some/root USE="-rustfmt" FOO="bar" 0 KiB
 | 
						|
#
 | 
						|
# Actually, there can also be another "version slot repo" part between
 | 
						|
# the first "version slot repo" and "target" part.
 | 
						|
STATUS_RE='\[[^]]*]' # 0 groups
 | 
						|
PACKAGE_NAME_RE='[^[:space:]]*' # 0 groups
 | 
						|
VER_SLOT_REPO_RE='\[\([^]]\+\)::\([^]]\+\)]' # 2 groups
 | 
						|
TARGET_RE='to[[:space:]]\+\([^[:space:]]\)\+' # 1 group
 | 
						|
KEYVALS_RE='\([[:space:]]*[A-Za-z0-9_]*="[^"]*"\)*' # 1 group (but containing only the last pair!)
 | 
						|
SIZE_RE='[[:digit:]]\+[[:space:]]*[[:alpha:]]*B' # 0 groups
 | 
						|
SPACES_RE='[[:space:]]\+' # 0 groups
 | 
						|
NONSPACES_RE='[^[:space:]]\+' # 0 groups
 | 
						|
NONSPACES_WITH_COLON_RE='[^[:space:]]*:' # 0 groups
 | 
						|
 | 
						|
FULL_LINE_RE='^'"${STATUS_RE}${SPACES_RE}${PACKAGE_NAME_RE}"'\('"${SPACES_RE}${VER_SLOT_REPO_RE}"'\)\{1,2\}\('"${SPACES_RE}${TARGET_RE}"'\)\?\('"${SPACES_RE}${KEYVALS_RE}"'\)*'"${SPACES_RE}${SIZE_RE}"'$'
 | 
						|
 | 
						|
# Filters sdk reports to get the package information.
 | 
						|
function filter_sdk_eo() {
 | 
						|
    cat "${SDK_EO}" | xgrep -e "${FULL_LINE_RE}"
 | 
						|
}
 | 
						|
 | 
						|
# Filters board reports for a given arch to get the package
 | 
						|
# information.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - architecture
 | 
						|
function filter_board_eo() {
 | 
						|
    local arch name
 | 
						|
    arch=${1}; shift
 | 
						|
    name=${arch^^}_BOARD_EO
 | 
						|
 | 
						|
    # Replace ${arch}-usr in the output with a generic word BOARD.
 | 
						|
    cat "${!name}"  | \
 | 
						|
        xgrep -e "${FULL_LINE_RE}" | \
 | 
						|
        sed -e "s#/build/${arch}-usr/#/build/BOARD/#"
 | 
						|
}
 | 
						|
 | 
						|
# Filters sdk reports to get anything but the package information
 | 
						|
# (i.e. junk).
 | 
						|
function junk_sdk_eo() {
 | 
						|
    cat "${SDK_EO}" | xgrep -v -e "${FULL_LINE_RE}"
 | 
						|
}
 | 
						|
 | 
						|
# Filters board reports to get anything but the package information
 | 
						|
# (i.e. junk).
 | 
						|
function junk_board_eo() {
 | 
						|
    local arch name
 | 
						|
    arch=${1}; shift
 | 
						|
    name=${arch^^}_BOARD_EO
 | 
						|
 | 
						|
    cat "${!name}" | xgrep -v -e "${FULL_LINE_RE}"
 | 
						|
}
 | 
						|
 | 
						|
# More regexp-like abominations follow.
 | 
						|
 | 
						|
# There may also be a line like:
 | 
						|
#
 | 
						|
# [blocks B      ] <dev-util/gdbus-codegen-2.76.4 ("<dev-util/gdbus-codegen-2.76.4" is soft blocking dev-libs/glib-2.76.4)
 | 
						|
#
 | 
						|
# But currently we don't care about those - they land in junk.
 | 
						|
 | 
						|
SLOT_INFO_SED_FILTERS=(
 | 
						|
    # if there is no slot information in version, add :0
 | 
						|
    #
 | 
						|
    # assumption here is that version is a second word
 | 
						|
    -e "/^${NONSPACES_RE}${SPACES_RE}${NONSPACES_WITH_COLON_RE}/ ! s/^\(${NONSPACES_RE}${SPACES_RE}${NONSPACES_RE}\)/\1:0/"
 | 
						|
)
 | 
						|
 | 
						|
PKG_VER_SLOT_SED_FILTERS=(
 | 
						|
    # from line like:
 | 
						|
    #
 | 
						|
    # [ebuild   R   ~] virtual/rust        [1.71.1:0/llvm-16::coreos]    USE="-rustfmt" 0 KiB
 | 
						|
    #
 | 
						|
    # extract package name, version and optionally a slot if it exists, the result would be:
 | 
						|
    #
 | 
						|
    # virtual/rust 1.71.1:0/llvm-16
 | 
						|
    -e "s/^${STATUS_RE}${SPACES_RE}\(${PACKAGE_NAME_RE}\)${SPACES_RE}${VER_SLOT_REPO_RE}.*/\1 \2/"
 | 
						|
    "${SLOT_INFO_SED_FILTERS[@]}"
 | 
						|
)
 | 
						|
 | 
						|
PKG_VER_SLOT_KV_SED_FILTERS=(
 | 
						|
    # from line like:
 | 
						|
    #
 | 
						|
    # [ebuild   R   ~] virtual/rust        [1.71.1:0/llvm-16::coreos]    USE="-rustfmt" 0 KiB
 | 
						|
    #
 | 
						|
    # extract package name, version, optionally a slot if it exists and key value pairs if any, the result would be:
 | 
						|
    #
 | 
						|
    # virtual/rust 1.71.1:0/llvm-16 USE="-rustfmt"
 | 
						|
    -e "s/${STATUS_RE}${SPACES_RE}\(${PACKAGE_NAME_RE}\)${SPACES_RE}${VER_SLOT_REPO_RE}\(${SPACES_RE}${VER_SLOT_REPO_RE}\)\?\(${SPACES_RE}${TARGET_RE}\)\?${SPACES_RE}\(${KEYVALS_RE}\)${SPACES_RE}${SIZE_RE}\$/\1 \2 \9/"
 | 
						|
    "${SLOT_INFO_SED_FILTERS[@]}"
 | 
						|
)
 | 
						|
 | 
						|
PKG_REPO_SED_FILTERS=(
 | 
						|
    # from line like:
 | 
						|
    #
 | 
						|
    # [ebuild   R   ~] virtual/rust        [1.71.1:0/llvm-16::coreos]    USE="-rustfmt" 0 KiB
 | 
						|
    #
 | 
						|
    # extract package name and repo, the result would be:
 | 
						|
    #
 | 
						|
    # virtual/rust coreos
 | 
						|
    -e "s/^${STATUS_RE}${SPACES_RE}\(${PACKAGE_NAME_RE}\)${SPACES_RE}${VER_SLOT_REPO_RE}${SPACES_RE}.*/\1 \3/"
 | 
						|
)
 | 
						|
 | 
						|
# Applies some sed filter over the SDK emerge output. Results are
 | 
						|
# printed.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# @ - parameters passed to sed
 | 
						|
function packages_for_sdk() {
 | 
						|
    cat "${SDK_EO_F}" | sed "${@}" | sort
 | 
						|
}
 | 
						|
 | 
						|
# Applies some sed filter over the board emerge output. Results are
 | 
						|
# printed.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# @ - parameters passed to sed
 | 
						|
function packages_for_board() {
 | 
						|
    local arch=${1}; shift
 | 
						|
    # rest goes to sed
 | 
						|
 | 
						|
    local name=${arch^^}_BOARD_EO_F
 | 
						|
 | 
						|
    sed "${@}" "${!name}" | sort
 | 
						|
}
 | 
						|
 | 
						|
# Prints package name, slot and version information for SDK.
 | 
						|
function versions_sdk() {
 | 
						|
    local -a sed_opts
 | 
						|
    sed_opts=(
 | 
						|
        "${PKG_VER_SLOT_SED_FILTERS[@]}"
 | 
						|
    )
 | 
						|
    packages_for_sdk "${sed_opts[@]}"
 | 
						|
}
 | 
						|
 | 
						|
# Prints package name, slot, version and key-values information for
 | 
						|
# SDK. Key-values may be something like USE="foo bar -baz".
 | 
						|
function versions_sdk_with_key_values() {
 | 
						|
    local -a sed_opts
 | 
						|
    sed_opts=(
 | 
						|
        "${PKG_VER_SLOT_KV_SED_FILTERS[@]}"
 | 
						|
    )
 | 
						|
    packages_for_sdk "${sed_opts[@]}"
 | 
						|
}
 | 
						|
 | 
						|
# Prints package name, slot and version information for board.
 | 
						|
function versions_board() {
 | 
						|
    local arch=${1}; shift
 | 
						|
    local -a sed_opts
 | 
						|
    sed_opts=(
 | 
						|
        -e '/to \/build\/BOARD\// ! d'
 | 
						|
        "${PKG_VER_SLOT_SED_FILTERS[@]}"
 | 
						|
    )
 | 
						|
    packages_for_board "${arch}" "${sed_opts[@]}"
 | 
						|
}
 | 
						|
 | 
						|
# Prints package name, slot, version and key-values information for
 | 
						|
# build dependencies of board. Key-values may be something like
 | 
						|
# USE="foo bar -baz".
 | 
						|
function board_bdeps() {
 | 
						|
    local arch=${1}; shift
 | 
						|
    local -a sed_opts
 | 
						|
    sed_opts=(
 | 
						|
        -e '/to \/build\/BOARD\// d'
 | 
						|
        "${PKG_VER_SLOT_KV_SED_FILTERS[@]}"
 | 
						|
    )
 | 
						|
    packages_for_board "${arch}" "${sed_opts[@]}"
 | 
						|
}
 | 
						|
 | 
						|
# Print package name and source repository names information for SDK.
 | 
						|
function package_sources_sdk() {
 | 
						|
    local -a sed_opts
 | 
						|
    sed_opts=(
 | 
						|
        "${PKG_REPO_SED_FILTERS[@]}"
 | 
						|
    )
 | 
						|
    packages_for_sdk "${sed_opts[@]}"
 | 
						|
}
 | 
						|
 | 
						|
# Print package name and source repository names information for
 | 
						|
# board.
 | 
						|
function package_sources_board() {
 | 
						|
    local arch=${1}; shift
 | 
						|
    local -a sed_opts
 | 
						|
    sed_opts=(
 | 
						|
        "${PKG_REPO_SED_FILTERS[@]}"
 | 
						|
    )
 | 
						|
    packages_for_board "${arch}" "${sed_opts[@]}"
 | 
						|
}
 | 
						|
 | 
						|
# Checks if no errors were produced by emerge when generating
 | 
						|
# reports. It is assumed that emerge will print a line with "ERROR" in
 | 
						|
# it to denote a failure.
 | 
						|
function ensure_no_errors() {
 | 
						|
    local -a files=( "${SDK_EO_W}" )
 | 
						|
    local arch name
 | 
						|
 | 
						|
    for arch; do
 | 
						|
        name=${arch^^}_BOARD_EO_W
 | 
						|
        files+=( "${!name}" )
 | 
						|
    done
 | 
						|
 | 
						|
    if grep --quiet --fixed-strings 'ERROR' "${files[@]}"; then
 | 
						|
        fail "there are errors in emerge output warnings files"
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
# Stores a path to a package.provided file inside the given root
 | 
						|
# filesystem portage configuration. Mostly used to ignore
 | 
						|
# cross-toolchains.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - path to root filesystem with the portage configuration
 | 
						|
# 2 - name of a variable where the path will be stored
 | 
						|
function get_provided_file() {
 | 
						|
    local root path_var_name
 | 
						|
    root=${1}; shift
 | 
						|
    path_var_name=${1}; shift
 | 
						|
    local -n path_ref="${path_var_name}"
 | 
						|
 | 
						|
    path_ref="${root}/etc/portage/profile/package.provided/ignore_cross_packages"
 | 
						|
}
 | 
						|
 | 
						|
# Marks packages coming from crossdev repo as provided at a very high
 | 
						|
# version. We do this, because updating their native counterparts will
 | 
						|
# cause emerge to complain that cross-<triplet>/<package> is masked
 | 
						|
# (like for sys-libs/glibc and cross-x86_64-cros-linux-gnu/glibc),
 | 
						|
# because it has no keywords. In theory, we could try updating
 | 
						|
# <ROOT>/etc/portage/package.mask/cross-<triplet> file created by the
 | 
						|
# crossdev tool to unmask the new version, but it's an unnecessary
 | 
						|
# hassle - native and cross package are supposed to be the same ebuild
 | 
						|
# anyway, so update information about cross package is redundant.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - root directory
 | 
						|
# 2 - ID of the crossdev repository (optional, defaults to x-crossdev)
 | 
						|
function ignore_crossdev_stuff() {
 | 
						|
    local root crossdev_repo_id
 | 
						|
    root=${1}; shift
 | 
						|
    crossdev_repo_id=${1:-x-crossdev}; shift || :
 | 
						|
 | 
						|
    local crossdev_repo_path
 | 
						|
    crossdev_repo_path=$(portageq get_repo_path "${root}" "${crossdev_repo_id}")
 | 
						|
 | 
						|
    local ics_path ics_dir
 | 
						|
    get_provided_file "${root}" ics_path
 | 
						|
    dirname_out "${ics_path}" ics_dir
 | 
						|
 | 
						|
    sudo mkdir -p "${ics_dir}"
 | 
						|
    env --chdir="${crossdev_repo_path}" find . -type l | \
 | 
						|
        cut -d/ -f2-3 | \
 | 
						|
        sed -e 's/$/-9999/' | \
 | 
						|
        sudo tee "${ics_path}" >/dev/null
 | 
						|
}
 | 
						|
 | 
						|
# Reverts effects of the ignore_crossdev_stuff function.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - root directory
 | 
						|
function revert_crossdev_stuff() {
 | 
						|
    local root
 | 
						|
    root=${1}; shift
 | 
						|
 | 
						|
    local ics_path ics_dir
 | 
						|
    get_provided_file "${root}" ics_path
 | 
						|
    dirname_out "${ics_path}" ics_dir
 | 
						|
 | 
						|
    sudo rm -f "${ics_path}"
 | 
						|
    if dir_is_empty "${ics_dir}"; then
 | 
						|
        sudo rmdir "${ics_dir}"
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
# Checks if the expected reports were generated by emerge.
 | 
						|
function ensure_valid_reports() {
 | 
						|
    local -a files=( "${SDK_EO_F}" )
 | 
						|
    local arch name
 | 
						|
 | 
						|
    for arch; do
 | 
						|
        name=${arch^^}_BOARD_EO_F
 | 
						|
        files+=( "${!name}" )
 | 
						|
    done
 | 
						|
 | 
						|
    local file
 | 
						|
    for file in "${files[@]}"; do
 | 
						|
        if [[ ! -s ${file} ]]; then
 | 
						|
            fail "report files are missing or are empty"
 | 
						|
        fi
 | 
						|
    done
 | 
						|
}
 | 
						|
 | 
						|
# Drops the empty warning files in given directory.
 | 
						|
#
 | 
						|
# Params:
 | 
						|
#
 | 
						|
# 1 - path to the directory
 | 
						|
function clean_empty_warning_files() {
 | 
						|
    local dir
 | 
						|
    dir=${1}; shift
 | 
						|
 | 
						|
    local file
 | 
						|
    for file in "${dir}/"*'-warnings'; do
 | 
						|
        if [[ ! -s ${file} ]]; then
 | 
						|
            rm -f "${file}"
 | 
						|
        fi
 | 
						|
    done
 | 
						|
}
 | 
						|
 | 
						|
function get_num_proc() {
 | 
						|
    local -n num_proc_ref=${1}; shift
 | 
						|
    local -i num_proc=1 rv=1
 | 
						|
 | 
						|
    # stolen from portage
 | 
						|
    [[ rv -eq 0 ]] || { rv=0; num_proc=$(getconf _NPROCESSORS_ONLN 2>/dev/null) || rv=1; }
 | 
						|
    [[ rv -eq 0 ]] || { rv=0; num_proc=$(sysctl -n hw.ncpu 2>/dev/null) || rv=1; }
 | 
						|
    # stolen from common.sh
 | 
						|
    [[ rv -eq 0 ]] || { rv=0; num_proc=$(grep -c "^processor" /proc/cpuinfo 2>/dev/null) || rv=1; }
 | 
						|
    [[ rv -eq 0 ]] || { rv=0; num_proc=1; }
 | 
						|
 | 
						|
    num_proc_ref=${num_proc}
 | 
						|
}
 | 
						|
 | 
						|
function generate_cache_for() {
 | 
						|
    local repo=${1}; shift
 | 
						|
 | 
						|
    local -i gcf_num_proc
 | 
						|
    local load_avg
 | 
						|
    get_num_proc gcf_num_proc
 | 
						|
    load_avg=$(bc <<< "${gcf_num_proc} * 0.75")
 | 
						|
    egencache --repo "${repo}" --jobs="${gcf_num_proc}" --load-average="${load_avg}" --update
 | 
						|
}
 | 
						|
 | 
						|
function copy_cache_to_reports() {
 | 
						|
    local repo=${1}; shift
 | 
						|
    local reports_dir=${1}; shift
 | 
						|
 | 
						|
    local repo_dir
 | 
						|
    repo_dir=$(portageq get_repo_path / "${repo}")
 | 
						|
    cp -a "${repo_dir}/metadata/md5-cache" "${reports_dir}/${repo}-cache"
 | 
						|
}
 | 
						|
 | 
						|
fi
 |