#!/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 # shellcheck disable=SC2034 # used externally 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 ] / 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 # /etc/portage/package.mask/cross- 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