{-# LANGUAGE NamedFieldPuns  #-}
{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -Wno-unused-matches #-}
module HaskellCI.Bash (
    makeBash
) where

import HaskellCI.Prelude

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

import Cabal.Project
import HaskellCI.Auxiliary
import HaskellCI.Bash.Template
import HaskellCI.Compiler
import HaskellCI.Config
import HaskellCI.Config.ConstraintSet
import HaskellCI.Config.Doctest
import HaskellCI.Config.Installed
import HaskellCI.Config.PackageScope
import HaskellCI.Config.Validity
import HaskellCI.Jobs
import HaskellCI.List
import HaskellCI.Package
import HaskellCI.Sh
import HaskellCI.ShVersionRange
import HaskellCI.Tools

{-
Bash-specific notes:

* We use -j for parallelism, as the exact number of cores depends on the
  particular machine the script is being run on.
-}

makeBash
    :: [String]
    -> Config
    -> Project URI Void Package
    -> JobVersions
    -> Either HsCiError Z -- TODO: writer
makeBash :: [String]
-> Config
-> Project URI Void Package
-> JobVersions
-> Either HsCiError Z
makeBash [String]
_argv config :: Config
config@Config {Bool
Natural
String
[String]
[PackageName]
[PrettyField ()]
[Installed]
[ConstraintSet]
Maybe String
Maybe Version
Maybe Jobs
VersionRange
Version
Set String
Set Fold
Map Version String
Ubuntu
PackageScope
HLintConfig
DoctestConfig
DocspecConfig
CopyFields
Components
TestedWithJobs
cfgTimeoutMinutes :: Config -> Natural
cfgGitHubActionName :: Config -> Maybe String
cfgRawTravis :: Config -> String
cfgRawProject :: Config -> [PrettyField ()]
cfgConstraintSets :: Config -> [ConstraintSet]
cfgHLint :: Config -> HLintConfig
cfgDocspec :: Config -> DocspecConfig
cfgDoctest :: Config -> DoctestConfig
cfgErrorMissingMethods :: Config -> PackageScope
cfgInsertVersion :: Config -> Bool
cfgGitHubPatches :: Config -> [String]
cfgTravisPatches :: Config -> [String]
cfgApt :: Config -> Set String
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 String
cfgGoogleChrome :: Config -> Bool
cfgPostgres :: Config -> Bool
cfgGhcHead :: Config -> Bool
cfgFolds :: Config -> Set Fold
cfgProjectName :: Config -> Maybe String
cfgEmailNotifications :: Config -> Bool
cfgIrcIfInOriginRepo :: Config -> Bool
cfgIrcPassword :: Config -> Maybe String
cfgIrcNickname :: Config -> Maybe String
cfgIrcChannels :: Config -> [String]
cfgOnlyBranches :: Config -> [String]
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 -> [String]
cfgCopyFields :: Config -> CopyFields
cfgEnabledJobs :: Config -> VersionRange
cfgTestedWith :: Config -> TestedWithJobs
cfgUbuntu :: Config -> Ubuntu
cfgJobs :: Config -> Maybe Jobs
cfgCabalInstallVersion :: Config -> Maybe Version
cfgTimeoutMinutes :: Natural
cfgGitHubActionName :: Maybe String
cfgRawTravis :: String
cfgRawProject :: [PrettyField ()]
cfgConstraintSets :: [ConstraintSet]
cfgHLint :: HLintConfig
cfgDocspec :: DocspecConfig
cfgDoctest :: DoctestConfig
cfgErrorMissingMethods :: PackageScope
cfgInsertVersion :: Bool
cfgGitHubPatches :: [String]
cfgTravisPatches :: [String]
cfgApt :: Set String
cfgGhcupVersion :: Version
cfgGhcupJobs :: VersionRange
cfgGhcupCabal :: Bool
cfgMacosJobs :: VersionRange
cfgLinuxJobs :: VersionRange
cfgLastInSeries :: Bool
cfgAllowFailures :: VersionRange
cfgEnv :: Map Version String
cfgGoogleChrome :: Bool
cfgPostgres :: Bool
cfgGhcHead :: Bool
cfgFolds :: Set Fold
cfgProjectName :: Maybe String
cfgEmailNotifications :: Bool
cfgIrcIfInOriginRepo :: Bool
cfgIrcPassword :: Maybe String
cfgIrcNickname :: Maybe String
cfgIrcChannels :: [String]
cfgOnlyBranches :: [String]
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 :: [String]
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
    -- Validity checks
    forall (m :: * -> *).
MonadErr HsCiError m =>
Config -> JobVersions -> m ()
checkConfigValidity Config
config JobVersions
jobs

    [String]
blocks <- forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Sh] -> String
shsToList) forall a b. (a -> b) -> a -> b
$ forall x. ListBuilder x () -> [x]
buildList forall a b. (a -> b) -> a -> b
$ do
        -- install doctest
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
doctestEnabled forall a b. (a -> b) -> a -> b
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"install doctest" forall a b. (a -> b) -> a -> b
$ do
            let range :: CompilerRange
range = VersionRange -> CompilerRange
Range (DoctestConfig -> VersionRange
cfgDoctestEnabled DoctestConfig
cfgDoctest) forall a. Lattice a => a -> a -> a
/\ CompilerRange
doctestJobVersionRange
            forall (m :: * -> *). MonadSh m => String -> m ()
comment String
"install doctest"
            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range String
"$CABAL v2-install $ARG_COMPILER --ignore-project -j doctest --constraint='doctest ^>=0.20'"
            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range String
"doctest --version"

        -- install hlint
        -- TODO

        -- autoreconf ...
        -- hmm, source is read-only...

        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"initial cabal.project for sdist" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
change_dir String
"$BUILDDIR"
            String -> ShM ()
run_cmd String
"touch cabal.project"
            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
$ \Package
pkg ->
                CompilerRange -> String -> String -> ShM ()
echo_if_to (Set CompilerVersion -> CompilerRange
RangePoints forall a b. (a -> b) -> a -> b
$ Package -> Set CompilerVersion
pkgJobs Package
pkg) String
"cabal.project" forall a b. (a -> b) -> a -> b
$ String
"packages: $SRCDIR/" forall a. [a] -> [a] -> [a]
++ Package -> String
pkgDir Package
pkg
            String -> ShM ()
run_cmd String
"cat cabal.project"

        -- sdist
        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"sdist" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
run_cmd String
"mkdir -p \"$BUILDDIR/sdist\""
            -- TODO: check if cabal-install-3.4 can be run on read only system
            String -> ShM ()
run_cmd String
"$CABAL sdist all --output-dir \"$BUILDDIR/sdist\""

        -- find and unpack sdist
        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"unpack" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
change_dir String
"$BUILDDIR"
            String -> ShM ()
run_cmd String
"mkdir -p \"$BUILDDIR/unpacked\""
            String -> ShM ()
run_cmd String
"find \"$BUILDDIR/sdist\" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C \"$BUILDDIR/unpacked\" -xzvf {} \\;"

        -- write cabal.project
        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"generate cabal.project" 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{String
pkgName :: Package -> String
pkgName :: String
pkgName} -> do
                forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ String -> String
pkgNameDirVariable' String
pkgName forall a. [a] -> [a] -> [a]
++ String
"=\"$(find \"$BUILDDIR/unpacked\" -maxdepth 1 -type d -regex '.*/" forall a. [a] -> [a] -> [a]
++ String
pkgName forall a. [a] -> [a] -> [a]
++ String
"-[0-9.]*')\""

            String -> ShM ()
run_cmd String
"touch cabal.project"
            String -> ShM ()
run_cmd String
"touch cabal.project.local"

            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
$ \Package
pkg ->
                CompilerRange -> String -> String -> ShM ()
echo_if_to (Set CompilerVersion -> CompilerRange
RangePoints forall a b. (a -> b) -> a -> b
$ Package -> Set CompilerVersion
pkgJobs Package
pkg) String
"cabal.project" forall a b. (a -> b) -> a -> b
$ String
"packages: " forall a. [a] -> [a] -> [a]
++ String -> String
pkgNameDirVariable (Package -> String
pkgName Package
pkg)

            -- per package options
            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{String
pkgName :: String
pkgName :: Package -> String
pkgName,Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs} -> do
                    let range :: CompilerRange
range = 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
                    CompilerRange -> String -> String -> ShM ()
echo_if_to CompilerRange
range String
"cabal.project" forall a b. (a -> b) -> a -> b
$ String
"package " forall a. [a] -> [a] -> [a]
++ String
pkgName
                    CompilerRange -> String -> String -> ShM ()
echo_if_to CompilerRange
range String
"cabal.project" forall a b. (a -> b) -> a -> b
$ String
"    ghc-options: -Werror=missing-methods"
                PackageScope
PackageScopeAll   -> String -> String -> ShM ()
cat String
"cabal.project" forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
                    [ String
"package *"
                    , String
"  ghc-options: -Werror=missing-methods"
                    ]

            -- extra cabal.project fields
            String -> String -> ShM ()
cat String
"cabal.project" forall a b. (a -> b) -> a -> b
$ forall ann.
(ann -> CommentPosition)
-> (ann -> [String] -> [String])
-> Int
-> [PrettyField ann]
-> String
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
$ String -> [PrettyField ()]
extraCabalProjectFields String
""

            -- 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 => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
                    [ String
"$HCPKG list --simple-output --names-only"
                    , String
"| perl -ne 'for (split /\\s+/) { print \"constraints: $_ installed\\n\" unless /" forall a. [a] -> [a] -> [a]
++ String
re forall a. [a] -> [a] -> [a]
++ String
"/; }'"
                    , String
">> cabal.project.local"
                    ]
                  where
                    pns' :: Set String
pns' = forall b a. Ord b => (a -> b) -> Set a -> Set b
S.map PackageName -> String
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 -> String
pkgName) [Package]
pkgs
                    re :: String
