From 91b541353e1d2884dd3899699101aa19ec930206 Mon Sep 17 00:00:00 2001 From: Andrew Walsh Date: Tue, 2 Aug 2022 21:14:51 -0700 Subject: [PATCH] Fix issues #36, #37, and minor refactors. (#40) (#41) * Bump license year. * Fix pre-existing dep bug in issue #36. * Account for packages without deps. * Fix bug in issue #37 by combining install and dep listing reads. Ensures only installed deps are cached. * Fix bad log lines. * Use apt-fast to show package information and remove CLI warning message. * Switch to apt-cache for package verification and remove CLI warning message. --- LICENSE | 2 +- install_and_cache_pkgs.sh | 66 +++++++++++++++------------------------ lib.sh | 32 ++++++++++++++----- pre_cache_action.sh | 16 +++++++--- 4 files changed, 62 insertions(+), 54 deletions(-) diff --git a/LICENSE b/LICENSE index a10a977..7122f41 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2021 Andrew Walsh +Copyright 2022 Andrew Walsh Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/install_and_cache_pkgs.sh b/install_and_cache_pkgs.sh index 2e7bc04..c0a30cc 100755 --- a/install_and_cache_pkgs.sh +++ b/install_and_cache_pkgs.sh @@ -7,9 +7,6 @@ set -e script_dir="$(dirname -- "$(realpath -- "${0}")")" source "${script_dir}/lib.sh" -# Install apt-fast for optimized installs. -/bin/bash -c "$(curl -sL https://git.io/vokNn)" - # Directory that holds the cached packages. cache_dir="${1}" @@ -24,10 +21,14 @@ log "Clean installing and caching ${package_count} package(s)." log_empty_line +manifest_main="" log "Package list:" for package in ${normalized_packages}; do - log "- ${package}" + read package_name package_ver < <(get_package_name_ver "${package}") + manifest_main="${manifest_main}${package_name}:${package_ver}," + log "- ${package_name}:${package_ver}" done +write_manifest "main" "${manifest_main}" "${cache_dir}/manifest_main.log" log_empty_line @@ -42,51 +43,35 @@ manifest_main="" # Contains all packages including dependencies. manifest_all="" -log "Gathering install information for ${package_count} packages..." -log_empty_line -cached_packages="" -for package in ${normalized_packages}; do - read package_name package_ver < <(get_package_name_ver "${package}") - - # Comma delimited name:ver pairs in the main requested packages manifest. - manifest_main="${manifest_main}${package_name}:${package_ver}," - - cached_packages="${cached_packages} ${package_name}:${package_version}" - read dep_packages < <(get_dep_packages "${package_name}") - cached_packages="${cached_packages} $(echo ${dep_packages} | tr '\n' ' ')" - - if test -z "${dep_packages}"; then - dep_packages_text="none"; - else - dep_packages_text="${dep_packages}" - fi - - log "- ${package_name}" - log " * Version: ${package_ver}" - log " * Dependencies: ${dep_packages_text}" - log_empty_line -done -log "done" - -log_empty_line +install_log_filepath="${cache_dir}/install.log" log "Clean installing ${package_count} packages..." # Zero interaction while installing or upgrading the system via apt. -sudo DEBIAN_FRONTEND=noninteractive apt-fast --yes install ${normalized_packages} > /dev/null +sudo DEBIAN_FRONTEND=noninteractive apt-fast --yes install ${normalized_packages} > "${install_log_filepath}" log "done" +log "Installation log written to ${install_log_filepath}" log_empty_line -cached_package_count=$(wc -w <<< "${cached_packages}") -log "Caching ${cached_package_count} installed packages..." -for cached_package in ${cached_packages}; do - cache_filepath="${cache_dir}/${cached_package}.tar.gz" +installed_packages=$(get_installed_packages "${install_log_filepath}") +log "Installed package list:" +for installed_package in ${installed_packages}; do + log "- ${installed_package}" +done +log_empty_line + +installed_package_count=$(wc -w <<< "${installed_packages}") +log "Caching ${installed_package_count} installed packages..." +for installed_package in ${installed_packages}; do + cache_filepath="${cache_dir}/${installed_package}.tar.gz" + + # Sanity test in case APT enumerates duplicates. if test ! -f "${cache_filepath}"; then - read cached_package_name cached_package_ver < <(get_package_name_ver "${cached_package}") - log " * Caching ${cached_package_name} to ${cache_filepath}..." + read installed_package_name installed_package_ver < <(get_package_name_ver "${installed_package}") + log " * Caching ${installed_package_name} to ${cache_filepath}..." # Pipe all package files (no folders) to Tar. - dpkg -L "${cached_package_name}" | + dpkg -L "${installed_package_name}" | while IFS= read -r f; do if test -f $f || test -L $f; then echo "${f:1}"; fi; #${f:1} removes the leading slash that Tar disallows done | @@ -95,11 +80,10 @@ for cached_package in ${cached_packages}; do fi # Comma delimited name:ver pairs in the all packages manifest. - manifest_all="${manifest_all}${cached_package_name}:${cached_package_ver}," + manifest_all="${manifest_all}${installed_package_name}:${installed_package_ver}," done log "done (total cache size $(du -h ${cache_dir} | tail -1 | awk '{print $1}'))" log_empty_line write_manifest "all" "${manifest_all}" "${cache_dir}/manifest_all.log" -write_manifest "main" "${manifest_main}" "${cache_dir}/manifest_main.log" diff --git a/lib.sh b/lib.sh index edabb1a..0aedaee 100755 --- a/lib.sh +++ b/lib.sh @@ -9,15 +9,28 @@ function normalize_package_list { echo "${sorted}" } -# Gets a package list of dependencies as newline delimited pairs -# :\n... -function get_dep_packages { - echo $(apt-fast install --dry-run --yes "${1}" | \ - grep "^Inst" | sort | awk '{print $2 $3}' | \ - tr '(' ':' | grep -v "${1}:") +# Gets a list of installed packages as space delimited pairs with each pair colon delimited. +# : ... +function get_installed_packages { + install_log_filepath="${1}" + local regex="^Unpacking ([^ :]+)([^ ]+)? (\[[^ ]+\]\s)?\(([^ )]+)" + dep_packages="" + while read -r line; do + if [[ "${line}" =~ ${regex} ]]; then + dep_packages="${dep_packages}${BASH_REMATCH[1]}:${BASH_REMATCH[4]} " + else + log_err "Unable to parse package name and version from \"${line}\"" + exit 2 + fi + done < <(grep "^Unpacking " ${install_log_filepath}) + if test -n "${dep_packages}"; then + echo "${dep_packages:0:-1}" # Removing trailing space. + else + echo "" + fi } -# Split fully qualified package into name and version +# Split fully qualified package into name and version. function get_package_name_ver { IFS=\: read name ver <<< "${1}" # If version not found in the fully qualified package value. @@ -28,13 +41,16 @@ function get_package_name_ver { } function log { echo "$(date +%H:%M:%S)" "${@}"; } +function log_err { >&2 echo "$(date +%H:%M:%S)" "${@}"; } function log_empty_line { echo ""; } # Writes the manifest to a specified file. function write_manifest { log "Writing ${1} packages manifest to ${3}..." - # 0:-1 to remove trailing comma, delimit by newline and sort + # 0:-1 to remove trailing comma, delimit by newline and sort. echo "${2:0:-1}" | tr ',' '\n' | sort > ${3} log "done" } + +get_installed_packages "/tmp/cache-apt-pkgs-action-cache/install.log" diff --git a/pre_cache_action.sh b/pre_cache_action.sh index b6755ed..c2fe2d6 100755 --- a/pre_cache_action.sh +++ b/pre_cache_action.sh @@ -19,7 +19,7 @@ packages="$(normalize_package_list "${input_packages}")" # Create cache directory so artifacts can be saved. mkdir -p ${cache_dir} -log -n "Validating action arguments (version='${version}', packages='${packages}')..."; +log "Validating action arguments (version='${version}', packages='${packages}')..."; if grep -q " " <<< "${version}"; then log "aborted" log "Version value '${version}' cannot contain spaces." >&2 @@ -32,14 +32,22 @@ if test -z "${packages}"; then log "Packages argument cannot be empty." >&2 exit 2 fi + +log "done" + +log_empty_line + +log "Installing apt-fast for optimized installs..." +# Install apt-fast for optimized installs. +/bin/bash -c "$(curl -sL https://git.io/vokNn)" log "done" log_empty_line versioned_packages="" -log -n "Verifying packages..." +log "Verifying packages..." for package in ${packages}; do - if test ! "$(apt show "${package}")"; then + if test ! "$(apt-cache show "${package}")"; then echo "aborted" log "Package '${package}' not found." >&2 exit 3 @@ -47,7 +55,7 @@ for package in ${packages}; do read package_name package_ver < <(get_package_name_ver "${package}") versioned_packages=""${versioned_packages}" "${package_name}"="${package_ver}"" done -echo "done" +log "done" log_empty_line