From 3afebc0c8e80d1493e1605863176e9bfdf89784a Mon Sep 17 00:00:00 2001 From: "Laurent P. René de Cotret" Date: Tue, 30 Jun 2020 08:57:47 -0400 Subject: Continuous integration on Windows and Linux --- .github/workflows/main.yml | 53 ++++++++++++++++++++++++++++++++++++-------- hakyll.cabal | 2 +- lib/Hakyll/Core/Util/File.hs | 30 ++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9253d60..4e2b7c3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,20 +1,55 @@ +# This Github Actions workflow is modified from +# https://kodimensional.dev/github-actions name: 'CI' -on: ['push'] + +# Trigger the workflow on push or pull request, but only for the master branch +on: [push, pull_request] + jobs: build: + strategy: matrix: os: [ubuntu-latest, windows-latest] + + env: + ARGS: --no-terminal --fast name: ${{ matrix.os }} - runs-on: $${{ matrix.os }} + runs-on: ${{ matrix.os }} steps: - - uses: 'actions/checkout@v1' - - uses: 'mstksg/setup-stack@v1' - - uses: 'actions/cache@v1' + - uses: actions/checkout@v2 + if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master' + + # https://github.com/actions/setup-haskell + - uses: actions/setup-haskell@v1.1 + name: Setup Haskell Stack with: - path: '~/.stack' - key: "${{ runner.os }}-v3-stack-${{ hashFiles('stack.yaml.lock') }}" - restore-keys: '${{ runner.os }}-v3-stack' - - run: 'stack build --test' + stack-version: "latest" + enable-stack: true + stack-no-global: true + + # https://github.com/actions/cache + - uses: actions/cache@v2 + name: Cache ~/.stack + with: + path: ~/.stack + key: ${{ runner.os }}-${{ hashFiles('stack.yaml') }} + + # There are strange problems with CI on Windows, where builds with GHC 8.8.* + # always fail. Therefore, we distinguish between builds on Ubuntu and Windows + # and use an older compiler on Windows. + # See here for bug reports: + # https://gitlab.haskell.org/ghc/ghc/issues/17599 + # https://gitlab.haskell.org/ghc/ghc/issues/17926 + + - name: Test (Ubuntu) + run: | + stack test $ARGS --stack-yaml stack.yaml + if: ${{ runner.os == 'Linux' }} + + - name: Test (Windows) + run: | + stack test $ARGS --stack-yaml stack.yaml --compiler ghc-8.6.5 + if: ${{ runner.os == 'Windows' }} diff --git a/hakyll.cabal b/hakyll.cabal index 4be61bc..6607ebf 100644 --- a/hakyll.cabal +++ b/hakyll.cabal @@ -173,7 +173,7 @@ Library cryptonite >= 0.25 && < 0.27, data-default >= 0.4 && < 0.8, deepseq >= 1.3 && < 1.5, - directory >= 1.0 && < 1.4, + directory >= 1.2.7.0 && < 1.4, file-embed >= 0.0.10.1 && < 0.0.12, filepath >= 1.0 && < 1.5, lrucache >= 1.1.1 && < 1.3, diff --git a/lib/Hakyll/Core/Util/File.hs b/lib/Hakyll/Core/Util/File.hs index 9db6b11..02b8ece 100644 --- a/lib/Hakyll/Core/Util/File.hs +++ b/lib/Hakyll/Core/Util/File.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE CPP #-} -------------------------------------------------------------------------------- -- | A module containing various file utility functions module Hakyll.Core.Util.File @@ -8,10 +10,12 @@ module Hakyll.Core.Util.File -------------------------------------------------------------------------------- +import Control.Concurrent (threadDelay) +import Control.Exception (SomeException, catch) import Control.Monad (filterM, forM, when) import System.Directory (createDirectoryIfMissing, doesDirectoryExist, getDirectoryContents, - removeDirectoryRecursive) + removeDirectoryRecursive, removePathForcibly) import System.FilePath (takeDirectory, ()) @@ -51,6 +55,30 @@ getRecursiveContents ignore top = go "" -------------------------------------------------------------------------------- removeDirectory :: FilePath -> IO () +#ifndef mingw32_HOST_OS removeDirectory fp = do e <- doesDirectoryExist fp when e $ removeDirectoryRecursive fp +#else +-- Deleting files on Windows is unreliable. If a file/directory is open by a program (e.g. antivirus), +-- then removing related directories *quickly* may fail with strange messages. +-- See here for discussions: +-- https://github.com/haskell/directory/issues/96 +-- https://github.com/haskell/win32/pull/129 +-- +-- The hacky solution is to retry deleting directories a few times, +-- with a delay, on Windows only. +removeDirectory = retryWithDelay 10 . removePathForcibly +#endif + + +-------------------------------------------------------------------------------- +-- | Retry an operation at most /n/ times (/n/ must be positive). +-- If the operation fails the /n/th time it will throw that final exception. +-- A delay of 100ms is introduced between every retry. +retryWithDelay :: Int -> IO a -> IO a +retryWithDelay i x + | i <= 0 = error "Hakyll.Core.Util.File.retry: retry count must be 1 or more" + | i == 1 = x + | otherwise = catch x $ \(_::SomeException) -> threadDelay 100 >> retryWithDelay (i-1) x + -- cgit v1.2.3