Skip to content

Commit 216c225

Browse files
Use split caching to cache deps even if the later build fails
1 parent 11af036 commit 216c225

1 file changed

Lines changed: 156 additions & 35 deletions

File tree

.github/workflows/haskell.yml

Lines changed: 156 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ jobs:
9090
# If you have not committed packcheck.sh in your repo at PACKCHECK
9191
# then it is automatically pulled from this URL.
9292
PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
93-
PACKCHECK_GITHUB_COMMIT: "3d3c94bf48f18a99271d509c1f1702d15824b1f0"
93+
PACKCHECK_GITHUB_COMMIT: "44902d709e53ea1bbbe00934541e15a9f62ab77f"
9494

9595
# ------------------------------------------------------------------------
9696
# Final build variables
@@ -106,23 +106,26 @@ jobs:
106106
fail-fast: false
107107
matrix:
108108

109-
# The order of jobs is important to optimize fail-fast.
109+
# The order of jobs is important to optimize fail-fast, if
110+
# fail-fast is set to true.
110111

111112
# This section is to order the important jobs first especially for
112113
# "fail-fast" so that these are the ones started first.
113114
#name:
114115
# - ci
115116

116-
# The name of the CI is built using the name and other info from CI,
117-
# therefore, the "name" field can be same for all tests here.
118-
#
119-
# The reason we have an explicit "name" field here is to force
120-
# an additional config instead of adding to an existing config
121-
# while adding additional configs.
117+
# IMPORTANT NOTE:
118+
# If runner, command, ghc version are identical then the name of
119+
# CI is used to distinguish the cache key.
120+
121+
# The reason we have an explicit "name" field in the following
122+
# entries is to force an additional config instead of adding to
123+
# an existing config while adding additional configs.
122124
# Look at <https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix>
123125
# for more info about adding matrix elements.
124126
# Adding any element to the list will increase the number of matrix
125127
# elements proportional to the cross product.
128+
126129
include:
127130

128131
#- name: ci
@@ -219,6 +222,8 @@ jobs:
219222
runner: windows-latest
220223
command: cabal
221224
ghc_version: 9.12.4
225+
# WARNING! cannot use # comments inside pack_options.
226+
# DISABLE_SDIST_BUILD for shorter paths on Windows
222227
pack_options: >-
223228
DISABLE_SDIST_BUILD="y"
224229
@@ -246,7 +251,27 @@ jobs:
246251
# Usually you do need to change anything below, this is generic code for
247252
# caching and running packcheck on Linux/Mac/Windows.
248253
#-----------------------------------------------------------------------------
254+
249255
steps:
256+
257+
- name: Optimize Windows Runner Environment
258+
if: runner.os == 'Windows'
259+
shell: powershell
260+
run: |
261+
# Enable long paths. Sometimes failures occur due to path
262+
# length limitation.
263+
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -value 1
264+
265+
# Cache saving is very slow on Windows, it could be due to tar,
266+
# or the compression program or the file system. Changing the
267+
# compression level of zstd does not help. We are also not able to pick
268+
# another tar program by changing the path, tar is picked up by the
269+
# cache action itself.
270+
271+
# This does not seem to make much difference.
272+
# Disable Windows Defender to speed up IO/Tar operations
273+
Set-MpPreference -DisableRealtimeMonitoring $true
274+
250275
- uses: actions/checkout@v4
251276

252277
# This should happen before cache restore.
@@ -255,34 +280,49 @@ jobs:
255280
run: |
256281
rm -f ~/.ghcup
257282
258-
- name: Cache hackage package index (non-Windows)
259-
uses: actions/cache@v4
283+
# See the "cabal path" output in the CI logs to tweak the cache
284+
# locations.
285+
286+
# Shared by all tests, all platforms
287+
- name: Restore hackage package index (non-Windows)
288+
id: restore-hackage
289+
uses: actions/cache/restore@v4
260290
if: runner.os != 'Windows'
261291
with:
262292
path: |
263293
~/.cache/cabal/packages
264-
# Bump the key version to clear the cache
265-
key: cache-cabal-packages
266-
267-
# See the "cabal path" output in the CI logs to tweak the cache locations
268-
# ghc is big but cheap to install, if cache size is a concern we can avoid
269-
# caching it.
270-
- name: Cache ghcup and ghc (non-Windows)
271-
uses: actions/cache@v4
294+
key: cabal-hackage-index-non-windows
295+
296+
# GHC is not test/options specific
297+
- name: Restore ghcup and ghc (non-Windows)
298+
id: restore-ghcup
299+
uses: actions/cache/restore@v4
272300
if: runner.os != 'Windows'
273301
with:
274302
path: |
275303
~/.ghcup
276-
key: ${{ matrix.runner }}-${{ matrix.ghc_version }}.${{ matrix.ghc_salt}}
304+
key: ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}
305+
306+
# GHC is not test/options specific
307+
#- name: Restore ghcup and ghc (Windows)
308+
# id: restore-ghcup-win
309+
# uses: actions/cache/restore@v4
310+
# if: runner.os == 'Windows'
311+
# with:
312+
# path: |
313+
# C:/ghcup
314+
# key: ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}
277315

