diff --git a/README.md b/README.md index 8cdebff..830d475 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,18 @@ There are three kinds of version labels you can use. * `packages` - Space delimited list of packages to install. * `version` - Version of cache to load. Each version will have its own cache. Note, all characters except spaces are allowed. +* `add-repositories` - Space delimited list of additional repositories to pull from. Examples of potential inputs. + + ```sh + 'deb http://myserver/path/to/repo stable myrepo' + 'http://myserver/path/to/repo myrepo' + 'https://packages.medibuntu.org free non-free' + http://extras.ubuntu.com/ubuntu + ppa:user/repository + ppa:user/distro/repository + multiverse + ``` + * `execute_install_scripts` - Execute Debian package pre and post install script upon restore. See [Caveats / Non-file Dependencies](#non-file-dependencies) for more information. ### Outputs diff --git a/action.yml b/action.yml index 1e77dd8..cdbf092 100644 --- a/action.yml +++ b/action.yml @@ -24,6 +24,10 @@ inputs: description: 'Enable debugging when there are issues with action. Minor performance penalty.' required: false default: 'false' + add-repositories: + description: 'Space delimited list of additional repositories to use. See README.md for a list of examples.' + required: false + default: '' outputs: cache-hit: @@ -44,10 +48,11 @@ runs: - id: pre-cache run: | ${GITHUB_ACTION_PATH}/pre_cache_action.sh \ + "${{ inputs.debug }}" \ ~/cache-apt-pkgs \ "${{ inputs.version }}" \ - "${{ inputs.execute_install_scripts }}" \ - "${{ inputs.debug }}" \ + "${{ inputs.add-repositories }}" \ + "${{ inputs.execute_install_scripts }}" \ ${{ inputs.packages }} echo "CACHE_KEY=$(cat ~/cache-apt-pkgs/cache_key.md5)" >> $GITHUB_ENV shell: bash @@ -61,11 +66,12 @@ runs: - id: post-cache run: | ${GITHUB_ACTION_PATH}/post_cache_action.sh \ + "${{ inputs.debug }}" \ ~/cache-apt-pkgs \ / \ "${{ steps.load-cache.outputs.cache-hit }}" \ - "${{ inputs.execute_install_scripts }}" \ - "${{ inputs.debug }}" \ + "${{ inputs.add-repositories }}" \ + "${{ inputs.execute_install_scripts }}" \ ${{ inputs.packages }} function create_list { local list=$(cat ~/cache-apt-pkgs/manifest_${1}.log | tr '\n' ','); echo ${list:0:-1}; }; echo "package-version-list=$(create_list main)" >> $GITHUB_OUTPUT diff --git a/install_and_cache_pkgs.sh b/install_and_cache_pkgs.sh index f94b87c..e1b7ae6 100755 --- a/install_and_cache_pkgs.sh +++ b/install_and_cache_pkgs.sh @@ -3,23 +3,30 @@ # Fail on any error. set -e -# Debug mode for diagnosing issues. -# Setup first before other operations. -debug="${2}" -test ${debug} == "true" && set -x - # Include library. script_dir="$(dirname -- "$(realpath -- "${0}")")" source "${script_dir}/lib.sh" -# Directory that holds the cached packages. -cache_dir="${1}" +# Debug mode for diagnosing issues. +# Setup first before other operations. +debug="${1}" +validate_bool "${debug}" debug 1 +test ${debug} == "true" && set -x -# List of the packages to use. -input_packages="${@:3}" +# Directory that holds the cached packages. +cache_dir="${2}" + +# Additional repositories to use for installation. +add_repositories="${3}" # Trim commas, excess spaces, and sort. -normalized_packages="$(normalize_package_list "${input_packages}")" +normalized_repositories="$(normalize_list "${add_repositories}")" + +# List of the packages to use. +input_packages="${@:4}" + +# Trim commas, excess spaces, and sort. +normalized_packages="$(normalize_list "${input_packages}")" package_count=$(wc -w <<< "${normalized_packages}") log "Clean installing and caching ${package_count} package(s)." @@ -55,6 +62,26 @@ fi log_empty_line +# Is length of string greater than zero? +if test -z "${normalized_repositories}"; then + log "Installing software-properties-common package to add repositories..." + sudo DEBIAN_FRONTEND=noninteractive apt-fast --yes install software-properties-common > /dev/null + log "done" + + log "Verifying and adding additional repositories..." + for repository in ${normalized_repositories}; do + add-apt-repository ${repository} + done + log "done" + + repositories_filepath="${cache_dir}/repositories.log" + log "Writing added repositories list to ${repositories_filepath}" + echo "${normalized_repositories}" | tr ' ' '\n' > ${repositories_filepath} + log "done" +fi + +log_empty_line + # Strictly contains the requested packages. manifest_main="" # Contains all packages including dependencies. @@ -64,7 +91,7 @@ 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} > "${install_log_filepath}" +sudo DEBIAN_FRONTEND=noninteractive apt-fast --yes install ${normalized_packages} >> "${install_log_filepath}" log "done" log "Installation log written to ${install_log_filepath}" diff --git a/lib.sh b/lib.sh index c2f1ec9..4abc31a 100755 --- a/lib.sh +++ b/lib.sh @@ -118,19 +118,20 @@ function log_err { >&2 echo "$(date +%H:%M:%S)" "${@}"; } function log_empty_line { echo ""; } ############################################################################### -# Sorts given packages by name and split on commas. +# Sorts given list by name and split on commas. # Arguments: -# The comma delimited list of packages. +# The comma delimited list. # Returns: -# Sorted list of space delimited packages. +# Sorted list of space delimited elements. ############################################################################### -function normalize_package_list { - local stripped=$(echo "${1}" | sed 's/,//g') +function normalize_list { + local stripped=$(echo "${1}" | sed 's/\s*,\s*/ /g' | sed 's/\s+/ /g') # Remove extraneous spaces at the middle, beginning, and end. local trimmed="$(\ echo "${stripped}" \ | sed 's/\s\+/ /g; s/^\s\+//g; s/\s\+$//g')" - local sorted="$(echo ${trimmed} | tr ' ' '\n' | sort | tr '\n' ' ')" + local sorted="$(echo ${trimmed} | tr ' ' '\n' | sort)" + # Echos as an inlined list (not newlines). echo "${sorted}" } diff --git a/post_cache_action.sh b/post_cache_action.sh index 25e7da3..68d9286 100755 --- a/post_cache_action.sh +++ b/post_cache_action.sh @@ -7,31 +7,36 @@ set -e script_dir="$(dirname -- "$(realpath -- "${0}")")" source "${script_dir}/lib.sh" +# Debug mode for diagnosing issues. +# Setup first before other operations. +debug="${1}" +validate_bool "${debug}" debug 1 +test ${debug} == "true" && set -x + # Directory that holds the cached packages. -cache_dir="${1}" +cache_dir="${2}" # Root directory to untar the cached packages to. # Typically filesystem root '/' but can be changed for testing. # WARNING: If non-root, this can cause errors during install script execution. -cache_restore_root="${2}" +cache_restore_root="${3}" # Indicates that the cache was found. -cache_hit="${3}" +cache_hit="${4}" + +# Additional repositories to use for installation. +add_repositories="${5}" # Cache and execute post install scripts on restore. -execute_install_scripts="${4}" - -# Debug mode for diagnosing issues. -debug="${5}" -test ${debug} == "true" && set -x +execute_install_scripts="${6}" # List of the packages to use. -packages="${@:6}" +packages="${@:7}" if [ "$cache_hit" == true ]; then - ${script_dir}/restore_pkgs.sh "${cache_dir}" "${cache_restore_root}" "${execute_install_scripts}" "${debug}" + ${script_dir}/restore_pkgs.sh "${debug}" "${cache_dir}" "${cache_restore_root}" "${execute_install_scripts}" else - ${script_dir}/install_and_cache_pkgs.sh "${cache_dir}" "${debug}" ${packages} + ${script_dir}/install_and_cache_pkgs.sh "${debug}" "${cache_dir}" "${add_repositories}" ${packages} fi log_empty_line diff --git a/pre_cache_action.sh b/pre_cache_action.sh index 030f3b5..a37c064 100755 --- a/pre_cache_action.sh +++ b/pre_cache_action.sh @@ -1,5 +1,6 @@ #!/bin/bash +# Fail on any error. set -e # Include library. @@ -8,32 +9,35 @@ source "${script_dir}/lib.sh" # Debug mode for diagnosing issues. # Setup first before other operations. -debug="${4}" +debug="${1}" validate_bool "${debug}" debug 1 test ${debug} == "true" && set -x # Directory that holds the cached packages. -cache_dir="${1}" +cache_dir="${2}" # Version of the cache to create or load. -version="${2}" +version="${3}" -# Execute post-installation script. -execute_install_scripts="${3}" - -# Debug mode for diagnosing issues. -debug="${4}" - -# List of the packages to use. -input_packages="${@:5}" +# Additional repositories to include. +add_repositories="${4}" # Trim commas, excess spaces, and sort. -packages="$(normalize_package_list "${input_packages}")" +repositories="$(normalize_list "${add_repositories}")" + +# Execute post-installation script. +execute_install_scripts="${5}" + +# List of the packages to use. +packages="${@:6}" + +# Trim commas, excess spaces, and sort. +normalized_packages="$(normalize_list "${packages}")" # Create cache directory so artifacts can be saved. mkdir -p ${cache_dir} -log "Validating action arguments (version='${version}', packages='${packages}')..."; +log "Validating action arguments (version='${version}', packages='${normalized_packages}')..."; if grep -q " " <<< "${version}"; then log "aborted" log "Version value '${version}' cannot contain spaces." >&2 @@ -41,7 +45,7 @@ if grep -q " " <<< "${version}"; then fi # Is length of string zero? -if test -z "${packages}"; then +if test -z "${normalized_packages}"; then log "aborted" log "Packages argument cannot be empty." >&2 exit 3 @@ -55,7 +59,7 @@ log_empty_line versioned_packages="" log "Verifying packages..." -for package in ${packages}; do +for package in ${normalized_packages}; do if test ! "$(apt-cache show "${package}")"; then echo "aborted" log "Package '${package}' not found." >&2 @@ -74,17 +78,23 @@ set -e log "Creating cache key..." # TODO Can we prove this will happen again? -normalized_versioned_packages="$(normalize_package_list "${versioned_packages}")" +normalized_versioned_packages="$(normalize_list "${versioned_packages}")" log "- Normalized package list is '${normalized_versioned_packages}'." -value="${normalized_versioned_packages} @ ${version}" -log "- Value to hash is '${value}'." +# Create value to hash for cache key. +value_to_hash="${normalized_versioned_packages}" +if test -n "${repositories}"; then + log "- Added repository list is '${repositories}'." + value_to_hash="${value_to_hash} add-repositories:'${repositories}'" +fi +value_to_hash="${value_to_hash}@ ${version}" -key="$(echo "${value}" | md5sum | cut -f1 -d' ')" -log "- Value hashed as '${key}'." +# Hash the value and set the key. +log "- Value to hash is '${value_to_hash}'." +hash_key="$(echo "${value_to_hash}" | md5sum | cut -f1 -d' ')" +log "- Value hashed as '${hash_key}'." -log "done" - -key_filepath="${cache_dir}/cache_key.md5" -echo ${key} > ${key_filepath} -log "Hash value written to ${key_filepath}" +# Write the key out to match for future runs. +hash_key_filepath="${cache_dir}/cache_key.md5" +echo ${hash_key} > ${hash_key_filepath} +log "Hash value written to ${hash_key_filepath}" diff --git a/restore_pkgs.sh b/restore_pkgs.sh index fec5b29..b7a8c80 100755 --- a/restore_pkgs.sh +++ b/restore_pkgs.sh @@ -3,25 +3,27 @@ # Fail on any error. set -e -# Debug mode for diagnosing issues. -# Setup first before other operations. -debug="${4}" -test ${debug} == "true" && set -x - # Include library. script_dir="$(dirname -- "$(realpath -- "${0}")")" source "${script_dir}/lib.sh" +# Debug mode for diagnosing issues. +# Setup first before other operations. +debug="${1}" +validate_bool "${debug}" debug 1 +test ${debug} == "true" && set -x + # Directory that holds the cached packages. -cache_dir="${1}" +cache_dir="${2}" # Root directory to untar the cached packages to. # Typically filesystem root '/' but can be changed for testing. -cache_restore_root="${2}" +# WARNING: If non-root, this can cause errors during install script execution. +cache_restore_root="${3}" test -d ${cache_restore_root} || mkdir ${cache_restore_root} # Cache and execute post install scripts on restore. -execute_install_scripts="${3}" +execute_install_scripts="${4}" cache_filepaths="$(ls -1 "${cache_dir}" | sort)" log "Found $(echo ${cache_filepaths} | wc -w) files in the cache."