re = String
"^(" forall a. [a] -> [a] -> [a]
++ forall a. [a] -> [[a]] -> [a]
intercalate String
"|" (forall a. Set a -> [a]
S.toList Set String
pns') forall a. [a] -> [a] -> [a]
++ String
")$"

                InstalledOnly Set PackageName
pns | Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set String
pns') -> String -> String -> ShM ()
cat String
"cabal.project.local" forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
                    [ String
"constraints: " forall a. [a] -> [a] -> [a]
++ String
pkg forall a. [a] -> [a] -> [a]
++ String
" installed"
                    | String
pkg <- forall a. Set a -> [a]
S.toList Set String
pns'
                    ]
                  where
                    pns' :: Set String
pns' = forall b a. Ord b => (a -> b) -> Set a -> Set b
S.map PackageName -> String
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 -> String
pkgName) [Package]
pkgs

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

            String -> ShM ()
run_cmd String
"cat cabal.project"
            String -> ShM ()
run_cmd String
"cat cabal.project.local"

        -- dump install plan
        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"dump install plan" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
run_cmd String
"$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all"
            String -> ShM ()
run_cmd String
"cabal-plan"

        -- install dependencies
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgInstallDeps forall a b. (a -> b) -> a -> b
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"install dependencies" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
run_cmd String
"$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j all"
            String -> ShM ()