278316
# XXX If we want to invalidate the cache on resolver change we
279317
# should use a separate cache for stack as it should be keyed on
280318
# resolver as well. But that requires resolver as a matrix element
281319
# and then copied to pack_options from there, needs some work. It
282320
# should be fine as resolver minor version change can only increase
283321
# the cache size.
284-
- name: Cache build dependencies (non-Windows)
285-
uses: actions/cache@v4
322+
# Deps are test/options specific
323+
- name: Restore build dependencies (non-Windows)
324+
id: restore-deps-nonwin
325+
uses: actions/cache/restore@v4
286326
if: runner.os != 'Windows'
287327
with:
288328
# cabal: ~/.local/bin, ~/.local/state/cabal
@@ -292,18 +332,17 @@ jobs:
292332
~/.local/bin
293333
~/.local/state/cabal
294334
~/.stack
295-
# Bump the key version to clear the cache
296-
key: ${{ matrix.runner }}-${{ matrix.command }}-${{ matrix.ghc_version }}-${{ matrix.name }}-v1
335+
key: ${{ matrix.command }}-deps-ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}-${{ matrix.name }}
297336

298-
- name: Cache common directories (Windows)
299-
uses: actions/cache@v4
337+
# Deps are test/options specific
338+
- name: Restore build dependencies, hackage index, local/bin (Windows)
339+
id: restore-deps-win
340+
uses: actions/cache/restore@v4
300341
if: runner.os == 'Windows'
301342
with:
302343
path: |
303-
${{ env.APPDATA }}/local
304-
C:/ghcup
305344
C:/cabal
306-
key: ${{ matrix.runner }}-${{ matrix.command }}-${{ matrix.ghc_version }}-${{ matrix.name }}-v1
345+
key: ${{ matrix.command }}-deps-ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}-${{ matrix.name }}
307346

