-- | Take configuration, produce 'Travis'.
{-# LANGUAGE NamedFieldPuns    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
{-# OPTIONS_GHC -Wno-unused-matches #-}
module HaskellCI.Travis (
    makeTravis,
    travisHeader,
    ) where

import HaskellCI.Prelude

import qualified Data.Map.Strict                 as M
import qualified Data.Set                        as S
import qualified Distribution.Fields.Pretty      as C
import qualified Distribution.Package            as C
import qualified Distribution.Pretty             as C
import qualified Distribution.Types.VersionRange as C
import qualified Distribution.Version            as C

import Cabal.Project
import HaskellCI.Auxiliary
import HaskellCI.Compiler
import HaskellCI.Config
import HaskellCI.Config.ConstraintSet
import HaskellCI.Config.Doctest
import HaskellCI.Config.Folds
import HaskellCI.Config.HLint
import HaskellCI.Config.Installed
import HaskellCI.Config.Jobs
import HaskellCI.Config.PackageScope
import HaskellCI.Config.Validity
import HaskellCI.HeadHackage
import HaskellCI.Jobs
import HaskellCI.List
import HaskellCI.MonadErr
import HaskellCI.Package
import HaskellCI.Sh
import HaskellCI.ShVersionRange
import HaskellCI.Tools
import HaskellCI.Travis.Yaml
import HaskellCI.VersionInfo

-------------------------------------------------------------------------------
-- Travis header
-------------------------------------------------------------------------------

travisHeader :: Bool -> [String] -> [String]
travisHeader :: Bool -> [[Char]] -> [[Char]]
travisHeader Bool
insertVersion [[Char]]
argv =
    [ [Char]
"This Travis job script has been generated by a script via"
    , [Char]
""
    , [Char]
"  haskell-ci " forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
unwords [ [Char]
"'" forall a. [a] -> [a] -> [a]
++ [Char]
a forall a. [a] -> [a] -> [a]
++ [Char]
"'" | [Char]
a <- [[Char]]
argv ]
    , [Char]
""
    , [Char]
"To regenerate the script (for example after adjusting tested-with) run"
    , [Char]
""
    , [Char]
"  haskell-ci regenerate"
    , [Char]
""
    , [Char]
"For more information, see https://github.com/haskell-CI/haskell-ci"
    , [Char]
""
    ] forall a. [a] -> [a] -> [a]
++
    if Bool
insertVersion then
    [ [Char]
"version: " forall a. [a] -> [a] -> [a]
++ [Char]
haskellCIVerStr
    , [Char]
""
    ] else []

-------------------------------------------------------------------------------
-- Generate travis configuration
-------------------------------------------------------------------------------

{-
Travis CI–specific notes:

* We use -j2 for parallelism, as Travis' virtual environments use 2 cores, per
  https://docs.travis-ci.com/user/reference/overview/#virtualisation-environment-vs-operating-system.
-}

makeTravis
    :: [String]
    -> Config
    -> Project URI Void Package
    -> JobVersions
    -> Either HsCiError Travis -- TODO: writer
makeTravis :: [[Char]]
-> Config
-> Project URI Void Package
-> JobVersions
-> Either HsCiError Travis
makeTravis [[Char]]
argv config :: Config
config@Config {Bool
Natural
[Char]
[[Char]]
[PackageName]
[PrettyField ()]
[Installed]
[ConstraintSet]
Maybe [Char]
Maybe Version
Maybe Jobs
VersionRange
Version
Set [Char]
Set Fold
Map Version [Char]
Ubuntu
PackageScope
HLintConfig
DoctestConfig
DocspecConfig
CopyFields
Components
TestedWithJobs
cfgTimeoutMinutes :: Config -> Natural
cfgGitHubActionName :: Config -> Maybe [Char]
cfgRawTravis :: Config -> [Char]
cfgRawProject :: Config -> [PrettyField ()]
cfgConstraintSets :: Config -> [ConstraintSet]
cfgHLint :: Config -> HLintConfig
cfgDocspec :: Config -> DocspecConfig
cfgDoctest :: Config -> DoctestConfig
cfgErrorMissingMethods :: Config -> PackageScope
cfgInsertVersion :: Config -> Bool
cfgGitHubPatches :: Config -> [[Char]]
cfgTravisPatches :: Config -> [[Char]]
cfgApt :: Config -> Set [Char]
cfgGhcupVersion :: Config -> Version
cfgGhcupJobs :: Config -> VersionRange
cfgGhcupCabal :: Config -> Bool
cfgMacosJobs :: Config -> VersionRange
cfgLinuxJobs :: Config -> VersionRange
cfgLastInSeries :: Config -> Bool
cfgAllowFailures :: Config -> VersionRange
cfgEnv :: Config -> Map Version [Char]
cfgGoogleChrome :: Config -> Bool
cfgPostgres :: Config -> Bool
cfgGhcHead :: Config -> Bool
cfgFolds :: Config -> Set Fold
cfgProjectName :: Config -> Maybe [Char]
cfgEmailNotifications :: Config -> Bool
cfgIrcIfInOriginRepo :: Config -> Bool
cfgIrcPassword :: Config -> Maybe [Char]
cfgIrcNickname :: Config -> Maybe [Char]
cfgIrcChannels :: Config -> [[Char]]
cfgOnlyBranches :: Config -> [[Char]]
cfgCheck :: Config -> Bool
cfgTestOutputDirect :: Config -> Bool
cfgGhcjsTools :: Config -> [PackageName]
cfgGhcjsTests :: Config -> Bool
cfgHeadHackageOverride :: Config -> Bool
cfgHeadHackage :: Config -> VersionRange
cfgUnconstrainted :: Config -> VersionRange
cfgNoTestsNoBench :: Config -> VersionRange
cfgHaddockComponents :: Config -> Components
cfgHaddock :: Config -> VersionRange
cfgBenchmarks :: Config -> VersionRange
cfgRunTests :: Config -> VersionRange
cfgTests :: Config -> VersionRange
cfgInstalled :: Config -> [Installed]
cfgInstallDeps :: Config -> Bool
cfgCache :: Config -> Bool
cfgSubmodules :: Config -> Bool
cfgLocalGhcOptions :: Config -> [[Char]]
cfgCopyFields :: Config -> CopyFields
cfgEnabledJobs :: Config -> VersionRange
cfgTestedWith :: Config -> TestedWithJobs
cfgUbuntu :: Config -> Ubuntu
cfgJobs :: Config -> Maybe Jobs
cfgCabalInstallVersion :: Config -> Maybe Version
cfgTimeoutMinutes :: Natural
cfgGitHubActionName :: Maybe [Char]
cfgRawTravis :: [Char]
cfgRawProject :: [PrettyField ()]
cfgConstraintSets :: [ConstraintSet]
cfgHLint :: HLintConfig
cfgDocspec :: DocspecConfig
cfgDoctest :: DoctestConfig
cfgErrorMissingMethods :: PackageScope
cfgInsertVersion :: Bool
cfgGitHubPatches :: [[Char]]
cfgTravisPatches :: [[Char]]
cfgApt :: Set [Char]
cfgGhcupVersion :: Version
cfgGhcupJobs :: VersionRange
cfgGhcupCabal :: Bool
cfgMacosJobs :: VersionRange
cfgLinuxJobs :: VersionRange
cfgLastInSeries :: Bool
cfgAllowFailures :: VersionRange
cfgEnv :: Map Version [Char]
cfgGoogleChrome :: Bool
cfgPostgres :: Bool
cfgGhcHead :: Bool
cfgFolds :: Set Fold
cfgProjectName :: Maybe [Char]
cfgEmailNotifications :: Bool
cfgIrcIfInOriginRepo :: Bool
cfgIrcPassword :: Maybe [Char]
cfgIrcNickname :: Maybe [Char]
cfgIrcChannels :: [[Char]]
cfgOnlyBranches :: [[Char]]
cfgCheck :: Bool
cfgTestOutputDirect :: Bool
cfgGhcjsTools :: [PackageName]
cfgGhcjsTests :: Bool
cfgHeadHackageOverride :: Bool
cfgHeadHackage :: VersionRange
cfgUnconstrainted :: VersionRange
cfgNoTestsNoBench :: VersionRange
cfgHaddockComponents :: Components
cfgHaddock :: VersionRange
cfgBenchmarks :: VersionRange
cfgRunTests :: VersionRange
cfgTests :: VersionRange
cfgInstalled :: [Installed]
cfgInstallDeps :: Bool
cfgCache :: Bool
cfgSubmodules :: Bool
cfgLocalGhcOptions :: [[Char]]
cfgCopyFields :: CopyFields
cfgEnabledJobs :: VersionRange
cfgTestedWith :: TestedWithJobs
cfgUbuntu :: Ubuntu
cfgJobs :: Maybe Jobs
cfgCabalInstallVersion :: Maybe Version
..} Project URI Void Package
prj jobs :: JobVersions
jobs@JobVersions {Set CompilerVersion
macosVersions :: JobVersions -> Set CompilerVersion
linuxVersions :: JobVersions -> Set CompilerVersion
allVersions :: JobVersions -> Set CompilerVersion
macosVersions :: Set CompilerVersion
linuxVersions :: Set CompilerVersion
allVersions :: Set CompilerVersion
..} = do
    -- before caching: clear some redundant stuff
    [Sh]
beforeCache <- forall e (m :: * -> *).
(MonadErr e m, FromHsCiError e) =>
ShM () -> m [Sh]
runSh forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgCache forall a b. (a -> b) -> a -> b
$ do
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
comment [Char]
"remove files that are regenerated by 'cabal update'"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*" -- legacy
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv $CABALHOME/packages/hackage.haskell.org/*.json" -- TUF meta-data
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -rfv $CABALHOME/packages/head.hackage" -- if we cache, it will break builds.

    -- before install: we set up the environment, install GHC/cabal on OSX
    [Sh]
beforeInstall <- forall e (m :: * -> *).
(MonadErr e m, FromHsCiError e) =>
ShM () -> m [Sh]
runSh forall a b. (a -> b) -> a -> b
$ do
        -- Validity checks
        forall (m :: * -> *).
MonadErr HsCiError m =>
Config -> JobVersions -> m ()
checkConfigValidity Config
config JobVersions
jobs

        -- This have to be first
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
anyGHCJS forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines
            [ [Char]
"if echo $CC | grep -q ghcjs; then"
            , [Char]
"    GHCJS=true; GHCJSARITH=1;"
            , [Char]
"else"
            , [Char]
"    GHCJS=false; GHCJSARITH=0;"
            , [Char]
"fi"
            ]

        -- Adjust $HC
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"HC=$(echo \"/opt/$CC/bin/ghc\" | sed 's/-/\\//')"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"WITHCOMPILER=\"-w $HC\""
        CompilerRange -> [Char] -> ShM ()
shForJob CompilerRange
RangeGHCJS [Char]
"HC=${HC}js"
        CompilerRange -> [Char] -> ShM ()
shForJob CompilerRange
RangeGHCJS [Char]
"WITHCOMPILER=\"--ghcjs ${WITHCOMPILER}js\""

        -- Needed to work around haskell/cabal#6214
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"HADDOCK=$(echo \"/opt/$CC/bin/haddock\" | sed 's/-/\\//')"
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set CompilerVersion
macosVersions) forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char]
"if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then HADDOCK=$(echo $HADDOCK | sed \"s:^/opt:$HOME/.ghc-install:\"); fi"

        -- Hack: happy needs ghc. Let's install version matching GHCJS.
        -- At the moment, there is only GHCJS-8.4, so we install GHC-8.4.4
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
anyGHCJS forall a b. (a -> b) -> a -> b
$ do
            CompilerRange -> [Char] -> ShM ()
shForJob CompilerRange
RangeGHCJS forall a b. (a -> b) -> a -> b
$ [Char]
"PATH=\"/opt/ghc/8.4.4/bin:$PATH\""

        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"HCPKG=\"$HC-pkg\""
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"unset CC"
        -- cabal
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"CABAL=/opt/ghc/bin/cabal"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"CABALHOME=$HOME/.cabal"
        -- PATH
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"export PATH=\"$CABALHOME/bin:$PATH\""
        -- rootdir is useful for manual script additions
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"TOP=$(pwd)"
        -- macOS installing
        let haskellOnMacos :: [Char]
haskellOnMacos = [Char]
"https://haskell.futurice.com/haskell-on-macos.py"
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set CompilerVersion
macosVersions) forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char]
"if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then curl " forall a. [a] -> [a] -> [a]
++ [Char]
haskellOnMacos forall a. [a] -> [a] -> [a]
++ [Char]
" | python3 - --make-dirs --install-dir=$HOME/.ghc-install --cabal-alias=3.2.0.0 install cabal-install-3.2.0.0 ${TRAVIS_COMPILER}; fi"
            forall (m :: * -> *). MonadSh m => [Integer] -> [Char] -> m ()
sh' [Integer
2034,Integer
2039] [Char]
"if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then HC=$HOME/.ghc-install/ghc/bin/$TRAVIS_COMPILER; WITHCOMPILER=\"-w $HC\"; HCPKG=$HOME/.ghc-install/ghc/bin/${TRAVIS_COMPILER}/ghc/ghc-pkg; CABAL=$HOME/.ghc-install/ghc/bin/cabal; fi"
        -- HCNUMVER, numeric HC version, e.g. ghc 7.8.4 is 70804 and 7.10.3 is 71003
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"echo $HCNUMVER"
        -- verbose in .cabal/config is not respected
        -- https://github.com/haskell/cabal/issues/5956
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"CABAL=\"$CABAL -vnormal+nowrap\""

        -- SC2039: In POSIX sh, set option pipefail is undefined. Travis is bash, so it's fine :)
        forall (m :: * -> *). MonadSh m => [Integer] -> [Char] -> m ()
sh' [Integer
2039, Integer
3040] [Char]
"set -o pipefail"

        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"TEST=--enable-tests"
        CompilerRange -> [Char] -> ShM ()
shForJob (CompilerRange -> CompilerRange
invertCompilerRange forall a b. (a -> b) -> a -> b
$ VersionRange -> CompilerRange
Range VersionRange
cfgTests) [Char]
"TEST=--disable-tests"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"BENCH=--enable-benchmarks"
        CompilerRange -> [Char] -> ShM ()
shForJob (CompilerRange -> CompilerRange
invertCompilerRange forall a b. (a -> b) -> a -> b
$ VersionRange -> CompilerRange
Range VersionRange
cfgBenchmarks) [Char]
"BENCH=--disable-benchmarks"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"HEADHACKAGE=false"
        CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range VersionRange
cfgHeadHackage forall a. Lattice a => a -> a -> a
\/ Set CompilerVersion -> CompilerRange
RangePoints (forall a. a -> Set a
S.singleton CompilerVersion
GHCHead)) [Char]
"HEADHACKAGE=true"

        -- create ~/.cabal/config
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -f $CABALHOME/config"
        [Char] -> [[Char]] -> ShM ()
cat [Char]
"$CABALHOME/config"
            [ [Char]
"verbose: normal +nowrap +markoutput" -- https://github.com/haskell/cabal/issues/5956
            , [Char]
"remote-build-reporting: anonymous"
            , [Char]
"write-ghc-environment-files: never"
            , [Char]
"remote-repo-cache: $CABALHOME/packages"
            , [Char]
"logs-dir:          $CABALHOME/logs"
            , [Char]
"world-file:        $CABALHOME/world"
            , [Char]
"extra-prog-path:   $CABALHOME/bin"
            , [Char]
"symlink-bindir:    $CABALHOME/bin"
            , [Char]
"installdir:        $CABALHOME/bin"
            , [Char]
"build-summary:     $CABALHOME/logs/build.log"
            , [Char]
"store-dir:         $CABALHOME/store"
            , [Char]
"install-dirs user"
            , [Char]
"  prefix: $CABALHOME"
            , [Char]
"repository hackage.haskell.org"
            , [Char]
"  url: http://hackage.haskell.org/"
            ]

        -- Add head.hackage repository to ~/.cabal/config
        -- (locally you want to add it to cabal.project)
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall a. Set a -> Bool
S.null Set CompilerVersion
headGhcVers) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines forall a b. (a -> b) -> a -> b
$
            [ [Char]
"if $HEADHACKAGE; then"
            ] forall a. [a] -> [a] -> [a]
++
            [Char] -> [[Char]]
lines (Quotes -> [Char] -> [[Char]] -> [Char]
catCmd Quotes
Double [Char]
"$CABALHOME/config" forall a b. (a -> b) -> a -> b
$ Bool -> [[Char]]
headHackageRepoStanza Bool
cfgHeadHackageOverride) forall a. [a] -> [a] -> [a]
++
            [ [Char]
"fi"
            ]

    -- in install step we install tools and dependencies
    [Sh]
install <- forall e (m :: * -> *).
(MonadErr e m, FromHsCiError e) =>
ShM () -> m [Sh]
runSh forall a b. (a -> b) -> a -> b
$ do
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"${CABAL} --version"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"echo \"$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]\""
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
anyGHCJS forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"node --version"
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"echo $GHCJS"

        -- Cabal jobs
        forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (Maybe Jobs
cfgJobs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Jobs -> Maybe Int
cabalJobs) forall a b. (a -> b) -> a -> b
$ \Int
n ->
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char]
"echo 'jobs: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Int
n forall a. [a] -> [a] -> [a]
++ [Char]
"' >> $CABALHOME/config"

        -- GHC jobs + ghc-options
        forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (Maybe Jobs
cfgJobs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Jobs -> Maybe Int
ghcJobs) forall a b. (a -> b) -> a -> b
$ \Int
m -> do
            CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range forall a b. (a -> b) -> a -> b
$ Version -> VersionRange
C.orLaterVersion ([Int] -> Version
C.mkVersion [Int
7,Int
8])) forall a b. (a -> b) -> a -> b
$ [Char]
"GHCJOBS=-j" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Int
m
        [Char] -> [[Char]] -> ShM ()
cat [Char]
"$CABALHOME/config"
            [ [Char]
"program-default-options"
            , [Char]
"  ghc-options: $GHCJOBS +RTS -M6G -RTS"
            ]

        -- output config for debugging purposes
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"cat $CABALHOME/config"

        -- remove project own cabal.project files
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -fv cabal.project cabal.project.local cabal.project.freeze"

        -- Update hackage index.
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"travis_retry ${CABAL} v2-update -v"

        -- Install doctest
        let doctestVersionConstraint :: [Char]
doctestVersionConstraint
                | VersionRange -> Bool
C.isAnyVersion (DoctestConfig -> VersionRange
cfgDoctestVersion DoctestConfig
cfgDoctest) = [Char]
""
                | Bool
otherwise = [Char]
" --constraint='doctest " forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow (DoctestConfig -> VersionRange
cfgDoctestVersion DoctestConfig
cfgDoctest) forall a. [a] -> [a] -> [a]
++ [Char]
"'"
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
doctestEnabled forall a b. (a -> b) -> a -> b
$
            CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range (DoctestConfig -> VersionRange
cfgDoctestEnabled DoctestConfig
cfgDoctest) forall a. Lattice a => a -> a -> a
/\ CompilerRange
doctestJobVersionRange) forall a b. (a -> b) -> a -> b
$
                [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-install $WITHCOMPILER --ignore-project -j2 doctest" forall a. [a] -> [a] -> [a]
++ [Char]
doctestVersionConstraint

        -- Install hlint
        let hlintVersionConstraint :: [Char]
hlintVersionConstraint
                | VersionRange -> Bool
C.isAnyVersion (HLintConfig -> VersionRange
cfgHLintVersion HLintConfig
cfgHLint) = [Char]
""
                | Bool
otherwise = [Char]
" --constraint='hlint " forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow (HLintConfig -> VersionRange
cfgHLintVersion HLintConfig
cfgHLint) forall a. [a] -> [a] -> [a]
++ [Char]
"'"
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (HLintConfig -> Bool
cfgHLintEnabled HLintConfig
cfgHLint) forall a b. (a -> b) -> a -> b
$ do
            let forHLint :: [Char] -> ShM ()
forHLint = CompilerRange -> [Char] -> ShM ()
shForJob (Set CompilerVersion -> VersionRange -> HLintJob -> CompilerRange
hlintJobVersionRange Set CompilerVersion
allVersions  VersionRange
cfgHeadHackage (HLintConfig -> HLintJob
cfgHLintJob HLintConfig
cfgHLint))
            if HLintConfig -> Bool
cfgHLintDownload HLintConfig
cfgHLint
            then do
                -- install --dry-run and use perl regex magic to find a hlint version
                -- -v is important
                [Char] -> ShM ()
forHLint forall a b. (a -> b) -> a -> b
$ [Char]
"HLINTVER=$(cd /tmp && (${CABAL} v2-install -v $WITHCOMPILER --dry-run hlint " forall a. [a] -> [a] -> [a]
++ [Char]
hlintVersionConstraint forall a. [a] -> [a] -> [a]
++ [Char]
" |  perl -ne 'if (/\\bhlint-(\\d+(\\.\\d+)*)\\b/) { print \"$1\"; last; }')); echo \"HLint version $HLINTVER\""
                [Char] -> ShM ()
forHLint forall a b. (a -> b) -> a -> b
$ [Char]
"if [ ! -e $HOME/.hlint/hlint-$HLINTVER/hlint ]; then " forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
unwords
                    [ [Char]
"echo \"Downloading HLint version $HLINTVER\";"
                    , [Char]
"mkdir -p $HOME/.hlint;"
                    , [Char]
"curl --write-out 'Status Code: %{http_code} Redirects: %{num_redirects} Total time: %{time_total} Total Dsize: %{size_download}\\n' --silent --location --output $HOME/.hlint/hlint-$HLINTVER.tar.gz \"https://github.com/ndmitchell/hlint/releases/download/v$HLINTVER/hlint-$HLINTVER-x86_64-linux.tar.gz\";"
                    , [Char]
"tar -xzv -f $HOME/.hlint/hlint-$HLINTVER.tar.gz -C $HOME/.hlint;"
                    , [Char]
"fi"
                    ]
                [Char] -> ShM ()
forHLint [Char]
"mkdir -p $CABALHOME/bin && ln -sf \"$HOME/.hlint/hlint-$HLINTVER/hlint\" $CABALHOME/bin/hlint"
                [Char] -> ShM ()
forHLint [Char]
"hlint --version"

            else [Char] -> ShM ()
forHLint forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-install $WITHCOMPILER --ignore-project -j2 hlint" forall a. [a] -> [a] -> [a]
++ [Char]
hlintVersionConstraint

        -- Install cabal-plan (for ghcjs tests)
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
anyGHCJS Bool -> Bool -> Bool
&& Bool
cfgGhcjsTests) forall a b. (a -> b) -> a -> b
$ do
            CompilerRange -> [Char] -> ShM ()
shForJob CompilerRange
RangeGHCJS forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal [Char]
"v2-install -w ghc-8.4.4 --ignore-project -j2 cabal-plan --constraint='cabal-plan ^>=0.6.0.0' --constraint='cabal-plan +exe'"

        -- Install happy
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
anyGHCJS forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [PackageName]
cfgGhcjsTools forall a b. (a -> b) -> a -> b
$ \PackageName
t ->
            CompilerRange -> [Char] -> ShM ()
shForJob CompilerRange
RangeGHCJS forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-install -w ghc-8.4.4 --ignore-project -j2" forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow PackageName
t

        -- create cabal.project file
        Bool -> ShM ()
generateCabalProject Bool
False

        -- autoreconf
        forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Package]
pkgs forall a b. (a -> b) -> a -> b
$ \Pkg{[Char]
pkgDir :: Package -> [Char]
pkgDir :: [Char]
pkgDir} ->
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char]
"if [ -f \"" forall a. [a] -> [a] -> [a]
++ [Char]
pkgDir forall a. [a] -> [a] -> [a]
++ [Char]
"/configure.ac\" ]; then (cd \"" forall a. [a] -> [a] -> [a]
++ [Char]
pkgDir forall a. [a] -> [a] -> [a]
++ [Char]
"\" && autoreconf -i); fi"

        -- dump install plan
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal [Char]
"v2-freeze $WITHCOMPILER ${TEST} ${BENCH}"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm  cabal.project.freeze"

        -- Install dependencies
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgInstallDeps forall a b. (a -> b) -> a -> b
$ do
            -- install dependencies
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabalTW [Char]
"v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all"

            -- install dependencies for no-test-no-bench
            CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range VersionRange
cfgNoTestsNoBench) forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabalTW [Char]
"v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all"

    -- Here starts the actual work to be performed for the package under test;
    -- any command which exits with a non-zero exit code causes the build to fail.
    [Sh]
script <- forall e (m :: * -> *).
(MonadErr e m, FromHsCiError e) =>
ShM () -> m [Sh]
runSh forall a b. (a -> b) -> a -> b
$ do
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)"

        -- sdist
        Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldSDist [Char]
"Packaging..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal [Char]
"v2-sdist all"

        -- unpack
        Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldUnpack [Char]
"Unpacking..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/"
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"cd ${DISTDIR} || false" -- fail explicitly, makes SC happier
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \\;"
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm       '{}' \\;"

            forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Package]
pkgs forall a b. (a -> b) -> a -> b
$ \Pkg{[Char]
pkgName :: Package -> [Char]
pkgName :: [Char]
pkgName} -> do
                forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
pkgNameDirVariable' [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
"=\"$(find . -maxdepth 1 -type d -regex '.*/" forall a. [a] -> [a] -> [a]
++ [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
"-[0-9.]*')\""

            Bool -> ShM ()
generateCabalProject Bool
True

            forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
anyGHCJS Bool -> Bool -> Bool
&& Bool
cfgGhcjsTests) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines forall a b. (a -> b) -> a -> b
$
                [ [Char]
"pkgdir() {"
                , [Char]
"  case $1 in"
                ] forall a. [a] -> [a] -> [a]
++
                [ [Char]
"    " forall a. [a] -> [a] -> [a]
++ [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
") echo " forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
pkgNameDirVariable [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
" ;;"
                | Pkg{[Char]
pkgName :: [Char]
pkgName :: Package -> [Char]
pkgName} <- [Package]
pkgs
                ] forall a. [a] -> [a] -> [a]
++
                [ [Char]
"  esac"
                , [Char]
"}"
                ]

        -- build no-tests no-benchmarks
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (VersionRange -> VersionRange -> Bool
equivVersionRanges VersionRange
C.noVersion VersionRange
cfgNoTestsNoBench) forall a b. (a -> b) -> a -> b
$ Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldBuild [Char]
"Building..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
comment [Char]
"this builds all libraries and executables (without tests/benchmarks)"
            CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range VersionRange
cfgNoTestsNoBench) forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal [Char]
"v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all"

        -- build everything
        Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldBuildEverything [Char]
"Building with tests and benchmarks..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
comment [Char]
"build & run tests, build benchmarks"
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal [Char]
"v2-build $WITHCOMPILER ${TEST} ${BENCH} all --write-ghc-environment-files=always"

        -- cabal v2-test fails if there are no test-suites.
        Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldTest [Char]
"Testing..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            CompilerRange -> [Char] -> ShM ()
shForJob (CompilerRange
RangeGHC forall a. Lattice a => a -> a -> a
/\ VersionRange -> CompilerRange
Range (VersionRange
cfgTests forall a. Lattice a => a -> a -> a
/\ VersionRange
cfgRunTests) forall a. Lattice a => a -> a -> a
/\ CompilerRange
hasTests) forall a b. (a -> b) -> a -> b
$
                [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-test $WITHCOMPILER ${TEST} ${BENCH} all" forall a. [a] -> [a] -> [a]
++ [Char]
testShowDetails

            forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgGhcjsTests forall a b. (a -> b) -> a -> b
$ CompilerRange -> [Char] -> ShM ()
shForJob (CompilerRange
RangeGHCJS forall a. Lattice a => a -> a -> a
/\ CompilerRange
hasTests) forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unwords
                [ [Char]
"cabal-plan list-bins '*:test:*' | while read -r line; do"
                , [Char]
"testpkg=$(echo \"$line\" | perl -pe 's/:.*//');"
                , [Char]
"testexe=$(echo \"$line\" | awk '{ print $2 }');"
                , [Char]
"echo \"testing $textexe in package $textpkg\";"
                , [Char]
"(cd \"$(pkgdir $testpkg)\" && nodejs \"$testexe\".jsexe/all.js);"
                , [Char]
"done"
                ]

        -- doctest
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
doctestEnabled forall a b. (a -> b) -> a -> b
$ Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldDoctest [Char]
"Doctest..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            let doctestOptions :: [Char]
doctestOptions = [[Char]] -> [Char]
unwords forall a b. (a -> b) -> a -> b
$ DoctestConfig -> [[Char]]
cfgDoctestOptions DoctestConfig
cfgDoctest
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char]
"$CABAL v2-build $WITHCOMPILER ${TEST} ${BENCH} all --dry-run"
            forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ DoctestConfig -> [PackageName]
cfgDoctestFilterEnvPkgs DoctestConfig
cfgDoctest) forall a b. (a -> b) -> a -> b
$ do
                -- cabal-install mangles unit ids on the OSX,
                -- removing the vowels to make filepaths shorter
                let manglePkgNames :: String -> [String]
                    manglePkgNames :: [Char] -> [[Char]]
manglePkgNames [Char]
n
                        | forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set CompilerVersion
macosVersions = [[Char]
n]
                        | Bool
otherwise          = [[Char]
n, forall a. (a -> Bool) -> [a] -> [a]
filter Char -> Bool
notVowel [Char]
n]
                      where
                        notVowel :: Char -> Bool
notVowel Char
c = forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Char
c ([Char]
"aeiou" :: String)
                let filterPkgs :: [Char]
filterPkgs = forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"|" forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Char] -> [[Char]]
manglePkgNames forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageName -> [Char]
C.unPackageName) forall a b. (a -> b) -> a -> b
$ DoctestConfig -> [PackageName]
cfgDoctestFilterEnvPkgs DoctestConfig
cfgDoctest
                forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [Char]
