{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -- | Configuration options for building. module Stack.Types.Config.Build ( BuildOpts (..) , BuildCommand (..) , defaultBuildOpts , defaultBuildOptsCLI , BuildOptsCLI (..) , BuildOptsMonoid (..) , TestOpts (..) , defaultTestOpts , TestOptsMonoid (..) , HaddockOpts (..) , defaultHaddockOpts , HaddockOptsMonoid (..) , BenchmarkOpts (..) , defaultBenchmarkOpts , BenchmarkOptsMonoid (..) , FileWatchOpts (..) , BuildSubset (..) , ApplyCLIFlag (..) , boptsCLIFlagsByName , CabalVerbosity (..) , toFirstCabalVerbosity ) where import qualified Data.Map.Strict as Map import qualified Data.Text as T import Distribution.Parsec ( Parsec (..), simpleParsec ) import Distribution.Verbosity ( Verbosity, normal, verbose ) import Generics.Deriving.Monoid ( memptydefault, mappenddefault ) import Pantry.Internal.AesonExtended import Stack.Prelude -- | Build options that is interpreted by the build command. -- This is built up from BuildOptsCLI and BuildOptsMonoid data BuildOpts = BuildOpts {boptsLibProfile :: !Bool ,boptsExeProfile :: !Bool ,boptsLibStrip :: !Bool ,boptsExeStrip :: !Bool ,boptsHaddock :: !Bool -- ^ Build haddocks? ,boptsHaddockOpts :: !HaddockOpts -- ^ Options to pass to haddock ,boptsOpenHaddocks :: !Bool -- ^ Open haddocks in the browser? ,boptsHaddockDeps :: !(Maybe Bool) -- ^ Build haddocks for dependencies? ,boptsHaddockInternal :: !Bool -- ^ Build haddocks for all symbols and packages, like @cabal haddock --internal@ ,boptsHaddockHyperlinkSource :: !Bool -- ^ Build hyperlinked source if possible. Fallback to -- @hscolour@. Disable for no sources. ,boptsInstallExes :: !Bool -- ^ Install executables to user path after building? ,boptsInstallCompilerTool :: !Bool -- ^ Install executables to compiler tools path after building? ,boptsPreFetch :: !Bool -- ^ Fetch all packages immediately -- ^ Watch files for changes and automatically rebuild ,boptsKeepGoing :: !(Maybe Bool) -- ^ Keep building/running after failure ,boptsKeepTmpFiles :: !Bool -- ^ Keep intermediate files and build directories ,boptsForceDirty :: !Bool -- ^ Force treating all local packages as having dirty files ,boptsTests :: !Bool -- ^ Turn on tests for local targets ,boptsTestOpts :: !TestOpts -- ^ Additional test arguments ,boptsBenchmarks :: !Bool -- ^ Turn on benchmarks for local targets ,boptsBenchmarkOpts :: !BenchmarkOpts -- ^ Additional test arguments -- ^ Commands (with arguments) to run after a successful build -- ^ Only perform the configure step when building ,boptsReconfigure :: !Bool -- ^ Perform the configure step even if already configured ,boptsCabalVerbose :: !CabalVerbosity -- ^ Ask Cabal to be verbose in its builds ,boptsSplitObjs :: !Bool -- ^ Whether to enable split-objs. ,boptsSkipComponents :: ![Text] -- ^ Which components to skip when building ,boptsInterleavedOutput :: !Bool -- ^ Should we use the interleaved GHC output when building -- multiple packages? ,boptsDdumpDir :: !(Maybe Text) } deriving (Show) defaultBuildOpts :: BuildOpts defaultBuildOpts = BuildOpts { boptsLibProfile = defaultFirstFalse buildMonoidLibProfile , boptsExeProfile = defaultFirstFalse buildMonoidExeProfile , boptsLibStrip = defaultFirstTrue buildMonoidLibStrip , boptsExeStrip = defaultFirstTrue buildMonoidExeStrip , boptsHaddock = False , boptsHaddockOpts = defaultHaddockOpts , boptsOpenHaddocks = defaultFirstFalse buildMonoidOpenHaddocks , boptsHaddockDeps = Nothing , boptsHaddockInternal = defaultFirstFalse buildMonoidHaddockInternal , boptsHaddockHyperlinkSource = defaultFirstTrue buildMonoidHaddockHyperlinkSource , boptsInstallExes = defaultFirstFalse buildMonoidInstallExes , boptsInstallCompilerTool = defaultFirstFalse buildMonoidInstallCompilerTool , boptsPreFetch = defaultFirstFalse buildMonoidPreFetch , boptsKeepGoing = Nothing , boptsKeepTmpFiles = defaultFirstFalse buildMonoidKeepTmpFiles , boptsForceDirty = defaultFirstFalse buildMonoidForceDirty , boptsTests = defaultFirstFalse buildMonoidTests , boptsTestOpts = defaultTestOpts , boptsBenchmarks = defaultFirstFalse buildMonoidBenchmarks , boptsBenchmarkOpts = defaultBenchmarkOpts , boptsReconfigure = defaultFirstFalse buildMonoidReconfigure , boptsCabalVerbose = CabalVerbosity normal , boptsSplitObjs = defaultFirstFalse buildMonoidSplitObjs , boptsSkipComponents = [] , boptsInterleavedOutput = defaultFirstTrue buildMonoidInterleavedOutput , boptsDdumpDir = Nothing } defaultBuildOptsCLI ::BuildOptsCLI defaultBuildOptsCLI = BuildOptsCLI { boptsCLITargets = [] , boptsCLIDryrun = False , boptsCLIFlags = Map.empty , boptsCLIGhcOptions = [] , boptsCLIBuildSubset = BSAll , boptsCLIFileWatch = NoFileWatch , boptsCLIWatchAll = False , boptsCLIExec = [] , boptsCLIOnlyConfigure = False , boptsCLICommand = Build , boptsCLIInitialBuildSteps = False } -- | How to apply a CLI flag data ApplyCLIFlag = ACFAllProjectPackages -- ^ Apply to all project packages which have such a flag name available. | ACFByName !PackageName -- ^ Apply to the specified package only. deriving (Show, Eq, Ord) -- | Only flags set via 'ACFByName' boptsCLIFlagsByName :: BuildOptsCLI -> Map PackageName (Map FlagName Bool) boptsCLIFlagsByName = Map.fromList . mapMaybe go . Map.toList . boptsCLIFlags where go (ACFAllProjectPackages, _) = Nothing go (ACFByName name, flags) = Just (name, flags) -- | Build options that may only be specified from the CLI data BuildOptsCLI = BuildOptsCLI { boptsCLITargets :: ![Text] , boptsCLIDryrun :: !Bool , boptsCLIGhcOptions :: ![Text] , boptsCLIFlags :: !(Map ApplyCLIFlag (Map FlagName Bool)) , boptsCLIBuildSubset :: !BuildSubset , boptsCLIFileWatch :: !FileWatchOpts , boptsCLIWatchAll :: !Bool , boptsCLIExec :: ![(String, [String])] , boptsCLIOnlyConfigure :: !Bool , boptsCLICommand :: !BuildCommand , boptsCLIInitialBuildSteps :: !Bool } deriving Show -- | Command sum type for conditional arguments. data BuildCommand = Build | Test | Haddock | Bench | Install deriving (Eq, Show) -- | Build options that may be specified in the stack.yaml or from the CLI data BuildOptsMonoid = BuildOptsMonoid { buildMonoidTrace :: !Any , buildMonoidProfile :: !Any , buildMonoidNoStrip :: !Any , buildMonoidLibProfile :: !FirstFalse , buildMonoidExeProfile :: !FirstFalse , buildMonoidLibStrip :: !FirstTrue , buildMonoidExeStrip :: !FirstTrue , buildMonoidHaddock :: !FirstFalse , buildMonoidHaddockOpts :: !HaddockOptsMonoid , buildMonoidOpenHaddocks :: !FirstFalse , buildMonoidHaddockDeps :: !(First Bool) , buildMonoidHaddockInternal :: !FirstFalse , buildMonoidHaddockHyperlinkSource :: !FirstTrue , buildMonoidInstallExes :: !FirstFalse , buildMonoidInstallCompilerTool :: !FirstFalse , buildMonoidPreFetch :: !FirstFalse , buildMonoidKeepGoing :: !(First Bool) , buildMonoidKeepTmpFiles :: !FirstFalse , buildMonoidForceDirty :: !FirstFalse , buildMonoidTests :: !FirstFalse , buildMonoidTestOpts :: !TestOptsMonoid , buildMonoidBenchmarks :: !FirstFalse , buildMonoidBenchmarkOpts :: !BenchmarkOptsMonoid , buildMonoidReconfigure :: !FirstFalse , buildMonoidCabalVerbose :: !(First CabalVerbosity) , buildMonoidSplitObjs :: !FirstFalse , buildMonoidSkipComponents :: ![Text] , buildMonoidInterleavedOutput :: !FirstTrue , buildMonoidDdumpDir :: !(First Text) } deriving (Show, Generic) instance FromJSON (WithJSONWarnings BuildOptsMonoid) where parseJSON = withObjectWarnings "BuildOptsMonoid" (\o -> do let buildMonoidTrace = Any False buildMonoidProfile = Any False buildMonoidNoStrip = Any False buildMonoidLibProfile <- FirstFalse <$> o ..:? buildMonoidLibProfileArgName buildMonoidExeProfile <-FirstFalse <$> o ..:? buildMonoidExeProfileArgName buildMonoidLibStrip <- FirstTrue <$> o ..:? buildMonoidLibStripArgName buildMonoidExeStrip <-FirstTrue <$> o ..:? buildMonoidExeStripArgName buildMonoidHaddock <- FirstFalse <$> o ..:? buildMonoidHaddockArgName buildMonoidHaddockOpts <- jsonSubWarnings (o ..:? buildMonoidHaddockOptsArgName ..!= mempty) buildMonoidOpenHaddocks <- FirstFalse <$> o ..:? buildMonoidOpenHaddocksArgName buildMonoidHaddockDeps <- First <$> o ..:? buildMonoidHaddockDepsArgName buildMonoidHaddockInternal <- FirstFalse <$> o ..:? buildMonoidHaddockInternalArgName buildMonoidHaddockHyperlinkSource <- FirstTrue <$> o ..:? buildMonoidHaddockHyperlinkSourceArgName buildMonoidInstallExes <- FirstFalse <$> o ..:? buildMonoidInstallExesArgName buildMonoidInstallCompilerTool <- FirstFalse <$> o ..:? buildMonoidInstallCompilerToolArgName buildMonoidPreFetch <- FirstFalse <$> o ..:? buildMonoidPreFetchArgName buildMonoidKeepGoing <- First <$> o ..:? buildMonoidKeepGoingArgName buildMonoidKeepTmpFiles <- FirstFalse <$> o ..:? buildMonoidKeepTmpFilesArgName buildMonoidForceDirty <- FirstFalse <$> o ..:? buildMonoidForceDirtyArgName buildMonoidTests <- FirstFalse <$> o ..:? buildMonoidTestsArgName buildMonoidTestOpts <- jsonSubWarnings (o ..:? buildMonoidTestOptsArgName ..!= mempty) buildMonoidBenchmarks <- FirstFalse <$> o ..:? buildMonoidBenchmarksArgName buildMonoidBenchmarkOpts <- jsonSubWarnings (o ..:? buildMonoidBenchmarkOptsArgName ..!= mempty) buildMonoidReconfigure <- FirstFalse <$> o ..:? buildMonoidReconfigureArgName cabalVerbosity <- First <$> o ..:? buildMonoidCabalVerbosityArgName cabalVerbose <- FirstFalse <$> o ..:? buildMonoidCabalVerboseArgName let buildMonoidCabalVerbose = cabalVerbosity <> toFirstCabalVerbosity cabalVerbose buildMonoidSplitObjs <- FirstFalse <$> o ..:? buildMonoidSplitObjsName buildMonoidSkipComponents <- o ..:? buildMonoidSkipComponentsName ..!= mempty buildMonoidInterleavedOutput <- FirstTrue <$> o ..:? buildMonoidInterleavedOutputName buildMonoidDdumpDir <- o ..:? buildMonoidDdumpDirName ..!= mempty pure BuildOptsMonoid{..}) buildMonoidLibProfileArgName :: Text buildMonoidLibProfileArgName = "library-profiling" buildMonoidExeProfileArgName :: Text buildMonoidExeProfileArgName = "executable-profiling" buildMonoidLibStripArgName :: Text buildMonoidLibStripArgName = "library-stripping" buildMonoidExeStripArgName :: Text buildMonoidExeStripArgName = "executable-stripping" buildMonoidHaddockArgName :: Text buildMonoidHaddockArgName = "haddock" buildMonoidHaddockOptsArgName :: Text buildMonoidHaddockOptsArgName = "haddock-arguments" buildMonoidOpenHaddocksArgName :: Text buildMonoidOpenHaddocksArgName = "open-haddocks" buildMonoidHaddockDepsArgName :: Text buildMonoidHaddockDepsArgName = "haddock-deps" buildMonoidHaddockInternalArgName :: Text buildMonoidHaddockInternalArgName = "haddock-internal" buildMonoidHaddockHyperlinkSourceArgName :: Text buildMonoidHaddockHyperlinkSourceArgName = "haddock-hyperlink-source" buildMonoidInstallExesArgName :: Text buildMonoidInstallExesArgName = "copy-bins" buildMonoidInstallCompilerToolArgName :: Text buildMonoidInstallCompilerToolArgName = "copy-compiler-tool" buildMonoidPreFetchArgName :: Text buildMonoidPreFetchArgName = "prefetch" buildMonoidKeepGoingArgName :: Text buildMonoidKeepGoingArgName = "keep-going" buildMonoidKeepTmpFilesArgName :: Text buildMonoidKeepTmpFilesArgName = "keep-tmp-files" buildMonoidForceDirtyArgName :: Text buildMonoidForceDirtyArgName = "force-dirty" buildMonoidTestsArgName :: Text buildMonoidTestsArgName = "test" buildMonoidTestOptsArgName :: Text buildMonoidTestOptsArgName = "test-arguments" buildMonoidBenchmarksArgName :: Text buildMonoidBenchmarksArgName = "bench" buildMonoidBenchmarkOptsArgName :: Text buildMonoidBenchmarkOptsArgName = "benchmark-opts" buildMonoidReconfigureArgName :: Text buildMonoidReconfigureArgName = "reconfigure" buildMonoidCabalVerbosityArgName :: Text buildMonoidCabalVerbosityArgName = "cabal-verbosity" buildMonoidCabalVerboseArgName :: Text buildMonoidCabalVerboseArgName = "cabal-verbose" buildMonoidSplitObjsName :: Text buildMonoidSplitObjsName = "split-objs" buildMonoidSkipComponentsName :: Text buildMonoidSkipComponentsName = "skip-components" buildMonoidInterleavedOutputName :: Text buildMonoidInterleavedOutputName = "interleaved-output" buildMonoidDdumpDirName :: Text buildMonoidDdumpDirName = "ddump-dir" instance Semigroup BuildOptsMonoid where (<>) = mappenddefault instance Monoid BuildOptsMonoid where mempty = memptydefault mappend = (<>) -- | Which subset of packages to build data BuildSubset = BSAll | BSOnlySnapshot -- ^ Only install packages in the snapshot database, skipping -- packages intended for the local database. | BSOnlyDependencies | BSOnlyLocals -- ^ Refuse to build anything in the snapshot database, see -- https://github.com/commercialhaskell/stack/issues/5272 deriving (Show, Eq) -- | Options for the 'FinalAction' 'DoTests' data TestOpts = TestOpts {toRerunTests :: !Bool -- ^ Whether successful tests will be run gain ,toAdditionalArgs :: ![String] -- ^ Arguments passed to the test program ,toCoverage :: !Bool -- ^ Generate a code coverage report ,toDisableRun :: !Bool -- ^ Disable running of tests ,toMaximumTimeSeconds :: !(Maybe Int) -- ^ test suite timeout in seconds ,toAllowStdin :: !Bool -- ^ Whether to allow standard input } deriving (Eq,Show) defaultTestOpts :: TestOpts defaultTestOpts = TestOpts { toRerunTests = defaultFirstTrue toMonoidRerunTests , toAdditionalArgs = [] , toCoverage = defaultFirstFalse toMonoidCoverage , toDisableRun = defaultFirstFalse toMonoidDisableRun , toMaximumTimeSeconds = Nothing , toAllowStdin = defaultFirstTrue toMonoidAllowStdin } data TestOptsMonoid = TestOptsMonoid { toMonoidRerunTests :: !FirstTrue , toMonoidAdditionalArgs :: ![String] , toMonoidCoverage :: !FirstFalse , toMonoidDisableRun :: !FirstFalse , toMonoidMaximumTimeSeconds :: !(First (Maybe Int)) , toMonoidAllowStdin :: !FirstTrue } deriving (Show, Generic) instance FromJSON (WithJSONWarnings TestOptsMonoid) where parseJSON = withObjectWarnings "TestOptsMonoid" (\o -> do toMonoidRerunTests <- FirstTrue <$> o ..:? toMonoidRerunTestsArgName toMonoidAdditionalArgs <- o ..:? toMonoidAdditionalArgsName ..!= [] toMonoidCoverage <- FirstFalse <$> o ..:? toMonoidCoverageArgName toMonoidDisableRun <- FirstFalse <$> o ..:? toMonoidDisableRunArgName toMonoidMaximumTimeSeconds <- First <$> o ..:? toMonoidMaximumTimeSecondsArgName toMonoidAllowStdin <- FirstTrue <$> o ..:? toMonoidTestsAllowStdinName pure TestOptsMonoid{..}) toMonoidRerunTestsArgName :: Text toMonoidRerunTestsArgName = "rerun-tests" toMonoidAdditionalArgsName :: Text toMonoidAdditionalArgsName = "additional-args" toMonoidCoverageArgName :: Text toMonoidCoverageArgName = "coverage" toMonoidDisableRunArgName :: Text toMonoidDisableRunArgName = "no-run-tests" toMonoidMaximumTimeSecondsArgName :: Text toMonoidMaximumTimeSecondsArgName = "test-suite-timeout" toMonoidTestsAllowStdinName :: Text toMonoidTestsAllowStdinName = "tests-allow-stdin" instance Semigroup TestOptsMonoid where (<>) = mappenddefault instance Monoid TestOptsMonoid where mempty = memptydefault mappend = (<>) -- | Haddock Options newtype HaddockOpts = HaddockOpts { hoAdditionalArgs :: [String] -- ^ Arguments passed to haddock program } deriving (Eq,Show) newtype HaddockOptsMonoid = HaddockOptsMonoid {hoMonoidAdditionalArgs :: [String] } deriving (Show, Generic) defaultHaddockOpts :: HaddockOpts defaultHaddockOpts = HaddockOpts {hoAdditionalArgs = []} instance FromJSON (WithJSONWarnings HaddockOptsMonoid) where parseJSON = withObjectWarnings "HaddockOptsMonoid" (\o -> do hoMonoidAdditionalArgs <- o ..:? hoMonoidAdditionalArgsName ..!= [] pure HaddockOptsMonoid{..}) instance Semigroup HaddockOptsMonoid where (<>) = mappenddefault instance Monoid HaddockOptsMonoid where mempty = memptydefault mappend = (<>) hoMonoidAdditionalArgsName :: Text hoMonoidAdditionalArgsName = "haddock-args" -- | Options for the 'FinalAction' 'DoBenchmarks' data BenchmarkOpts = BenchmarkOpts { beoAdditionalArgs :: !(Maybe String) -- ^ Arguments passed to the benchmark program , beoDisableRun :: !Bool -- ^ Disable running of benchmarks } deriving (Eq,Show) defaultBenchmarkOpts :: BenchmarkOpts defaultBenchmarkOpts = BenchmarkOpts { beoAdditionalArgs = Nothing , beoDisableRun = False } data BenchmarkOptsMonoid = BenchmarkOptsMonoid { beoMonoidAdditionalArgs :: !(First String) , beoMonoidDisableRun :: !(First Bool) } deriving (Show, Generic) instance FromJSON (WithJSONWarnings BenchmarkOptsMonoid) where parseJSON = withObjectWarnings "BenchmarkOptsMonoid" (\o -> do beoMonoidAdditionalArgs <- First <$> o ..:? beoMonoidAdditionalArgsArgName beoMonoidDisableRun <- First <$> o ..:? beoMonoidDisableRunArgName pure BenchmarkOptsMonoid{..}) beoMonoidAdditionalArgsArgName :: Text beoMonoidAdditionalArgsArgName = "benchmark-arguments" beoMonoidDisableRunArgName :: Text beoMonoidDisableRunArgName = "no-run-benchmarks" instance Semigroup BenchmarkOptsMonoid where (<>) = mappenddefault instance Monoid BenchmarkOptsMonoid where mempty = memptydefault mappend = (<>) data FileWatchOpts = NoFileWatch | FileWatch | FileWatchPoll deriving (Show,Eq) newtype CabalVerbosity = CabalVerbosity Verbosity deriving (Eq, Show) toFirstCabalVerbosity :: FirstFalse -> First CabalVerbosity toFirstCabalVerbosity vf = First $ getFirstFalse vf <&> \p -> if p then verboseLevel else normalLevel where verboseLevel = CabalVerbosity verbose normalLevel = CabalVerbosity normal instance FromJSON CabalVerbosity where parseJSON = withText "CabalVerbosity" $ \t -> let s = T.unpack t errMsg = fail $ "Unrecognised Cabal verbosity: " ++ s in maybe errMsg pure (simpleParsec s) instance Parsec CabalVerbosity where parsec = CabalVerbosity <$> parsec