| #!/bin/bash |
| |
| # Copyright 2023 Google Inc. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # Builds debug-<board>-package-info.json which contains debug |
| # information of the packages available as part of a board. |
| # The script should be used from inside the chroot as it |
| # uses cros_sdk dependencies for extracting package information. |
| |
| set -eu |
| set -o pipefail |
| |
| PROG_NAME=$(basename "$0") |
| readonly PROG_NAME |
| BOARD="" |
| BUILD_ID="" |
| OUTPUT_DIR="" |
| TMP_DIR="" |
| |
| cleanup_dir() { |
| if [[ -d "${TMP_DIR}" ]]; then |
| rm -fr "${TMP_DIR}" |
| fi |
| } |
| |
| # Returns the overlay of the package name provided. |
| # Example: |
| # Input: sys-apps/systemd-248.6 |
| # Output: portage-stable |
| find_overlay() { |
| local -r file_path=$(equery-"${BOARD}" w "${1}") |
| # Split the ebuild path of the package based on '/'. |
| IFS="/" read -r -a arr <<< "${file_path}" |
| # Return the overlay of the package. |
| # It should be the fourth element from the end. |
| if [[ "${#arr[@]}" -le 4 ]]; then |
| echo "" |
| else |
| echo "${arr[-4]}" |
| fi |
| } |
| |
| # Returns the set use_flags for the package name provided. |
| # Example: |
| # Input: sys-apps/systemd-248.6 |
| # Output: +apparmor,+audit,+cgroup-hybrid,+gcrypt,+hwdb,+kmod,+lz4, |
| # +networkd-wait-online,+pam,+resolvconf,+seccomp,+sysv-utils,+vanilla |
| find_use_flags() { |
| local -r use_flags=$(equery-"${BOARD}" u "${1}" | cut -f 2-3) |
| result="" |
| |
| # Looping over the use_flags. |
| for val in ${use_flags}; do |
| # Only include the use_flags which are set. |
| if [[ "${val::1}" == "+" ]]; then |
| if [[ "${result}" == "" ]]; then |
| result=${val} |
| else |
| result+=",${val}" |
| fi |
| fi |
| done |
| echo "${result}" |
| } |
| |
| write_debug_package_info() { |
| local -r pkg_info_file=$1 |
| local -r output_file=$2 |
| local -r tmp_overlay_file=$3 |
| local -r tmp_use_flags_file=$4 |
| |
| while IFS= read -r line; do |
| # Check for empty line and comment. |
| [[ -z "${line}" || "${line}" =~ ^#.* ]] && continue |
| find_overlay "${line}" > "${tmp_overlay_file}" & |
| find_use_flags "${line}" > "${tmp_use_flags_file}" & |
| wait |
| |
| overlay=$(<"${tmp_overlay_file}") |
| use_flags=$(<"${tmp_use_flags_file}") |
| |
| output="${line}" |
| if [[ "${overlay}" != "" ]]; then |
| output+=" overlay:${overlay}" |
| fi |
| if [[ "${use_flags}" != "" ]]; then |
| output+=" use_flags:${use_flags}" |
| fi |
| echo "${output}" >> "${output_file}" |
| done < "${pkg_info_file}" |
| } |
| |
| build_debug_package_info() { |
| trap cleanup_dir EXIT |
| echo "Generating debug-cos-package-info.json. It may take couple of minutes.." |
| TMP_DIR="$(mktemp -d -p /tmp package-list.XXXXXXXXXX)" |
| |
| local -r pkg_deps_file="${TMP_DIR}"/pkg_deps.txt |
| local -r pkg_info_file="${TMP_DIR}"/pkg_info.txt |
| local -r debug_pkg_info_file="${TMP_DIR}"/debug_pkg_info.txt |
| local -r tmp_overlay_file="${TMP_DIR}"/overlay.txt |
| local -r tmp_use_flags_file="${TMP_DIR}"/use_flags.txt |
| local -r tmp_uniq_pkgs_file="${TMP_DIR}"/uniq_pkgs.txt |
| |
| # Generate the package dependency file. |
| # The generated file will contain snippet |
| # similar to below: |
| # |
| # { |
| # "acct-group/docker-0.0.1": { |
| # "action": "merge", |
| # "category": "acct-group", |
| # "cpes": [], |
| # "deps": [ |
| # "sys-apps/baselayout-2.2-r1" |
| # ], |
| # "full_name": "acct-group/docker-0.0.1", |
| # "name": "docker", |
| # "rev_deps": [ |
| # "app-emulation/docker-20.10.6-r5" |
| # ], |
| # "version": "0.0.1" |
| # } |
| (cros_extract_deps \ |
| --sysroot /build/"${BOARD}" \ |
| --format deps \ |
| virtual/target-os \ |
| --output-path "${pkg_deps_file}") |
| |
| # Extract the package name from the |
| # above generated file. |
| # Output: |
| # acct-group/docker-0.0.1 |
| ( grep "full_name" <"${pkg_deps_file}" \ |
| | awk -F '"' '{print $4}' >> "${pkg_info_file}") |
| |
| # Package listed above does not include some of the SDK related |
| # dependencies such as glibc and gcc. To add those packages, |
| # use the package list present at /etc/portage/profile/package.provided |
| # under sysroot. It is the same location from where cros_extract_deps |
| # gets those package for generation of CPE file. |
| local -r pkg_list_file="/build/${BOARD}/etc/portage/profile/package.provided" |
| # The below condition will help in |
| # reading lines where \n is not present. |
| while read -r line || [ -n "${line}" ] |
| do |
| # skip comment. |
| [[ "${line}" =~ ^#.* ]] && continue |
| echo "${line}" >> "${pkg_info_file}" |
| done < "${pkg_list_file}" |
| |
| # Remove duplicate entries of the package if any. |
| ( sort < "${pkg_info_file}" | uniq > "${tmp_uniq_pkgs_file}" \ |
| && mv "${tmp_uniq_pkgs_file}" "${pkg_info_file}") |
| |
| write_debug_package_info \ |
| "${pkg_info_file}" \ |
| "${debug_pkg_info_file}" \ |
| "${tmp_overlay_file}" \ |
| "${tmp_use_flags_file}" |
| |
| local -r script_root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")" |
| sudo "${script_root}/create_pkg_info.py" \ |
| --input="allPackages:${debug_pkg_info_file}" \ |
| --output="${OUTPUT_DIR}/debug-${BOARD}-package-info.json" \ |
| --build-id="${BUILD_ID}" \ |
| --debug |
| |
| cleanup_dir |
| trap - EXIT |
| } |
| |
| usage() { |
| local exit_code="${1}" |
| |
| cat <<EOF |
| Usage: |
| ${PROG_NAME} -b <board> -i <build_id> -o <output_dir> |
| -b, --board board for which file should be created |
| -i, --build_id build_id to be used in the debug-<board>-package-info.json |
| -o, --output_dir Output directory where file will be created |
| |
| Examples: |
| $ ${PROG_NAME} \ |
| -b lakitu \ |
| -i 1.0.0 \ |
| -o /mnt/host/source/src/build/images/lakitu/1.0.0 |
| EOF |
| exit "${exit_code}" |
| } |
| |
| # Parse command line arguments. |
| parse_args() { |
| local args |
| if ! args=$(getopt \ |
| --options "b:i:o:" \ |
| --longoptions "board: build_id: output_dir:" \ |
| -- "$@"); then |
| usage 1 |
| fi |
| eval set -- "${args}" |
| |
| while :; do |
| arg="${1}" |
| shift |
| case "${arg}" in |
| -b|--board) |
| BOARD="${1}"; shift ;; |
| -i|--build_id) |
| BUILD_ID="${1}"; shift ;; |
| -o|--output_dir) |
| OUTPUT_DIR="${1}"; shift ;; |
| --) |
| break ;; |
| *) |
| echo "internal error parsing arguments!"; usage 1 ;; |
| esac |
| done |
| |
| if [[ -z "${BOARD}" || |
| -z "${BUILD_ID}" || |
| -z "${OUTPUT_DIR}" ]]; then |
| usage 1 |
| fi |
| } |
| |
| main() { |
| parse_args "$@" |
| build_debug_package_info |
| } |
| |
| main "$@" |