Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add package caching #6

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/cache-perf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Cache performance testing

# Only run manually: the purpose of this test is to check how much (if at all)
# using the caches helps, and that's not something that needs doing often, and
# it is something that's time consuming.
on: workflow_dispatch

# Avoid running at the same time as other actions that interfere with caches,
# to avoid pollution.
concurrency: caches

jobs:
clear-caches:
uses: ./.github/workflows/clear-caches.yml
permissions:
actions: write

# There should now be no cache, so we can test how long it takes to do an
# install without a cache while building the cache for the later action.
install-without-cache:
runs-on: windows-latest
needs: clear-caches
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Install a large set of Cygwin packages
uses: ./
with:
packages: >
biber doxygen evolution kde-dev-utils
mkvtoolnix-debuginfo nghttp x11vnc
package-cache: saveonly

install-with-cache:
runs-on: windows-latest
needs: install-without-cache
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Install a large set of Cygwin packages
uses: ./
with:
packages: >
biber doxygen evolution kde-dev-utils
mkvtoolnix-debuginfo nghttp x11vnc
package-cache: enabled
173 changes: 173 additions & 0 deletions .github/workflows/cache-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: Caching tests

on: [push, pull_request]

# Ensure there's only a single version of this running in any repo, so one set
# of tests won't create or destroy caches that interfere with another run.
concurrency: caches

jobs:
clear-caches:
uses: ./.github/workflows/clear-caches.yml
permissions:
actions: write

test-caching:
runs-on: windows-latest

needs: clear-caches

# Ordering is important here to ensure the correct things are in the
# correct caches at the correct times.
#
# This also relies on having six Cygwin packages that don't have any
# cross-dependencies (and ideally are small and have few dependencies of
# their own), so we can distinguish what's cached at what step.
#
# We test for the correct behaviour in the following circumstances:
#
# option | saves | restores
# ------------+---------+----------
# disabled | no (1) | no (5)
# enabled | yes (2) | yes (6)
# saveonly | yes (3) | no (7)
# restoreonly | no (4) | yes (8)
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Install Cygwin + bash_completion, no caching
uses: ./
with:
packages: bash-completion
package-cache: disabled

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*

- name: Install Cygwin + brotli, with caching
uses: ./
with:
packages: brotli
package-cache: enabled

# This assumes 6 and tests 1
- name: Ensure bash-completion not downloaded
shell: C:\cygwin\bin\bash.exe --noprofile --norc -e -o pipefail -o igncr {0}
run: |
for file in /cygdrive/c/cygwin-packages/*/*/*/*/bash-completion-*.tar.*; do
[[ -f "$file" ]] && exit 1
done
exit 0

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*

- name: Install Cygwin + libyajl2, with caching
uses: ./
with:
packages: libyajl2
package-cache: enabled

# This tests 2 and 6
- name: Ensure brotli downloaded
shell: C:\cygwin\bin\bash.exe --noprofile --norc -e -o pipefail -o igncr {0}
run: |
for file in /cygdrive/c/cygwin-packages/*/*/*/*/brotli-*.tar.*; do
[[ -f "$file" ]] && exit 0
done
exit 1

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*

- name: Install Cygwin + mksh, saveonly
uses: ./
with:
packages: mksh
package-cache: saveonly

# This assumes 2 and tests 7
- name: Ensure libyajl2 not downloaded
shell: C:\cygwin\bin\bash.exe --noprofile --norc -e -o pipefail -o igncr {0}
run: |
for file in /cygdrive/c/cygwin-packages/*/*/*/*/libyajl2-*.tar.*; do
[[ -f "$file" ]] && exit 1
done
exit 0

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*

- name: Install Cygwin + libgif7, restoreonly
uses: ./
with:
packages: libgif7
package-cache: restoreonly

# This tests 3 and 8
- name: Ensure mksh downloaded
shell: C:\cygwin\bin\bash.exe --noprofile --norc -e -o pipefail -o igncr {0}
run: |
for file in /cygdrive/c/cygwin-packages/*/*/*/*/mksh-*.tar.*; do
[[ -f "$file" ]] && exit 1
done
exit 0

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*

- name: Install Cygwin, restoreonly
uses: ./
with:
package-cache: restoreonly

# This assumes 8 and tests 4
- name: Ensure libgif7 not downloaded
shell: C:\cygwin\bin\bash.exe --noprofile --norc -e -o pipefail -o igncr {0}
run: |
for file in /cygdrive/c/cygwin-packages/*/*/*/*/libgif7-*.tar.*; do
[[ -f "$file" ]] && exit 1
done
exit 0

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*

- name: Install Cygwin, caching disabled
uses: ./
with:
package-cache: disabled

# This assumes 3 and tests 5
- name: Ensure mksh not downloaded
shell: C:\cygwin\bin\bash.exe --noprofile --norc -e -o pipefail -o igncr {0}
run: |
for file in /cygdrive/c/cygwin-packages/*/*/*/*/mksh-*.tar.*; do
[[ -f "$file" ]] && exit 1
done
exit 0

- name: Delete the Cygwin installation and downloaded packages
run: |
Remove-Item -Force -Recurse C:\cygwin
Remove-Item -Force -Recurse C:\cygwin-packages
Remove-Item -Force -Recurse C:\cygwin-packages-checksum.*
29 changes: 29 additions & 0 deletions .github/workflows/clear-caches.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Clear Cygwin package caches

on: workflow_call

