diff --git a/README.md b/README.md index 650f81d..927e93a 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,11 @@ Create a workflow `.yml` file in your repositories `.github/workflows` directory * `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. -* `refresh` - Refresh / upgrade the packages in the same cache. ### Outputs * `cache-hit` - A boolean value to indicate a cache was found for the packages requested. -* `package_version_list` - The packages and versions that are installed as a comma delimited list with colon delimit on the package version (i.e. \:,\:\,...). +* `package-version-list` - The packages and versions that are installed as a comma delimited list with colon delimit on the package version (i.e. \:,\:\,...). ### Cache scopes diff --git a/action.yml b/action.yml index 999ccb7..e717de5 100644 --- a/action.yml +++ b/action.yml @@ -25,44 +25,34 @@ outputs: # This compound expression is needed because lhs can be empty. # Need to output true and false instead of true and nothing. value: ${{ steps.load-cache.outputs.cache-hit || false }} - package_version_list: + package-version-list: description: 'The packages and versions that are installed as a comma delimited list with colon delimit on the package version (i.e. ::).' - value: ${{ steps.get-package-versions.outputs.package_version_list }} + value: ${{ steps.post-cache.outputs.package-version-list }} runs: using: "composite" steps: - - name: Validate Packages - run: ${{ github.action_path }}/validate_pkgs.sh "${{ inputs.version }}" ${{ inputs.packages }} - shell: bash - - - name: Create Cache Key + - id: pre-cache run: | - ${{ github.action_path }}/create_cache_key.sh "${{ inputs.version }})" ${{ inputs.packages }} + ${{ github.action_path }}/pre_cache_action.sh \ + ~/cache-apt-pkgs \ + "${{ inputs.version }}" \ + ${{ inputs.packages }} + echo "CACHE_KEY=$(cat ~/cache-apt-pkgs/cache_key.md5)" >> $GITHUB_ENV shell: bash - - name: Load Package Cache - id: load-cache + - id: load-cache uses: actions/cache@v2 with: path: ~/cache-apt-pkgs key: cache-apt-pkgs_${{ env.CACHE_KEY }} - - name: Load Packages + - id: post-cache run: | - if [ ! ${{ steps.load-cache.outputs.cache-hit }} ] || [ ${{ inputs.refresh }} ]; then - ${{ github.action_path }}/install_and_cache_pkgs.sh ~/cache-apt-pkgs ${{ inputs.packages }} - else - ${{ github.action_path }}/restore_pkgs.sh ~/cache-apt-pkgs / - fi - shell: bash - - - name: Get Package Versions - id: get-package-versions - run: | - output= - for package in ${{ inputs.packages }}; do - output=$output,$package:$(dpkg -s $package | grep Version | awk '{print $2}') - done - echo '::set-output name=package_version_list::output' + ${{ github.action_path }}/post_cache_action.sh \ + ~/cache-apt-pkgs \ + / \ + "${{ steps.load-cache.outputs.cache-hit }}" \ + ${{ inputs.packages }} + echo "::set-output name=package-version-list::$(cat ~/cache-apt-pkgs/manifest.log)" shell: bash diff --git a/create_cache_key.sh b/create_cache_key.sh deleted file mode 100755 index 3fd0536..0000000 --- a/create_cache_key.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Fail on any error. -set -e - -version=$1 -packages=${@:2} - -echo "::group::Create Cache Key" - -# Remove package delimiters, sort (requires newline) and then convert back to inline list. -normalized_list=$(echo $packages | sed 's/[\s,]+/ /g' | tr ' ' '\n' | sort | tr '\n' ' ') -echo "::debug::Normalized package list is '$normalized_list'." - -value=$(echo $normalized_list @ $version) -echo "::debug::Value to hash is '$value'." - -key=$(echo $value | md5sum | /bin/cut -f1 -d' ') -echo "::debug::Value hashed as '$key'." - -echo "::endgroup::" - -echo "CACHE_KEY=$key" >> $GITHUB_ENV \ No newline at end of file diff --git a/install_and_cache_pkgs.sh b/install_and_cache_pkgs.sh index d5a7979..bbf54dc 100755 --- a/install_and_cache_pkgs.sh +++ b/install_and_cache_pkgs.sh @@ -5,39 +5,47 @@ set -e # Directory that holds the cached packages. cache_dir=$1 + # List of the packages to use. packages="${@:2}" package_count=$(echo $packages | wc -w) -echo "::debug::Clean installing $package_count packages..." +echo "Clean installing and caching $package_count package(s)." +echo "Package list:" for package in $packages; do - echo "::debug::- $package" + echo "- $package" done -echo "::endgroup::" -mkdir -p $cache_dir - -echo "::group::Update APT Package List" -sudo apt-get update -echo "::endgroup::" +echo -n "Updating APT package list..." +sudo apt-get update > /dev/null +echo "done." +echo "Clean installing and caching $(echo $packages | wc -w) packages..." for package in $packages; do cache_filepath=$cache_dir/$package.tar.gz - echo "::group::Clean install $package" - sudo apt-get --yes install $package - echo "::endgroup::" + echo "- $package" + echo -n " Installing..." + sudo apt-get --yes install $package > /dev/null + echo "done." - echo "::group::Caching $package to $cache_filepath" + echo -n " Caching to $cache_filepath..." # Pipe all package files (no folders) to Tar. dpkg -L $package | - while IFS= read -r f; do - if test -f $f; then echo $f; fi; + while IFS= read -r f; do + if test -f $f; then echo ${f:1}; fi; #${f:1} removes the leading slash that Tar disallows done | - xargs tar -czf $cache_filepath -C / - echo "::endgroup::" + xargs tar -czf $cache_filepath -C / + echo "done." done +echo "done." -echo "::group::Finished" -echo "::debug::$(echo $packages | wc -w) package(s) installed and cached." -echo "::endgroup::" +manifest_filepath="$cache_dir/manifest.log" +echo -n "Writing package manifest to $manifest_filepath..." +manifest= +for package in $packages; do + manifest=$manifest$package:$(dpkg -s $package | grep Version | awk '{print $2}'), +done +# Remove trailing comma. +echo ${manifest:0:-1} > $manifest_filepath +echo "done." \ No newline at end of file diff --git a/post_cache_action.sh b/post_cache_action.sh new file mode 100755 index 0000000..5503013 --- /dev/null +++ b/post_cache_action.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Fail on any error. +set -e + +# Directory that holds the cached packages. +cache_dir=$1 + +# Root directory to untar the cached packages to. +# Typically filesystem root '/' but can be changed for testing. +cache_restore_root=$2 + +# Indicates that the cache was found. +cache_hit=$3 + +# List of the packages to use. +packages="${@:4}" + +script_dir=$(dirname $0) + +if [ "$cache_hit" == true ]; then + $script_dir/restore_pkgs.sh ~/cache-apt-pkgs $cache_restore_root +else + $script_dir/install_and_cache_pkgs.sh ~/cache-apt-pkgs $packages +fi +echo "" diff --git a/pre_cache_action.sh b/pre_cache_action.sh new file mode 100755 index 0000000..51a5b78 --- /dev/null +++ b/pre_cache_action.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Directory that holds the cached packages. +cache_dir=$1 + +# Version of the cache to create or load. +version=$2 + +# List of the packages to use. +packages=${@:3} + +# Create cache directory so artifacts can be saved. +mkdir -p $cache_dir + +echo -n "Validating action arguments (version='$version', packages='$packages')..."; +echo $version | grep -o " " > /dev/null +if [ $? -eq 0 ]; then + echo "aborted." + echo "Version value '$version' cannot contain spaces." >&2 + exit 1 +fi +if [ "$packages" == "" ]; then + echo "aborted." + echo "Packages argument cannot be empty." >&2 + exit 2 +fi +echo "done." + +echo -n "Verifying packages..." +for package in $packages; do + apt-cache search ^$package$ | grep $package > /dev/null + if [ $? -ne 0 ]; then + echo "aborted." + echo "Package '$package' not found." >&2 + exit 3 + fi +done +echo "done." + +# Abort on any failure at this point. +set -e + +echo "Creating cache key..." + +# Remove package delimiters, sort (requires newline) and then convert back to inline list. +normalized_list=$(echo $packages | sed 's/[\s,]+/ /g' | tr ' ' '\n' | sort | tr '\n' ' ') +echo "- Normalized package list is '$normalized_list'." + +value=$(echo $normalized_list @ $version) +echo "- Value to hash is '$value'." + +key=$(echo $value | md5sum | /bin/cut -f1 -d' ') +echo "- Value hashed as '$key'." + +echo "done." + +key_filepath="$cache_dir/cache_key.md5" +echo $key > $key_filepath +echo "Hash value written to $key_filepath" diff --git a/restore_pkgs.sh b/restore_pkgs.sh index 0c5994c..ab87879 100755 --- a/restore_pkgs.sh +++ b/restore_pkgs.sh @@ -5,29 +5,30 @@ set -e # Directory that holds the cached packages. cache_dir=$1 + # Root directory to untar the cached packages to. # Typically filesystem root '/' but can be changed for testing. cache_restore_root=$2 -# List of the packages to use. -packages="${@:3}" -cache_filenames=$(ls -1 $cache_dir | sort) -cache_filename_count=$(echo $cache_filenames | wc -w) - -echo "::group::Found $cache_filename_count files in cache." -for cache_filename in $cache_filenames; do - echo "::debug::$cache_filename" +cache_filepaths=$(ls -1 $cache_dir | sort) +echo "Found $(echo $cache_filepaths | wc -w) files in the cache." +for cache_filepath in $cache_filepaths; do + echo "- $(basename $cache_filepath)" done -echo "::endgroup::" -echo "::group::Package Restore" -for package in $packages; do - cache_filepath=$cache_dir/$package.tar.gz - echo "::debug::Restoring package $package ($cache_filepath) from cache... " - sudo tar -xf $cache_filepath -C $cache_restore_root +echo "Reading from manifest..." +for logline in $(cat $cache_dir/manifest.log | tr ',' '\n' ); do + echo "- $(echo $logline | tr ':' ' ')" done -echo "::endgroup::" +echo "done." -echo "::group::Finished" -echo "::debug::Action complete. $cache_filename_count package(s) restored." -echo "::endgroup::" \ No newline at end of file +# Only search for archived results. Manifest and cache key also live here. +cache_pkg_filepaths=$(ls -1 $cache_dir/*.tar.gz | sort) +cache_pkg_filecount=$(echo $cache_pkg_filepaths | wc -w) +echo "Restoring $cache_pkg_filecount packages from cache..." +for cache_pkg_filepath in $cache_pkg_filepaths; do + echo -n "- $(basename $cache_pkg_filepath) restoring..." + sudo tar -xf $cache_pkg_filepath -C $cache_restore_root > /dev/null + echo "done." +done +echo "done." diff --git a/validate_pkgs.sh b/validate_pkgs.sh deleted file mode 100755 index 0b24b79..0000000 --- a/validate_pkgs.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -version=$1 -packages=${@:2} - -echo "::group::Validate Action Arguments"; - -echo $version | grep -o " " > /dev/null -if [ $? -eq 0 ]; then - echo "::error::Aborted. Version value '$version' cannot contain spaces." >&2 - exit 1 -fi -echo "::debug::Version '$version' is valid." - -if [ "$packages" == "" ]; then - echo "::error::Aborted. Packages argument cannot be empty." >&2 - exit 2 -fi - -for package in $packages; do - apt-cache search ^$package$ | grep $package > /dev/null - if [ $? -ne 0 ]; then - echo "::error::Aborted. Package '$package' not found." >&2 - exit 3 - fi -done -echo "::debug::Packages '$packages' are valid." - -echo "::endgroup::"