run_cmd String
"$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j all"

        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (VersionRange -> VersionRange -> Bool
equivVersionRanges VersionRange
C.noVersion VersionRange
cfgNoTestsNoBench) forall a b. (a -> b) -> a -> b
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"build w/o tests" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
run_cmd String
"$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all"

        -- build
        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"build" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
run_cmd String
"$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all"

        -- tests
        String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"tests" forall a b. (a -> b) -> a -> b
$ do
            let range :: CompilerRange
range = 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
            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range forall a b. (a -> b) -> a -> b
$ String
"$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all" forall a. [a] -> [a] -> [a]
++ String
testShowDetails

        -- doctest
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
doctestEnabled forall a b. (a -> b) -> a -> b
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"doctest" forall a b. (a -> b) -> a -> b
$ do
            let doctestOptions :: String
doctestOptions = [String] -> String
unwords forall a b. (a -> b) -> a -> b
$ DoctestConfig -> [String]
cfgDoctestOptions DoctestConfig
cfgDoctest

            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 :: String -> [String]
manglePkgNames String
n
                        | forall (t :: * -> *) a. Foldable t => t a -> Bool
null Set CompilerVersion
macosVersions = [String
n]
                        | Bool
otherwise          = [String
n, forall a. (a -> Bool) -> [a] -> [a]
filter Char -> Bool
notVowel String
n]
                      where
                        notVowel :: Char -> Bool
notVowel Char
c = forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Char
c (String
"aeiou" :: String)
                let filterPkgs :: String