jobs:
clear-caches:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
# This will only delete up to 100 caches. That should be far more than
# is ever needed.
- name: Delete cache entries
uses: actions/github-script@v6
with:
script: |
const response = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
key: 'cygwin-install-action-packages-'
});
for (const cache of response.data.actions_caches) {
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id
});
}
51 changes: 43 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ Please fix my terrible cargo-cult PowerShell.
Parameters
----------

| Input | Default | Description
| ----------- | -------------------------------------------- | -----------
| platform | x86_64 | Install the x86 or x86\_64 version of Cygwin.
| packages | *none* | List of additional packages to install.
| install-dir | C:\cygwin | Installation directory
| site | http://mirrors.kernel.org/sourceware/cygwin/ | Mirror site to install from
| check-sig | true | Whether to check the setup.ini signature
| add-to-path | true | Whether to add Cygwin's `/bin` directory to the system `PATH`
| Input | Default | Description
| ------------- | -------------------------------------------- | -----------
| platform | x86_64 | Install the x86 or x86\_64 version of Cygwin.
| packages | *none* | List of additional packages to install.
| install-dir | C:\cygwin | Installation directory
| site | http://mirrors.kernel.org/sourceware/cygwin/ | Mirror site to install from
| check-sig | true | Whether to check the setup.ini signature
| add-to-path | true | Whether to add Cygwin's `/bin` directory to the system `PATH`
| package-cache | disabled | Whether to cache the package downloads

Line endings
------------
Expand Down Expand Up @@ -85,6 +86,40 @@ those executables directly in a `run:` in your workflow. Execute them via
Alternatively, putting e.g. `CYGWIN=winsymlinks:native` into the workflow's
environment works, since setup now honours that.

Caching
-------

If you're likely to do regular builds, you might want to store the packages
locally rather than needing to download them from the Cygwin mirrors on every
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure "locally" is the best word to use here.

build. Set `package-cache` to `enabled` and the action will use [GitHub's
dependency caching][0] to store downloaded package files between runs.

[0]: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows

This has the effect of speeding up the run of the installation itself, at the
expense of taking slightly longer before and after the installation to check
and potentially update the cache. The installer will still check for updated
packages, and will download new packages if the cached ones are out of date

In certain circumstances you might want to ignore any existing caches but still
store a new one, or restore a cache but not write one. Do this by setting
`package-cache` to `saveonly` or `restoreonly` as appropriate. This is
particularly useful when calling the action multiple times in the same run,
where you probably want to restore the cache the first time the action is
called, then save it the last time it is called.

You should make sure to clear these caches every so often. This action, like
the underlying Cygwin installer, doesn't remove old package files from its
download directory, so if you don't clear the caches occasionally (and you run
builds often enough that GitHub doesn't do it for you automatically) you'll
find the caches keep getting larger as they gain more and more outdated and
unused packages. Either [delete them manually][1], [use a separate action or
API call][2], or do occasional runs with `saveonly` to create a fresher small
cache.

[1]: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#deleting-cache-entries
[2]: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#deleting-cache-entries

Mirrors and signatures
----------------------

Expand Down
45 changes: 45 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,35 @@ inputs:
description: Should Cygwin's bin directory be added to the system PATH?
required: false
default: true
package-cache:
description: Cache package downloads for speed
required: false
default: disabled

runs:
using: "composite"
steps:
- uses: actions/cache/restore@v3
if: inputs.package-cache-behaviour == 'enabled' || inputs.package-cache-behaviour == 'restoreonly'
with:
key: cygwin-install-action-packages-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}-${{ github.action }}
path: C:\cygwin-packages
restore-keys:
cygwin-install-action-packages-${{ github.run_id }}-${{ github.job }}-${{ github.run_attempt }}-
cygwin-install-action-packages-${{ github.run_id }}-${{ github.job }}-
cygwin-install-action-packages-${{ github.run_id }}-
cygwin-install-action-packages-

- if: inputs.package-cache-behaviour == 'enabled' || inputs.package-cache-behaviour == 'restoreonly'
working-directory: C:\
shell: bash
run: |
if [[ -d cygwin-packages ]]; then
find cygwin-packages -type f ! -name setup.ini -print0 |
sort -z |
xargs -0 b2sum >cygwin-packages-checksum.old
fi

- run: |
$platform = '${{ inputs.platform }}'
$platform = $platform -replace '^(x64|amd64)$', 'x86_64'
Expand Down Expand Up @@ -82,6 +107,26 @@ runs:
& C:\setup.exe $args | Out-Default
shell: powershell

- if: inputs.package-cache-behaviour == 'enabled' || inputs.package-cache-behaviour == 'saveonly'
id: refresh-cache
working-directory: C:\
shell: bash
run: |
if [[ -d cygwin-packages ]]; then
find cygwin-packages -type f ! -name setup.ini -print0 |
sort -z |
xargs -0 b2sum >cygwin-packages-checksum.new
if ! diff cygwin-packages-checksum.old cygwin-packages-checksum.new; then
printf 'update_package_cache=YesPlease\n' >>"$GITHUB_OUTPUT"
fi
fi

- if: steps.refresh-cache.outputs.update_package_cache != ''
uses: actions/cache/save@v3
with:
key: cygwin-install-action-packages-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}-${{ github.action }}
path: C:\cygwin-packages

- if: ${{ inputs.add-to-path == 'true' }}
run: echo "${{ inputs.install-dir }}\bin" >> $env:GITHUB_PATH
shell: powershell
Expand Down