308347
- name: Download packcheck
309348
# on windows-latest GitHub Actions defaults to PowerShell
@@ -323,7 +362,8 @@ jobs:
323362
chmod +x $PACKCHECK
324363
fi
325364
326-
- name: Run packcheck
365+
- name: Run packcheck (dependencies only)
366+
id: deps-only
327367
# on windows-latest GitHub Actions defaults to PowerShell
328368
shell: bash
329369
run: |
@@ -344,6 +384,8 @@ jobs:
344384
export GHCUP_INSTALL_BASE_PREFIX=$HOME
345385
;;
346386
CYGWIN*|MINGW*|MSYS*)
387+
# To keep the paths shorter on Windows
388+
# XXX Will docspec work with this?
347389
export CABAL_BUILDDIR="C:\b"
348390
PATH_VAR="$PATH_VAR:/c/Program Files/7-Zip:/mingw64/bin"
349391
;;
@@ -352,20 +394,99 @@ jobs:
352394
# arguments in PACKCHECK_COMMAND e.g. DOCSPEC_OPTIONS="--timeout 60".
353395
# Direct invocation would word-split on spaces inside quoted values.
354396
echo "$PACKCHECK $PACKCHECK_COMMAND PATH=\"$PATH_VAR\""
355-
bash -c "$PACKCHECK $PACKCHECK_COMMAND PATH=\"$PATH_VAR\""
397+
bash -c "$PACKCHECK $PACKCHECK_COMMAND BUILD_ONLY_DEPS=y PATH=\"$PATH_VAR\""
398+
399+
- name: Save hackage package index (non-Windows)
400+
uses: actions/cache/save@v4
401+
if: always() && steps.deps-only.outcome == 'success' && runner.os != 'Windows' && steps.restore-hackage.outputs.cache-hit != 'true'
402+
with:
403+
path: ~/.cache/cabal/packages
404+
key: cabal-hackage-index-non-windows
405+
406+
- name: Save ghcup and ghc (non-Windows)
407+
uses: actions/cache/save@v4
408+
if: always() && steps.deps-only.outcome == 'success' && runner.os != 'Windows' && steps.restore-ghcup.outputs.cache-hit != 'true'
409+
with:
410+
path: ~/.ghcup
411+
key: ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}
412+
413+
# On Windows, ghc restore step takes 2-3 minutes whereas installing
414+
# GHC takes less than 2 minutes. On top of this saving the ghc cache
415+
# takes 7 minutes. So this does not make sense.
416+
#- name: Save ghcup and ghc (Windows)
417+
# uses: actions/cache/save@v4
418+
# if: always() && steps.deps-only.outcome == 'success' && runner.os == 'Windows' && steps.restore-ghcup-win.outputs.cache-hit != 'true'
419+
# with:
420+
# path: |
421+
# C:/ghcup
422+
# key: ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}
423+
424+
# Deps are test/options specific, hence, matrix.name in the key
425+
- name: Save build dependencies (non-Windows)
426+
uses: actions/cache/save@v4
427+
if: always() && steps.deps-only.outcome == 'success' && runner.os != 'Windows' && steps.restore-deps-nonwin.outputs.cache-hit != 'true'
428+
with:
429+
path: |
430+
~/.local/bin
431+
~/.local/state/cabal
432+
~/.stack
433+
key: ${{ matrix.command }}-deps-ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}-${{ matrix.name }}
434+
435+
# hackage package index is part of C:/cabal
436+
# Deps are test/options specific, hence, matrix.name in the key
437+
- name: Save build dependencies (Windows)
438+
uses: actions/cache/save@v4
439+
if: always() && steps.deps-only.outcome == 'success' && runner.os == 'Windows' && steps.restore-deps-win.outputs.cache-hit != 'true'
440+
with:
441+
path: |
442+
${{ env.APPDATA }}/local
443+
C:/cabal
444+
key: ${{ matrix.command }}-deps-ghc-${{ matrix.ghc_version }}-v${{ matrix.ghc_salt }}-${{ matrix.runner }}-${{ matrix.name }}
445+
446+
- name: Run packcheck (final build)
447+
# on windows-latest GitHub Actions defaults to PowerShell
448+
shell: bash
449+
run: |
450+
if test -n "$SUBDIR"
451+
then
452+
cd "$SUBDIR"
453+
fi
454+
# Commands like mount, sysctl for info require sbin
455+
PATH_VAR=/bin:/usr/bin:/sbin:/usr/sbin
456+
case "$(uname)" in
457+
Linux)
458+
# On Linux it defaults to /usr/local, during cache restore
459+
# tar is unable to change permissions and restore fails.
460+
export GHCUP_INSTALL_BASE_PREFIX=$HOME
461+
;;
462+
CYGWIN*|MINGW*|MSYS*)
463+
PATH_VAR="$PATH_VAR:/c/Program Files/7-Zip:/mingw64/bin"
464+
;;
465+
esac
466+
echo "$PACKCHECK $PACKCHECK_COMMAND PATH=\"$PATH_VAR\""
467+
bash -c "$PACKCHECK $PACKCHECK_COMMAND BUILD_POST_DEPS=y PATH=\"$PATH_VAR\""
356468
357469
- name: Check cache locations
358-
if: runner.os != 'Windows'
470+
shell: bash
359471
run: |
360-
# We want to see if it is a symlink; e.g. on github ~/.ghcup is a
361-
# pre-existing symlink to /usr/local.
362-
list="$HOME/.local/bin $HOME/.local/state/cabal $HOME/.ghcup $HOME/.stack"
472+
# We want to see if any cache paths are symlinks; e.g. on github
473+
# ~/.ghcup is a pre-existing symlink to /usr/local.
474+
if [ "$RUNNER_OS" == "Windows" ]; then
475+
# Convert Windows paths to Unix-style for Bash
476+
APPDATA_UNIX=$(cygpath "$APPDATA")
477+
list="$APPDATA_UNIX/local C:/ghcup C:/cabal"
478+
else
479+
list="$HOME/.local/bin $HOME/.local/state/cabal $HOME/.ghcup $HOME/.stack"
480+
fi
481+
363482
for dir in $list; do
364483
# macOS does not have --no-dereference option
365484
if [ -L "$dir" ]; then
366485
echo "$dir is a symlink -> $(readlink $dir)"
486+
elif [ -d "$dir" ]; then
487+
du -sh "$dir" 2>/dev/null || echo "$dir permission denied"
367488
else
368-
du -sh "$dir" 2>/dev/null || echo "$dir missing"
489+
echo "$dir missing or not a dir"
369490
fi
370491
done
371492
echo

0 commit comments

Comments
 (0)