filterPkgs = forall a. [a] -> [[a]] -> [a]
intercalate String
"|" forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (String -> [String]
manglePkgNames forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageName -> String
C.unPackageName) forall a b. (a -> b) -> a -> b
$ DoctestConfig -> [PackageName]
cfgDoctestFilterEnvPkgs DoctestConfig
cfgDoctest
                String -> ShM ()
run_cmd forall a b. (a -> b) -> a -> b
$ String
"perl -i -e 'while (<ARGV>) { print unless /package-id\\s+(" forall a. [a] -> [a] -> [a]
++ String
filterPkgs forall a. [a] -> [a] -> [a]
++ String
")-\\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{String
pkgName :: String
pkgName :: Package -> String
pkgName,GenericPackageDescription
pkgGpd :: Package -> GenericPackageDescription
pkgGpd :: GenericPackageDescription
pkgGpd,Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs} ->
                forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String -> PackageName
C.mkPackageName String
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 -> [[String]]
doctestArgs GenericPackageDescription
pkgGpd) forall a b. (a -> b) -> a -> b
$ \[String]
args -> do
                        let args' :: String
args' = [String] -> String
unwords [String]
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 [String]
args) forall a b. (a -> b) -> a -> b
$ do
                            CompilerRange -> String -> ShM ()
change_dir_if CompilerRange
vr forall a b. (a -> b) -> a -> b
$ String -> String
pkgNameDirVariable String
pkgName
                            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
vr forall a b. (a -> b) -> a -> b
$ String
"doctest " forall a. [a] -> [a] -> [a]
++ String
doctestOptions forall a. [a] -> [a] -> [a]
++ String
" " forall a. [a] -> [a] -> [a]
++ String
args'

        -- hlint
        -- TODO

        -- cabal check
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
cfgCheck forall a b. (a -> b) -> a -> b
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"cabal check" 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{String
pkgName :: String
pkgName :: Package -> String
pkgName,Set CompilerVersion
pkgJobs :: Set CompilerVersion
pkgJobs :: Package -> Set CompilerVersion
pkgJobs} -> do
                let range :: CompilerRange
range = Set CompilerVersion -> CompilerRange
RangePoints Set CompilerVersion
pkgJobs
                CompilerRange -> String -> ShM ()
change_dir_if CompilerRange
range forall a b. (a -> b) -> a -> b
$ String -> String
pkgNameDirVariable String
pkgName
                CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range String
"${CABAL} -vnormal check"
            String -> ShM ()
change_dir String
"$BUILDDIR"

        -- 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
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"haddock" forall a b. (a -> b) -> a -> b
$ do
            let range :: CompilerRange
range = CompilerRange
RangeGHC forall a. Lattice a => a -> a -> a
/\ VersionRange -> CompilerRange
Range VersionRange
cfgHaddock
            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range String
"$CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all"

        -- unconstrained build
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (VersionRange -> VersionRange -> Bool
equivVersionRanges VersionRange
C.noVersion VersionRange
cfgUnconstrainted) forall a b. (a -> b) -> a -> b
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"unconstrained build" forall a b. (a -> b) -> a -> b
$ do
            let range :: CompilerRange
range = VersionRange -> CompilerRange
Range VersionRange
cfgUnconstrainted
            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range String
"rm -f cabal.project.local"
            CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
range String
"$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all"

        -- 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
$ String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
"constraint sets" forall a b. (a -> b) -> a -> b
$ do
            String -> ShM ()
run_cmd String
"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 :: String
name            = ConstraintSet -> String
csName ConstraintSet
cs
                let run_cmd_cs :: String -> ShM ()
run_cmd_cs      = CompilerRange -> String -> ShM ()
run_cmd_if (VersionRange -> CompilerRange
Range (ConstraintSet -> VersionRange
csGhcVersions ConstraintSet
cs))
                let run_cmd_cs' :: CompilerRange -> String -> ShM ()
run_cmd_cs' CompilerRange
r   = CompilerRange -> String -> ShM ()
run_cmd_if (VersionRange -> CompilerRange
Range (ConstraintSet -> VersionRange
csGhcVersions ConstraintSet
cs) forall a. Lattice a => a -> a -> a
/\ CompilerRange
r)
                let testFlag :: String
testFlag        = if ConstraintSet -> Bool
csTests ConstraintSet
cs then String
"--enable-tests" else String
"--disable-tests"
                let benchFlag :: String
benchFlag       = if ConstraintSet -> Bool
csBenchmarks ConstraintSet
cs then String
"--enable-benchmarks" else String
"--disable-benchmarks"
                let constraintFlags :: [String]