"perl -i -e 'while (<ARGV>) { print unless /package-id\\s+(" forall a. [a] -> [a] -> [a]
++ [Char]
filterPkgs forall a. [a] -> [a] -> [a]
++ [Char]
")-\\d+(\\.\\d+)*/; }' .ghc.environment.*"
            forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Package]
pkgs forall a b. (a -> b) -> a -> b
$ \Pkg{[Char]
pkgName :: [Char]
pkgName :: Package -> [Char]
pkgName,GenericPackageDescription
pkgGpd :: Package -> GenericPackageDescription
pkgGpd :: GenericPackageDescription
pkgGpd,Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs} ->
                forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([Char] -> PackageName
C.mkPackageName [Char]
pkgName forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` DoctestConfig -> [PackageName]
cfgDoctestFilterSrcPkgs DoctestConfig
cfgDoctest) forall a b. (a -> b) -> a -> b
$ do
                    forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (GenericPackageDescription -> [[[Char]]]
doctestArgs GenericPackageDescription
pkgGpd) forall a b. (a -> b) -> a -> b
$ \[[Char]]
args -> do
                        let args' :: [Char]
args' = [[Char]] -> [Char]
unwords [[Char]]
args
                        let vr :: CompilerRange
vr = VersionRange -> CompilerRange
Range (DoctestConfig -> VersionRange
cfgDoctestEnabled DoctestConfig
cfgDoctest)
                              forall a. Lattice a => a -> a -> a
/\ CompilerRange
doctestJobVersionRange
                              forall a. Lattice a => a -> a -> a
/\ Set CompilerVersion -> CompilerRange
RangePoints Set CompilerVersion
pkgJobs
                        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Char]]
args) forall a b. (a -> b) -> a -> b
$ CompilerRange -> [Char] -> ShM ()
shForJob  CompilerRange
vr forall a b. (a -> b) -> a -> b
$
                            [Char]
"(cd " forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
pkgNameDirVariable [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
" && doctest " forall a. [a] -> [a] -> [a]
++ [Char]
doctestOptions forall a. [a] -> [a] -> [a]
++ [Char]
" " forall a. [a] -> [a] -> [a]
++ [Char]
args' forall a. [a] -> [a] -> [a]
++ [Char]
")"

        -- hlint
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (HLintConfig -> Bool
cfgHLintEnabled HLintConfig
cfgHLint) forall a b. (a -> b) -> a -> b
$ Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldHLint [Char]
"HLint.." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            let [Char]
"" <+> :: [Char] -> [Char] -> [Char]
<+> [Char]
ys = [Char]
ys
                [Char]
xs <+> [Char]
"" = [Char]
xs
                [Char]
xs <+> [Char]
ys = [Char]
xs forall a. [a] -> [a] -> [a]
++ [Char]
" " forall a. [a] -> [a] -> [a]
++ [Char]
ys

                prependSpace :: [Char] -> [Char]
prependSpace [Char]
"" = [Char]
""
                prependSpace [Char]
xs = [Char]
" " forall a. [a] -> [a] -> [a]
++ [Char]
xs

            let hlintOptions :: [Char]
hlintOptions = [Char] -> [Char]
prependSpace forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Char]
"" ([Char]
"-h ${TOP}/" forall a. [a] -> [a] -> [a]
++) (HLintConfig -> Maybe [Char]
cfgHLintYaml HLintConfig
cfgHLint) [Char] -> [Char] -> [Char]
<+> [[Char]] -> [Char]
unwords (HLintConfig -> [[Char]]
cfgHLintOptions HLintConfig
cfgHLint)

            forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Package]
pkgs forall a b. (a -> b) -> a -> b
$ \Pkg{[Char]
pkgName :: [Char]
pkgName :: Package -> [Char]
pkgName,GenericPackageDescription
pkgGpd :: GenericPackageDescription
pkgGpd :: Package -> GenericPackageDescription
pkgGpd,Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs} -> do
                forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (GenericPackageDescription -> [[[Char]]]
hlintArgs GenericPackageDescription
pkgGpd) forall a b. (a -> b) -> a -> b
$ \[[Char]]
args -> do
                    let args' :: [Char]
args' = [[Char]] -> [Char]
unwords [[Char]]
args
                    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Char]]
args) forall a b. (a -> b) -> a -> b
$
                        CompilerRange -> [Char] -> ShM ()
shForJob (Set CompilerVersion -> VersionRange -> HLintJob -> CompilerRange
hlintJobVersionRange Set CompilerVersion
allVersions VersionRange
cfgHeadHackage (HLintConfig -> HLintJob
cfgHLintJob HLintConfig
cfgHLint) forall a. Lattice a => a -> a -> a
/\ Set CompilerVersion -> CompilerRange
RangePoints Set CompilerVersion
pkgJobs) forall a b. (a -> b) -> a -> b
$
                        [Char]
"(cd " forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
pkgNameDirVariable [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
" && hlint" forall a. [a] -> [a] -> [a]
++ [Char]
hlintOptions forall a. [a] -> [a] -> [a]
++ [Char]
" " forall a. [a] -> [a] -> [a]
++ [Char]
args' forall a. [a] -> [a] -> [a]
++ [Char]
")"

        -- cabal check
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgCheck forall a b. (a -> b) -> a -> b
$ Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldCheck [Char]
"cabal check..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
            forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Package]
pkgs forall a b. (a -> b) -> a -> b
$ \Pkg{[Char]
pkgName :: [Char]
pkgName :: Package -> [Char]
pkgName,Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs} -> CompilerRange -> [Char] -> ShM ()
shForJob (Set CompilerVersion -> CompilerRange
RangePoints Set CompilerVersion
pkgJobs) forall a b. (a -> b) -> a -> b
$
                [Char]
"(cd " forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
pkgNameDirVariable [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
" && ${CABAL} -vnormal check)"

        -- haddock
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (VersionRange -> VersionRange -> Bool
equivVersionRanges VersionRange
C.noVersion VersionRange
cfgHaddock) forall a b. (a -> b) -> a -> b
$
            Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldHaddock [Char]
"haddock..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$
                CompilerRange -> [Char] -> ShM ()
shForJob (CompilerRange
RangeGHC forall a. Lattice a => a -> a -> a
/\ VersionRange -> CompilerRange
Range VersionRange
cfgHaddock) forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-haddock --haddock-all $WITHCOMPILER " forall a. [a] -> [a] -> [a]
++ [Char]
withHaddock forall a. [a] -> [a] -> [a]
++ [Char]
" ${TEST} ${BENCH} all"

        -- unconstained build
        -- Have to build last, as we remove cabal.project.local
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (VersionRange -> VersionRange -> Bool
equivVersionRanges VersionRange
C.noVersion VersionRange
cfgUnconstrainted) forall a b. (a -> b) -> a -> b
$
            Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
FoldBuildInstalled [Char]
"Building without installed constraints for packages in global-db..." Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
                CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range VersionRange
cfgUnconstrainted) [Char]
"rm -f cabal.project.local"
                CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range VersionRange
cfgUnconstrainted) forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal [Char]
"v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all"

        -- and now, as we don't have cabal.project.local;
        -- we can test with other constraint sets
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ConstraintSet]
cfgConstraintSets) forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
comment [Char]
"Constraint sets"
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -f cabal.project.local"

            forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [ConstraintSet]
cfgConstraintSets forall a b. (a -> b) -> a -> b
$ \ConstraintSet
cs -> do
                let name :: [Char]
name            = ConstraintSet -> [Char]
csName ConstraintSet
cs
                let shForCs :: [Char] -> ShM ()
shForCs         = CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range (ConstraintSet -> VersionRange
csGhcVersions ConstraintSet
cs))
                let shForCs' :: CompilerRange -> [Char] -> ShM ()
shForCs' CompilerRange
r      = CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range (ConstraintSet -> VersionRange
csGhcVersions ConstraintSet
cs) forall a. Lattice a => a -> a -> a
/\ CompilerRange
r)
                let testFlag :: [Char]
testFlag        = if ConstraintSet -> Bool
csTests ConstraintSet
cs then [Char]
"--enable-tests" else [Char]
"--disable-tests"
                let benchFlag :: [Char]
benchFlag       = if ConstraintSet -> Bool
csBenchmarks ConstraintSet
cs then [Char]
"--enable-benchmarks" else [Char]
"--disable-benchmarks"
                let constraintFlags :: [[Char]]
constraintFlags = forall a b. (a -> b) -> [a] -> [b]
map (\[Char]
x ->  [Char]
"--constraint='" forall a. [a] -> [a] -> [a]
++ [Char]
x forall a. [a] -> [a] -> [a]
++ [Char]
"'") (ConstraintSet -> [[Char]]
csConstraints ConstraintSet
cs)
                let allFlags :: [Char]
allFlags        = [[Char]] -> [Char]
unwords ([Char]
testFlag forall a. a -> [a] -> [a]
: [Char]
benchFlag forall a. a -> [a] -> [a]
: [[Char]]
constraintFlags)

                Fold -> [Char] -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh' Fold
FoldConstraintSets [Char]
name ([Char]
"Constraint set " forall a. [a] -> [a] -> [a]
++ [Char]
name) Set Fold
cfgFolds forall a b. (a -> b) -> a -> b
$ do
                    [Char] -> ShM ()
shForCs forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-build $WITHCOMPILER " forall a. [a] -> [a] -> [a]
++ [Char]
allFlags forall a. [a] -> [a] -> [a]
++ [Char]
" --dependencies-only -j2 all"
                    [Char] -> ShM ()
shForCs forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-build $WITHCOMPILER " forall a. [a] -> [a] -> [a]
++ [Char]
allFlags forall a. [a] -> [a] -> [a]
++ [Char]
" all"
                    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ConstraintSet -> Bool
csRunTests ConstraintSet
cs) forall a b. (a -> b) -> a -> b
$
                        CompilerRange -> [Char] -> ShM ()
shForCs' CompilerRange
hasTests forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-test $WITHCOMPILER " forall a. [a] -> [a] -> [a]
++ [Char]
allFlags forall a. [a] -> [a] -> [a]
++ [Char]
" all --test-show-details=direct"
                    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ConstraintSet -> Bool
csHaddock ConstraintSet
cs) forall a b. (a -> b) -> a -> b
$
                        [Char] -> ShM ()
shForCs forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
cabal forall a b. (a -> b) -> a -> b
$ [Char]
"v2-haddock --haddock-all $WITHCOMPILER " forall a. [a] -> [a] -> [a]
++ [Char]
withHaddock forall a. [a] -> [a] -> [a]
++ [Char]
" " forall a. [a] -> [a] -> [a]
++ [Char]
allFlags forall a. [a] -> [a] -> [a]
++ [Char]
" all"

        -- At the end, we allow some raw travis scripts
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
cfgRawTravis) forall a b. (a -> b) -> a -> b
$ do
            forall (m :: * -> *). MonadSh m => [Char] -> m ()
comment [Char]
"Raw travis commands"
            forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh
                [ [Char]
l
                | [Char]
l <- [Char] -> [[Char]]
lines [Char]
cfgRawTravis
                , Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
l)
                ]

    -- assemble travis configuration
    forall (m :: * -> *) a. Monad m => a -> m a
return Travis
        { travisLanguage :: [Char]
travisLanguage      = [Char]
"c"
        , travisUbuntu :: Ubuntu
travisUbuntu        = Ubuntu
cfgUbuntu
        , travisGit :: TravisGit
travisGit           = TravisGit
            { tgSubmodules :: Bool
tgSubmodules = Bool
cfgSubmodules
            }
        , travisCache :: TravisCache
travisCache         = TravisCache
            { tcDirectories :: [[Char]]
tcDirectories = forall x. ListBuilder x () -> [x]
buildList forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgCache forall a b. (a -> b) -> a -> b
$ do
                forall x. x -> ListBuilder x ()
item [Char]
"$HOME/.cabal/packages"
                forall x. x -> ListBuilder x ()
item [Char]
"$HOME/.cabal/store"
                forall x. x -> ListBuilder x ()
item [Char]
"$HOME/.hlint"
                -- on OSX ghc is installed in $HOME so we can cache it
                -- independently of linux
                forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
cfgCache Bool -> Bool -> Bool
&& Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set CompilerVersion
macosVersions)) forall a b. (a -> b) -> a -> b
$ do
                    forall x. x -> ListBuilder x ()
item [Char]
"$HOME/.ghc-install"
            }
        , travisBranches :: TravisBranches
travisBranches      = TravisBranches
            { tbOnly :: [[Char]]
tbOnly = [[Char]]
cfgOnlyBranches
            }
        , travisNotifications :: TravisNotifications
travisNotifications = TravisNotifications
            { tnIRC :: Maybe TravisIRC
tnIRC = forall {a}. Bool -> a -> Maybe a
justIf (Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Char]]
cfgIrcChannels) forall a b. (a -> b) -> a -> b
$ TravisIRC
                { tiChannels :: [[Char]]
tiChannels = [[Char]]
cfgIrcChannels
                , tiSkipJoin :: Bool
tiSkipJoin = Bool
True
                , tiTemplate :: [[Char]]
tiTemplate =
                    [ [Char]
"\x0313" forall a. [a] -> [a] -> [a]
++ [Char]
projectName forall a. [a] -> [a] -> [a]
++ [Char]
"\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
                    ]
                , tiNick :: Maybe [Char]
tiNick     = Maybe [Char]
cfgIrcNickname
                , tiPassword :: Maybe [Char]
tiPassword = Maybe [Char]
cfgIrcPassword
                }
            , tnEmail :: Bool
tnEmail = Bool
cfgEmailNotifications
            }
        , travisServices :: [[Char]]
travisServices      = forall x. ListBuilder x () -> [x]
buildList forall a b. (a -> b) -> a -> b
$ do
            forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgPostgres forall a b. (a -> b) -> a -> b
$ forall x. x -> ListBuilder x ()
item [Char]
"postgresql"
        , travisAddons :: TravisAddons
travisAddons        = TravisAddons
            { taApt :: TravisApt
taApt          = [[Char]] -> [TravisAptSource] -> TravisApt
TravisApt [] []
            , taPostgres :: Maybe [Char]
taPostgres     = if Bool
cfgPostgres then forall a. a -> Maybe a
Just [Char]
"10" else forall a. Maybe a
Nothing
            , taGoogleChrome :: Bool
taGoogleChrome = Bool
cfgGoogleChrome
            }
        , travisMatrix :: TravisMatrix
travisMatrix        = TravisMatrix
            { tmInclude :: [TravisJob]
tmInclude = forall x. ListBuilder x () -> [x]
buildList forall a b. (a -> b) -> a -> b
$ do
                let tellJob :: Bool -> CompilerVersion -> ListBuilder TravisJob ()
                    tellJob :: Bool -> CompilerVersion -> ListBuilder TravisJob ()
tellJob Bool
osx CompilerVersion
gv = do
                        let cvs :: [Char]
cvs = Maybe Version -> [Char]
dispCabalVersion forall a b. (a -> b) -> a -> b
$ Maybe Version -> CompilerVersion -> Maybe Version
correspondingCabalVersion Maybe Version
cfgCabalInstallVersion CompilerVersion
gv
                        let gvs :: [Char]
gvs = CompilerVersion -> [Char]
dispGhcVersion CompilerVersion
gv

                        -- https://docs.travis-ci.com/user/installing-dependencies/#adding-apt-sources
                        let hvrppa :: TravisAptSource
                            hvrppa :: TravisAptSource
hvrppa = [Char] -> Maybe [Char] -> TravisAptSource
TravisAptSourceLine ([Char]
"deb http://ppa.launchpad.net/hvr/ghc/ubuntu " forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow Ubuntu
cfgUbuntu forall a. [a] -> [a] -> [a]
++ [Char]
" main") (forall a. a -> Maybe a
Just [Char]
"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286")

                        let ghcjsAptSources :: [TravisAptSource]
                            ghcjsAptSources :: [TravisAptSource]
ghcjsAptSources | Bool -> Bool
not (CompilerVersion -> Bool
isGHCJS CompilerVersion
gv) = []
                                            | Bool
otherwise =
                                [ [Char] -> Maybe [Char] -> TravisAptSource
TravisAptSourceLine ([Char]
"deb http://ppa.launchpad.net/hvr/ghcjs/ubuntu " forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow Ubuntu
cfgUbuntu forall a. [a] -> [a] -> [a]
++ [Char]
" main") forall a. Maybe a
Nothing
                                , [Char] -> Maybe [Char] -> TravisAptSource
TravisAptSourceLine ([Char]
"deb https://deb.nodesource.com/node_10.x " forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow Ubuntu
cfgUbuntu forall a. [a] -> [a] -> [a]
++ [Char]
" main") (forall a. a -> Maybe a
Just [Char]
"https://deb.nodesource.com/gpgkey/nodesource.gpg.key")
                                ]

                        let ghcjsPackages :: [String]
                            ghcjsPackages :: [[Char]]
ghcjsPackages = case CompilerVersion -> Maybe Version
maybeGHCJS CompilerVersion
gv of
                                Just Version
v -> [ [Char]
"ghc-" forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
C.prettyShow Version
v', [Char]
"nodejs" ] where
                                    -- TODO: partial maximum
                                    v' :: Version
v' = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
filter (Version -> VersionRange -> Bool
`C.withinRange` Version -> VersionRange
C.withinVersion Version
v) forall a b. (a -> b) -> a -> b
$ [Version]
knownGhcVersions
                                Maybe Version
Nothing -> []

                        forall x. x -> ListBuilder x ()
item TravisJob
                            { tjCompiler :: [Char]
tjCompiler = [Char]
gvs
                            , tjOS :: [Char]
tjOS       = if Bool
osx then [Char]
"osx" else [Char]
"linux"
                            , tjEnv :: Maybe [Char]
tjEnv      = case CompilerVersion
gv of
                                GHC Version
v -> forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Version
v Map Version [Char]
cfgEnv
                                CompilerVersion
_     -> forall a. Maybe a
Nothing
                            , tjAddons :: TravisAddons
tjAddons   = TravisAddons
                                { taApt :: TravisApt
taApt = TravisApt
                                    { taPackages :: [[Char]]
taPackages = [Char]
gvs forall a. a -> [a] -> [a]
: ([Char]
"cabal-install-" forall a. [a] -> [a] -> [a]
++ [Char]
cvs) forall a. a -> [a] -> [a]
: [[Char]]
ghcjsPackages forall a. [a] -> [a] -> [a]
++ forall a. Set a -> [a]
S.toList Set [Char]
cfgApt
                                    , taSources :: [TravisAptSource]
taSources  = TravisAptSource
hvrppa forall a. a -> [a] -> [a]
: [TravisAptSource]
ghcjsAptSources
                                    }

                                , taPostgres :: Maybe [Char]
taPostgres     = forall a. Maybe a
Nothing
                                , taGoogleChrome :: Bool
taGoogleChrome = Bool
False
                                }
                            }

                forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
S.toList Set CompilerVersion
linuxVersions) forall a b. (a -> b) -> a -> b
$ Bool -> CompilerVersion -> ListBuilder TravisJob ()
tellJob Bool
False
                forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
S.toList Set CompilerVersion
macosVersions) forall a b. (a -> b) -> a -> b
$ Bool -> CompilerVersion -> ListBuilder TravisJob ()
tellJob Bool
True

            , tmAllowFailures :: [TravisAllowFailure]
tmAllowFailures =
                [ [Char] -> TravisAllowFailure
TravisAllowFailure forall a b. (a -> b) -> a -> b
$ CompilerVersion -> [Char]
dispGhcVersion CompilerVersion
compiler
                | CompilerVersion
compiler <- forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Set CompilerVersion
allVersions
                , VersionRange -> CompilerVersion -> Bool
previewGHC VersionRange
cfgHeadHackage CompilerVersion
compiler Bool -> Bool -> Bool
|| forall a. a -> (Version -> a) -> CompilerVersion -> a
maybeGHC Bool
False (Version -> VersionRange -> Bool
`C.withinRange` VersionRange
cfgAllowFailures) CompilerVersion
compiler
                ]
            }
        , travisBeforeCache :: [Sh]
travisBeforeCache   = [Sh]
beforeCache
        , travisBeforeInstall :: [Sh]
travisBeforeInstall = [Sh]
beforeInstall
        , travisInstall :: [Sh]
travisInstall       = [Sh]
install
        , travisScript :: [Sh]
travisScript        = [Sh]
script
        }
  where
    Auxiliary {Bool
[Char]
[URI]
[Package]
CompilerRange
[Char] -> [PrettyField ()]
haddockFlags :: Auxiliary -> [Char]
runHaddock :: Auxiliary -> Bool
anyJobUsesHeadHackage :: Auxiliary -> Bool
testShowDetails :: Auxiliary -> [Char]
extraCabalProjectFields :: Auxiliary -> [Char] -> [PrettyField ()]
hasLibrary :: Auxiliary -> Bool
hasTests :: Auxiliary -> CompilerRange
docspecEnabled :: Auxiliary -> Bool
doctestEnabled :: Auxiliary -> Bool
projectName :: Auxiliary -> [Char]
uris :: Auxiliary -> [URI]
pkgs :: Auxiliary -> [Package]
haddockFlags :: [Char]
runHaddock :: Bool
anyJobUsesHeadHackage :: Bool
extraCabalProjectFields :: [Char] -> [PrettyField ()]
hasLibrary :: Bool
docspecEnabled :: Bool
uris :: [URI]
projectName :: [Char]
testShowDetails :: [Char]
hasTests :: CompilerRange
pkgs :: [Package]
doctestEnabled :: Bool
..} = Config -> Project URI Void Package -> JobVersions -> Auxiliary
auxiliary Config
config Project URI Void Package
prj JobVersions
jobs

    justIf :: Bool -> a -> Maybe a
justIf Bool
True a
x  = forall a. a -> Maybe a
Just a
x
    justIf Bool
False a
_ = forall a. Maybe a
Nothing

    -- TODO: should this be part of MonadSh ?
    foldedSh :: Fold -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh Fold
label = Fold -> [Char] -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh' Fold
label [Char]
""

    anyGHCJS :: Bool
anyGHCJS = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any CompilerVersion -> Bool
isGHCJS Set CompilerVersion
allVersions

    -- https://github.com/travis-ci/docs-travis-ci-com/issues/949#issuecomment-276755003
    -- https://github.com/travis-ci/travis-rubies/blob/9f7962a881c55d32da7c76baefc58b89e3941d91/build.sh#L38-L44
    -- https://github.com/travis-ci/travis-build/blob/91bf066/lib/travis/build/shell/dsl.rb#L58-L63
    foldedSh' :: Fold -> String -> String -> Set Fold -> ShM () -> ShM ()
    foldedSh' :: Fold -> [Char] -> [Char] -> Set Fold -> ShM () -> ShM ()
foldedSh' Fold
label [Char]
sfx [Char]
plabel Set Fold
labels ShM ()
block
        | Fold
label forall a. Ord a => a -> Set a -> Bool
`S.notMember` Set Fold
labels = forall (m :: * -> *). MonadSh m => [Char] -> m () -> m ()
commentedBlock [Char]
plabel ShM ()
block
        | Bool
otherwise = case forall e (m :: * -> *).
(MonadErr e m, FromHsCiError e) =>
ShM () -> m [Sh]
runSh ShM ()
block of
            Left HsCiError
err  -> forall e (m :: * -> *) a. MonadErr e m => e -> m a
throwErr HsCiError
err
            Right [Sh]
shs
                | forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Sh -> Bool
isComment [Sh]
shs -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
                | Bool
otherwise         -> forall a.
(([Sh] -> [Sh]) -> Either HsCiError ([Sh] -> [Sh], a)) -> ShM a
ShM forall a b. (a -> b) -> a -> b
$ \[Sh] -> [Sh]
shs1 -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$
                    ( [Sh] -> [Sh]
shs1
                    forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> Sh
Comment [Char]
plabel forall a. a -> [a] -> [a]
:)
                    forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> Sh
Sh ([Char]
"echo '" forall a. [a] -> [a] -> [a]
++ [Char]
plabel forall a. [a] -> [a] -> [a]
++ [Char]
"' && echo -en 'travis_fold:start:" forall a. [a] -> [a] -> [a]
++ [Char]
label' forall a. [a] -> [a] -> [a]
++ [Char]
"\\\\r'") forall a. a -> [a] -> [a]
:)
                    forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Sh]
shs forall a. [a] -> [a] -> [a]
++)
                    forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> Sh
Sh ([Char]
"echo -en 'travis_fold:end:" forall a. [a] -> [a] -> [a]
++ [Char]
label' forall a. [a] -> [a] -> [a]
++ [Char]
"\\\\r'") forall a. a -> [a] -> [a]
:)
                    -- return ()
                    , ()
                    )
      where
        label' :: [Char]
label' | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
sfx  = Fold -> [Char]
showFold Fold
label
               | Bool
otherwise = Fold -> [Char]
showFold Fold
label forall a. [a] -> [a] -> [a]
++ [Char]
"-" forall a. [a] -> [a] -> [a]
++ [Char]
sfx


    -- GHC versions which need head.hackage
    headGhcVers :: Set CompilerVersion
    headGhcVers :: Set CompilerVersion
headGhcVers = forall a. (a -> Bool) -> Set a -> Set a
S.filter (VersionRange -> CompilerVersion -> Bool
previewGHC VersionRange
cfgHeadHackage) Set CompilerVersion
allVersions

    cabal :: String -> String
    cabal :: [Char] -> [Char]
cabal [Char]
cmd = [Char]
"${CABAL} " forall a. [a] -> [a] -> [a]
++ [Char]
cmd

    cabalTW :: String -> String
    cabalTW :: [Char] -> [Char]
cabalTW [Char]
cmd = [Char]
"travis_wait 40 ${CABAL} " forall a. [a] -> [a] -> [a]
++ [Char]
cmd

    forJob :: CompilerRange -> String -> Maybe String
    forJob :: CompilerRange -> [Char] -> Maybe [Char]
forJob CompilerRange
vr [Char]
cmd
        | forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (CompilerVersion -> CompilerRange -> Bool
`compilerWithinRange` CompilerRange
vr) Set CompilerVersion
allVersions       = forall a. a -> Maybe a
Just [Char]
cmd
        | Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (CompilerVersion -> CompilerRange -> Bool
`compilerWithinRange` CompilerRange
vr) Set CompilerVersion
allVersions = forall a. Maybe a
Nothing
        | Bool
otherwise                                        = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unwords
            [ [Char]
"if"
            , Set CompilerVersion -> CompilerRange -> [Char]
compilerVersionPredicate Set CompilerVersion
allVersions CompilerRange
vr
            , [Char]
"; then"
            , [Char]
cmd
            , [Char]
"; fi"
            ]

    shForJob :: CompilerRange -> String -> ShM ()
    shForJob :: CompilerRange -> [Char] -> ShM ()
shForJob CompilerRange
vr [Char]
cmd = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh (CompilerRange -> [Char] -> Maybe [Char]
forJob CompilerRange
vr [Char]
cmd)

    -- catForJob vr fp contents = shForJob vr (catCmd Double fp contents)

    generateCabalProject :: Bool -> ShM ()
    generateCabalProject :: Bool -> ShM ()
generateCabalProject Bool
dist = do
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
comment [Char]
"Generate cabal.project"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"rm -rf cabal.project cabal.project.local cabal.project.freeze"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"touch cabal.project"

        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines
            [ [Char]
cmd
            | Package
pkg <- [Package]
pkgs
            , let p :: [Char]
p | Bool
dist      = [Char] -> [Char]
pkgNameDirVariable (Package -> [Char]
pkgName Package
pkg)
                    | Bool
otherwise = Package -> [Char]
pkgDir Package
pkg
            , [Char]
cmd <- forall (t :: * -> *) a. Foldable t => t a -> [a]
toList forall a b. (a -> b) -> a -> b
$ CompilerRange -> [Char] -> Maybe [Char]
forJob (Set CompilerVersion -> CompilerRange
RangePoints forall a b. (a -> b) -> a -> b
$ Package -> Set CompilerVersion
pkgJobs Package
pkg) forall a b. (a -> b) -> a -> b
$
                [Char]
"echo \"packages: " forall a. [a] -> [a] -> [a]
++ [Char]
p forall a. [a] -> [a] -> [a]
++ [Char]
"\" >> cabal.project"
            ]

        case PackageScope
cfgErrorMissingMethods of
            PackageScope
PackageScopeNone  -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
            PackageScope
PackageScopeLocal -> forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Package]
pkgs forall a b. (a -> b) -> a -> b
$ \Pkg{[Char]
pkgName :: [Char]
pkgName :: Package -> [Char]
pkgName,Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs} -> do
                CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range (Version -> VersionRange
C.orLaterVersion ([Int] -> Version
C.mkVersion [Int
8,Int
2])) forall a. Lattice a => a -> a -> a
/\ Set CompilerVersion -> CompilerRange
RangePoints Set CompilerVersion
pkgJobs) forall a b. (a -> b) -> a -> b
$
                    [Char]
"echo 'package " forall a. [a] -> [a] -> [a]
++ [Char]
pkgName forall a. [a] -> [a] -> [a]
++ [Char]
"' >> cabal.project"
                CompilerRange -> [Char] -> ShM ()
shForJob (VersionRange -> CompilerRange
Range (Version -> VersionRange
C.orLaterVersion ([Int] -> Version
C.mkVersion [Int
8,Int
2])) forall a. Lattice a => a -> a -> a
/\ Set CompilerVersion -> CompilerRange
RangePoints Set CompilerVersion
pkgJobs) forall a b. (a -> b) -> a -> b
$
                    [Char]
"echo '  ghc-options: -Werror=missing-methods' >> cabal.project"
            PackageScope
PackageScopeAll   -> do
                forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"echo 'package *' >> cabal.project"
                forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"echo '  ghc-options: -Werror=missing-methods' >> cabal.project"

        [Char] -> [[Char]] -> ShM ()
cat [Char]
"cabal.project" forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]]
lines forall a b. (a -> b) -> a -> b
$ forall ann.
(ann -> CommentPosition)
-> (ann -> [[Char]] -> [[Char]])
-> Int
-> [PrettyField ann]
-> [Char]
C.showFields' (forall a b. a -> b -> a
const CommentPosition
C.NoComment) (forall a b. a -> b -> a
const forall a. a -> a
id) Int
2 forall a b. (a -> b) -> a -> b
$ [Char] -> [PrettyField ()]
extraCabalProjectFields [Char]
""

        -- If using head.hackage, allow building with newer versions of GHC boot libraries.
        -- Note that we put this in a cabal.project file, not ~/.cabal/config, in order to avoid
        -- https://github.com/haskell/cabal/issues/7291.
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall a. Set a -> Bool
S.null Set CompilerVersion
headGhcVers) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines forall a b. (a -> b) -> a -> b
$
            [ [Char]
"if $HEADHACKAGE; then"
            , [Char]
"echo \"allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\\1,/g')\" >> $CABALHOME/config"
            , [Char]
"fi"
            ]

        -- also write cabal.project.local file with
        -- @
        -- constraints: base installed
        -- constraints: array installed
        -- ...
        --
        -- omitting any local package names
        case [Installed] -> InstalledNormalised
normaliseInstalled [Installed]
cfgInstalled of
            InstalledDiff Set PackageName
pns -> forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unwords
                [ [Char]
"for pkg in $($HCPKG list --simple-output); do"
                , [Char]
"echo $pkg"
                , [Char]
"| sed 's/-[^-]*$//'"
                , [Char]
"| (grep -vE -- " forall a. [a] -> [a] -> [a]
++ [Char]
re forall a. [a] -> [a] -> [a]
++ [Char]
" || true)"
                , [Char]
"| sed 's/^/constraints: /'"
                , [Char]
"| sed 's/$/ installed/'"
                , [Char]
">> cabal.project.local; done"
                ]
              where
                pns' :: Set [Char]
pns' = forall b a. Ord b => (a -> b) -> Set a -> Set b
S.map PackageName -> [Char]
C.unPackageName Set PackageName
pns forall a. Ord a => Set a -> Set a -> Set a
`S.union` forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (forall a. a -> Set a
S.singleton forall b c a. (b -> c) -> (a -> b) -> a -> c
. Package -> [Char]
pkgName) [Package]
pkgs
                re :: [Char]
re = [Char]
"'^(" forall a. [a] -> [a] -> [a]
++ forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"|" (forall a. Set a -> [a]
S.toList Set [Char]
pns') forall a. [a] -> [a] -> [a]
++ [Char]
")$'"

            InstalledOnly Set PackageName
pns | Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set [Char]
pns') -> forall (m :: * -> *). MonadSh m => [Integer] -> [Char] -> m ()
sh' [Integer
2043] forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unwords
                [ [Char]
"for pkg in " forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
unwords (forall a. Set a -> [a]
S.toList Set [Char]
pns') forall a. [a] -> [a] -> [a]
++ [Char]
"; do"
                , [Char]
"echo \"constraints: $pkg installed\""
                , [Char]
">> cabal.project.local; done"
                ]
              where
                pns' :: Set [Char]
pns' = forall b a. Ord b => (a -> b) -> Set a -> Set b
S.map PackageName -> [Char]
C.unPackageName Set PackageName
pns forall a. Ord a => Set a -> Set a -> Set a
`S.difference` forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (forall a. a -> Set a
S.singleton forall b c a. (b -> c) -> (a -> b) -> a -> c
. Package -> [Char]
pkgName) [Package]
pkgs

            -- otherwise: nothing
            InstalledNormalised
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"cat cabal.project || true"
        forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh [Char]
"cat cabal.project.local || true"

    -- Needed to work around haskell/cabal#6214
    withHaddock :: String
    withHaddock :: [Char]
withHaddock = [Char]
"--with-haddock $HADDOCK"



data Quotes = Single | Double

escape :: Quotes -> String -> String
escape :: Quotes -> [Char] -> [Char]
escape Quotes
Single [Char]
xs = [Char]
"'" forall a. [a] -> [a] -> [a]
++ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Char -> [Char]
f [Char]
xs forall a. [a] -> [a] -> [a]
++ [Char]
"'" where
    f :: Char -> [Char]
f Char
'\0' = [Char]
""
    f Char
'\'' = [Char]
"'\"'\"'"
    f Char
x    = [Char
x]
escape Quotes
Double [Char]
xs = forall a. Show a => a -> [Char]
show [Char]
xs

catCmd :: Quotes -> FilePath -> [String] -> String
catCmd :: Quotes -> [Char] -> [[Char]] -> [Char]
catCmd Quotes
q [Char]
fp [[Char]]
contents = [[Char]] -> [Char]
unlines
    [ [Char]
"echo " forall a. [a] -> [a] -> [a]
++ Quotes -> [Char] -> [Char]
escape Quotes
q [Char]
l forall a. [a] -> [a] -> [a]
++ forall a. Int -> a -> [a]
replicate (Int
maxLength forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
l) Char
' ' forall a. [a] -> [a] -> [a]
++ [Char]
" >> " forall a. [a] -> [a] -> [a]
++ [Char]
fp
    | [Char]
l <- [[Char]]
contents
    ]
  where
    maxLength :: Int
maxLength = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Int
a [Char]
l -> forall a. Ord a => a -> a -> a
max Int
a (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
l)) Int
0 [[Char]]
contents
{-
-- https://travis-ci.community/t/multiline-commands-have-two-spaces-in-front-breaks-heredocs/2756
catCmd fp contents = unlines $
    [ "cat >> " ++ fp ++ " << HEREDOC" ] ++
    contents ++
    [ "HEREDOC" ]
-}

cat :: FilePath -> [String] -> ShM ()
cat :: [Char] -> [[Char]] -> ShM ()
cat [Char]
fp [[Char]]
contents = forall (m :: * -> *). MonadSh m => [Char] -> m ()
sh forall a b. (a -> b) -> a -> b
$ Quotes -> [Char] -> [[Char]] -> [Char]
catCmd Quotes
Double [Char]
fp [[Char]]
contents