constraintFlags = forall a b. (a -> b) -> [a] -> [b]
map (\String
x ->  String
"--constraint='" forall a. [a] -> [a] -> [a]
++ String
x forall a. [a] -> [a] -> [a]
++ String
"'") (ConstraintSet -> [String]
csConstraints ConstraintSet
cs)
                let allFlags :: String
allFlags        = [String] -> String
unwords (String
testFlag forall a. a -> [a] -> [a]
: String
benchFlag forall a. a -> [a] -> [a]
: [String]
constraintFlags)

                String -> ShM ()
put_info forall a b. (a -> b) -> a -> b
$ String
"constraint set " forall a. [a] -> [a] -> [a]
++ String
name
                String -> ShM ()
run_cmd_cs forall a b. (a -> b) -> a -> b
$ String
"$CABAL v2-build $ARG_COMPILER " forall a. [a] -> [a] -> [a]
++ String
allFlags forall a. [a] -> [a] -> [a]
++ String
" --dependencies-only -j all"
                String -> ShM ()
run_cmd_cs forall a b. (a -> b) -> a -> b
$ String
"$CABAL v2-build $ARG_COMPILER " forall a. [a] -> [a] -> [a]
++ String
allFlags forall a. [a] -> [a] -> [a]
++ String
" all"
                forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ConstraintSet -> Bool
csRunTests ConstraintSet
cs) forall a b. (a -> b) -> a -> b
$
                    CompilerRange -> String -> ShM ()
run_cmd_cs' CompilerRange
hasTests forall a b. (a -> b) -> a -> b
$ String
"$CABAL v2-test $ARG_COMPILER " forall a. [a] -> [a] -> [a]
++ String
allFlags forall a. [a] -> [a] -> [a]
++ String
" all"
                forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ConstraintSet -> Bool
csHaddock ConstraintSet
cs) forall a b. (a -> b) -> a -> b
$
                    String -> ShM ()
run_cmd_cs forall a b. (a -> b) -> a -> b
$ String
"$CABAL v2-haddock --haddock-all $ARG_COMPILER " forall a. [a] -> [a] -> [a]
++ String
withHaddock forall a. [a] -> [a] -> [a]
++ String
" " forall a. [a] -> [a] -> [a]
++ String
allFlags forall a. [a] -> [a] -> [a]
++ String
" all"

    forall (m :: * -> *) a. Monad m => a -> m a
return Z
defaultZ
        { zJobs :: [String]
zJobs =
            [ forall a. Pretty a => a -> String
prettyShow Version
v
            | GHC Version
v <- forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Set CompilerVersion
linuxVersions
            ]
        , zBlocks :: [String]
zBlocks = [String]
blocks
        , zApt :: [String]
zApt = forall a. Set a -> [a]
S.toList Set String
cfgApt
        , zTestsCond :: String
zTestsCond = Set CompilerVersion -> CompilerRange -> String
compilerVersionArithPredicate Set CompilerVersion
linuxVersions forall a b. (a -> b) -> a -> b
$ VersionRange -> CompilerRange
Range VersionRange
cfgTests
        , zBenchCond :: String
zBenchCond = Set CompilerVersion -> CompilerRange -> String
compilerVersionArithPredicate Set CompilerVersion
linuxVersions forall a b. (a -> b) -> a -> b
$ VersionRange -> CompilerRange
Range VersionRange
cfgBenchmarks
        }
  where
    Auxiliary {Bool
String
[URI]
[Package]
CompilerRange
String -> [PrettyField ()]
haddockFlags :: Auxiliary -> String
runHaddock :: Auxiliary -> Bool
anyJobUsesHeadHackage :: Auxiliary -> Bool
testShowDetails :: Auxiliary -> String
extraCabalProjectFields :: Auxiliary -> String -> [PrettyField ()]
hasLibrary :: Auxiliary -> Bool
hasTests :: Auxiliary -> CompilerRange
docspecEnabled :: Auxiliary -> Bool
doctestEnabled :: Auxiliary -> Bool
projectName :: Auxiliary -> String
uris :: Auxiliary -> [URI]
pkgs :: Auxiliary -> [Package]
haddockFlags :: String
runHaddock :: Bool
anyJobUsesHeadHackage :: Bool
hasLibrary :: Bool
docspecEnabled :: Bool
projectName :: String
uris :: [URI]
testShowDetails :: String
hasTests :: CompilerRange
extraCabalProjectFields :: String -> [PrettyField ()]
pkgs :: [Package]
doctestEnabled :: Bool
..} = Config -> Project URI Void Package -> JobVersions -> Auxiliary
auxiliary Config
config Project URI Void Package
prj JobVersions
jobs

    -- TODO: this can be smart and do nothing is there are only comments in [Sh]
    step :: String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
    step :: String -> ShM () -> ListBuilder (Either HsCiError [Sh]) ()
step String
name ShM ()
action = forall x. x -> ListBuilder x ()
item forall a b. (a -> b) -> a -> b
$ forall e (m :: * -> *).
(MonadErr e m, FromHsCiError e) =>
ShM () -> m [Sh]
runSh forall a b. (a -> b) -> a -> b
$ do
        forall (m :: * -> *). MonadSh m => String -> m ()
comment String
name
        String -> ShM ()
put_info String
name
        ShM ()
action

    put_info :: String -> ShM ()
    put_info :: String -> ShM ()
put_info String
s = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ String
"put_info " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
s

    change_dir :: String -> ShM ()
    change_dir :: String -> ShM ()
change_dir String
dir = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ String
"change_dir " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
dir

    change_dir_if :: CompilerRange -> String -> ShM ()
    change_dir_if :: CompilerRange -> String -> ShM ()
change_dir_if CompilerRange
vr String
dir
        | forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (CompilerVersion -> CompilerRange -> Bool
`compilerWithinRange` CompilerRange
vr) Set CompilerVersion
linuxVersions       = String -> ShM ()
change_dir String
dir
        | 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
linuxVersions = forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        | Bool
otherwise = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
            [ String
"change_dir_if"
            , Set CompilerVersion -> CompilerRange -> String
compilerVersionArithPredicate Set CompilerVersion
linuxVersions CompilerRange
vr
            , String
dir
            ]

    run_cmd :: String -> ShM ()
    run_cmd :: String -> ShM ()
run_cmd String
cmd = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
        [ String
"run_cmd"
        , String
cmd
        ]

    run_cmd_if :: CompilerRange -> String -> ShM ()
    run_cmd_if :: CompilerRange -> String -> ShM ()
run_cmd_if CompilerRange
vr String
cmd
        | forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (CompilerVersion -> CompilerRange -> Bool
`compilerWithinRange` CompilerRange
vr) Set CompilerVersion
linuxVersions       = String -> ShM ()
run_cmd String
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
linuxVersions = forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        | Bool
otherwise = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
            [ String
"run_cmd_if"
            , Set CompilerVersion -> CompilerRange -> String
compilerVersionArithPredicate Set CompilerVersion
linuxVersions CompilerRange
vr
            , String
cmd
            ]

    echo_if_to :: CompilerRange -> FilePath -> String -> ShM ()
    echo_if_to :: CompilerRange -> String -> String -> ShM ()
echo_if_to CompilerRange
vr String
path String
contents
        | forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (CompilerVersion -> CompilerRange -> Bool
`compilerWithinRange` CompilerRange
vr) Set CompilerVersion
linuxVersions = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
            [ String
"echo_to"
            , String
path
            , forall a. Show a => a -> String
show String
contents
            ]
        | 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
linuxVersions = forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        | Bool
otherwise = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
            [ String
"echo_if_to"
            , Set CompilerVersion -> CompilerRange -> String
compilerVersionArithPredicate Set CompilerVersion
linuxVersions CompilerRange
vr
            , String
path
            , forall a. Show a => a -> String
show String
contents
            ]

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

shsToList :: [Sh] -> String
shsToList :: [Sh] -> String
shsToList = [String] -> String
unlines forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Sh -> String
f where
    f :: Sh -> String
f (Sh String
x)      = String
x
    f (Comment String
c) = String
"# " forall a. [a] -> [a] -> [a]
++ String
c

cat :: FilePath -> String -> ShM ()
cat :: String -> String -> ShM ()
cat String
path String
contents = forall (m :: * -> *). MonadSh m => String -> m ()
sh forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    [ String
"cat >> " forall a. [a] -> [a] -> [a]
++ String
path forall a. [a] -> [a] -> [a]
++ String
" <<EOF\n"
    , String
contents
    , String
"EOF"
    ]