1{-# LANGUAGE NoImplicitPrelude #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE RecordWildCards #-}
6
7-- | Configuration options for building.
8
9module Stack.Types.Config.Build
10    (
11      BuildOpts(..)
12    , BuildCommand(..)
13    , defaultBuildOpts
14    , defaultBuildOptsCLI
15    , BuildOptsCLI(..)
16    , BuildOptsMonoid(..)
17    , TestOpts(..)
18    , defaultTestOpts
19    , TestOptsMonoid(..)
20    , HaddockOpts(..)
21    , defaultHaddockOpts
22    , HaddockOptsMonoid(..)
23    , BenchmarkOpts(..)
24    , defaultBenchmarkOpts
25    , BenchmarkOptsMonoid(..)
26    , FileWatchOpts(..)
27    , BuildSubset(..)
28    , ApplyCLIFlag (..)
29    , boptsCLIFlagsByName
30    )
31    where
32
33import           Pantry.Internal.AesonExtended
34import qualified Data.Map.Strict as Map
35import           Generics.Deriving.Monoid (memptydefault, mappenddefault)
36import           Stack.Prelude
37
38-- | Build options that is interpreted by the build command.
39--   This is built up from BuildOptsCLI and BuildOptsMonoid
40data BuildOpts =
41  BuildOpts {boptsLibProfile :: !Bool
42            ,boptsExeProfile :: !Bool
43            ,boptsLibStrip :: !Bool
44            ,boptsExeStrip :: !Bool
45            ,boptsHaddock :: !Bool
46            -- ^ Build haddocks?
47            ,boptsHaddockOpts :: !HaddockOpts
48            -- ^ Options to pass to haddock
49            ,boptsOpenHaddocks :: !Bool
50            -- ^ Open haddocks in the browser?
51            ,boptsHaddockDeps :: !(Maybe Bool)
52            -- ^ Build haddocks for dependencies?
53            ,boptsHaddockInternal :: !Bool
54            -- ^ Build haddocks for all symbols and packages, like @cabal haddock --internal@
55            ,boptsHaddockHyperlinkSource  :: !Bool
56            -- ^ Build hyperlinked source if possible. Fallback to
57            -- @hscolour@. Disable for no sources.
58            ,boptsInstallExes :: !Bool
59            -- ^ Install executables to user path after building?
60            ,boptsInstallCompilerTool :: !Bool
61            -- ^ Install executables to compiler tools path after building?
62            ,boptsPreFetch :: !Bool
63            -- ^ Fetch all packages immediately
64            -- ^ Watch files for changes and automatically rebuild
65            ,boptsKeepGoing :: !(Maybe Bool)
66            -- ^ Keep building/running after failure
67            ,boptsKeepTmpFiles :: !Bool
68            -- ^ Keep intermediate files and build directories
69            ,boptsForceDirty :: !Bool
70            -- ^ Force treating all local packages as having dirty files
71
72            ,boptsTests :: !Bool
73            -- ^ Turn on tests for local targets
74            ,boptsTestOpts :: !TestOpts
75            -- ^ Additional test arguments
76
77            ,boptsBenchmarks :: !Bool
78            -- ^ Turn on benchmarks for local targets
79            ,boptsBenchmarkOpts :: !BenchmarkOpts
80            -- ^ Additional test arguments
81            -- ^ Commands (with arguments) to run after a successful build
82            -- ^ Only perform the configure step when building
83            ,boptsReconfigure :: !Bool
84            -- ^ Perform the configure step even if already configured
85            ,boptsCabalVerbose :: !Bool
86            -- ^ Ask Cabal to be verbose in its builds
87            ,boptsSplitObjs :: !Bool
88            -- ^ Whether to enable split-objs.
89            ,boptsSkipComponents :: ![Text]
90            -- ^ Which components to skip when building
91            ,boptsInterleavedOutput :: !Bool
92            -- ^ Should we use the interleaved GHC output when building
93            -- multiple packages?
94            ,boptsDdumpDir :: !(Maybe Text)
95            }
96  deriving (Show)
97
98defaultBuildOpts :: BuildOpts
99defaultBuildOpts = BuildOpts
100    { boptsLibProfile = defaultFirstFalse buildMonoidLibProfile
101    , boptsExeProfile = defaultFirstFalse buildMonoidExeProfile
102    , boptsLibStrip = defaultFirstTrue buildMonoidLibStrip
103    , boptsExeStrip = defaultFirstTrue buildMonoidExeStrip
104    , boptsHaddock = False
105    , boptsHaddockOpts = defaultHaddockOpts
106    , boptsOpenHaddocks = defaultFirstFalse buildMonoidOpenHaddocks
107    , boptsHaddockDeps = Nothing
108    , boptsHaddockInternal = defaultFirstFalse buildMonoidHaddockInternal
109    , boptsHaddockHyperlinkSource = defaultFirstTrue buildMonoidHaddockHyperlinkSource
110    , boptsInstallExes = defaultFirstFalse buildMonoidInstallExes
111    , boptsInstallCompilerTool = defaultFirstFalse buildMonoidInstallCompilerTool
112    , boptsPreFetch = defaultFirstFalse buildMonoidPreFetch
113    , boptsKeepGoing = Nothing
114    , boptsKeepTmpFiles = defaultFirstFalse buildMonoidKeepTmpFiles
115    , boptsForceDirty = defaultFirstFalse buildMonoidForceDirty
116    , boptsTests = defaultFirstFalse buildMonoidTests
117    , boptsTestOpts = defaultTestOpts
118    , boptsBenchmarks = defaultFirstFalse buildMonoidBenchmarks
119    , boptsBenchmarkOpts = defaultBenchmarkOpts
120    , boptsReconfigure = defaultFirstFalse buildMonoidReconfigure
121    , boptsCabalVerbose = defaultFirstFalse buildMonoidCabalVerbose
122    , boptsSplitObjs = defaultFirstFalse buildMonoidSplitObjs
123    , boptsSkipComponents = []
124    , boptsInterleavedOutput = defaultFirstTrue buildMonoidInterleavedOutput
125    , boptsDdumpDir = Nothing
126    }
127
128defaultBuildOptsCLI ::BuildOptsCLI
129defaultBuildOptsCLI = BuildOptsCLI
130    { boptsCLITargets = []
131    , boptsCLIDryrun = False
132    , boptsCLIFlags = Map.empty
133    , boptsCLIGhcOptions = []
134    , boptsCLIBuildSubset = BSAll
135    , boptsCLIFileWatch = NoFileWatch
136    , boptsCLIWatchAll = False
137    , boptsCLIExec = []
138    , boptsCLIOnlyConfigure = False
139    , boptsCLICommand = Build
140    , boptsCLIInitialBuildSteps = False
141    }
142
143-- | How to apply a CLI flag
144data ApplyCLIFlag
145  = ACFAllProjectPackages
146  -- ^ Apply to all project packages which have such a flag name available.
147  | ACFByName !PackageName
148  -- ^ Apply to the specified package only.
149  deriving (Show, Eq, Ord)
150
151-- | Only flags set via 'ACFByName'
152boptsCLIFlagsByName :: BuildOptsCLI -> Map PackageName (Map FlagName Bool)
153boptsCLIFlagsByName =
154  Map.fromList .
155  mapMaybe go .
156  Map.toList .
157  boptsCLIFlags
158  where
159    go (ACFAllProjectPackages, _) = Nothing
160    go (ACFByName name, flags) = Just (name, flags)
161
162-- | Build options that may only be specified from the CLI
163data BuildOptsCLI = BuildOptsCLI
164    { boptsCLITargets :: ![Text]
165    , boptsCLIDryrun :: !Bool
166    , boptsCLIGhcOptions :: ![Text]
167    , boptsCLIFlags :: !(Map ApplyCLIFlag (Map FlagName Bool))
168    , boptsCLIBuildSubset :: !BuildSubset
169    , boptsCLIFileWatch :: !FileWatchOpts
170    , boptsCLIWatchAll :: !Bool
171    , boptsCLIExec :: ![(String, [String])]
172    , boptsCLIOnlyConfigure :: !Bool
173    , boptsCLICommand :: !BuildCommand
174    , boptsCLIInitialBuildSteps :: !Bool
175    } deriving Show
176
177-- | Command sum type for conditional arguments.
178data BuildCommand
179    = Build
180    | Test
181    | Haddock
182    | Bench
183    | Install
184    deriving (Eq, Show)
185
186-- | Build options that may be specified in the stack.yaml or from the CLI
187data BuildOptsMonoid = BuildOptsMonoid
188    { buildMonoidTrace :: !Any
189    , buildMonoidProfile :: !Any
190    , buildMonoidNoStrip :: !Any
191    , buildMonoidLibProfile :: !FirstFalse
192    , buildMonoidExeProfile :: !FirstFalse
193    , buildMonoidLibStrip :: !FirstTrue
194    , buildMonoidExeStrip :: !FirstTrue
195    , buildMonoidHaddock :: !FirstFalse
196    , buildMonoidHaddockOpts :: !HaddockOptsMonoid
197    , buildMonoidOpenHaddocks :: !FirstFalse
198    , buildMonoidHaddockDeps :: !(First Bool)
199    , buildMonoidHaddockInternal :: !FirstFalse
200    , buildMonoidHaddockHyperlinkSource :: !FirstTrue
201    , buildMonoidInstallExes :: !FirstFalse
202    , buildMonoidInstallCompilerTool :: !FirstFalse
203    , buildMonoidPreFetch :: !FirstFalse
204    , buildMonoidKeepGoing :: !(First Bool)
205    , buildMonoidKeepTmpFiles :: !FirstFalse
206    , buildMonoidForceDirty :: !FirstFalse
207    , buildMonoidTests :: !FirstFalse
208    , buildMonoidTestOpts :: !TestOptsMonoid
209    , buildMonoidBenchmarks :: !FirstFalse
210    , buildMonoidBenchmarkOpts :: !BenchmarkOptsMonoid
211    , buildMonoidReconfigure :: !FirstFalse
212    , buildMonoidCabalVerbose :: !FirstFalse
213    , buildMonoidSplitObjs :: !FirstFalse
214    , buildMonoidSkipComponents :: ![Text]
215    , buildMonoidInterleavedOutput :: !FirstTrue
216    , buildMonoidDdumpDir :: !(First Text)
217    } deriving (Show, Generic)
218
219instance FromJSON (WithJSONWarnings BuildOptsMonoid) where
220  parseJSON = withObjectWarnings "BuildOptsMonoid"
221    (\o -> do let buildMonoidTrace = Any False
222                  buildMonoidProfile = Any False
223                  buildMonoidNoStrip = Any False
224              buildMonoidLibProfile <- FirstFalse <$> o ..:? buildMonoidLibProfileArgName
225              buildMonoidExeProfile <-FirstFalse <$>  o ..:? buildMonoidExeProfileArgName
226              buildMonoidLibStrip <- FirstTrue <$> o ..:? buildMonoidLibStripArgName
227              buildMonoidExeStrip <-FirstTrue <$>  o ..:? buildMonoidExeStripArgName
228              buildMonoidHaddock <- FirstFalse <$> o ..:? buildMonoidHaddockArgName
229              buildMonoidHaddockOpts <- jsonSubWarnings (o ..:? buildMonoidHaddockOptsArgName ..!= mempty)
230              buildMonoidOpenHaddocks <- FirstFalse <$> o ..:? buildMonoidOpenHaddocksArgName
231              buildMonoidHaddockDeps <- First <$> o ..:? buildMonoidHaddockDepsArgName
232              buildMonoidHaddockInternal <- FirstFalse <$> o ..:? buildMonoidHaddockInternalArgName
233              buildMonoidHaddockHyperlinkSource <- FirstTrue <$> o ..:? buildMonoidHaddockHyperlinkSourceArgName
234              buildMonoidInstallExes <- FirstFalse <$> o ..:? buildMonoidInstallExesArgName
235              buildMonoidInstallCompilerTool <- FirstFalse <$> o ..:? buildMonoidInstallCompilerToolArgName
236              buildMonoidPreFetch <- FirstFalse <$> o ..:? buildMonoidPreFetchArgName
237              buildMonoidKeepGoing <- First <$> o ..:? buildMonoidKeepGoingArgName
238              buildMonoidKeepTmpFiles <- FirstFalse <$> o ..:? buildMonoidKeepTmpFilesArgName
239              buildMonoidForceDirty <- FirstFalse <$> o ..:? buildMonoidForceDirtyArgName
240              buildMonoidTests <- FirstFalse <$> o ..:? buildMonoidTestsArgName
241              buildMonoidTestOpts <- jsonSubWarnings (o ..:? buildMonoidTestOptsArgName ..!= mempty)
242              buildMonoidBenchmarks <- FirstFalse <$> o ..:? buildMonoidBenchmarksArgName
243              buildMonoidBenchmarkOpts <- jsonSubWarnings (o ..:? buildMonoidBenchmarkOptsArgName ..!= mempty)
244              buildMonoidReconfigure <- FirstFalse <$> o ..:? buildMonoidReconfigureArgName
245              buildMonoidCabalVerbose <- FirstFalse <$> o ..:? buildMonoidCabalVerboseArgName
246              buildMonoidSplitObjs <- FirstFalse <$> o ..:? buildMonoidSplitObjsName
247              buildMonoidSkipComponents <- o ..:? buildMonoidSkipComponentsName ..!= mempty
248              buildMonoidInterleavedOutput <- FirstTrue <$> o ..:? buildMonoidInterleavedOutputName
249              buildMonoidDdumpDir <- o ..:? buildMonoidDdumpDirName ..!= mempty
250              return BuildOptsMonoid{..})
251
252buildMonoidLibProfileArgName :: Text
253buildMonoidLibProfileArgName = "library-profiling"
254
255buildMonoidExeProfileArgName :: Text
256buildMonoidExeProfileArgName = "executable-profiling"
257
258buildMonoidLibStripArgName :: Text
259buildMonoidLibStripArgName = "library-stripping"
260
261buildMonoidExeStripArgName :: Text
262buildMonoidExeStripArgName = "executable-stripping"
263
264buildMonoidHaddockArgName :: Text
265buildMonoidHaddockArgName = "haddock"
266
267buildMonoidHaddockOptsArgName :: Text
268buildMonoidHaddockOptsArgName = "haddock-arguments"
269
270buildMonoidOpenHaddocksArgName :: Text
271buildMonoidOpenHaddocksArgName = "open-haddocks"
272
273buildMonoidHaddockDepsArgName :: Text
274buildMonoidHaddockDepsArgName = "haddock-deps"
275
276buildMonoidHaddockInternalArgName :: Text
277buildMonoidHaddockInternalArgName = "haddock-internal"
278
279buildMonoidHaddockHyperlinkSourceArgName :: Text
280buildMonoidHaddockHyperlinkSourceArgName = "haddock-hyperlink-source"
281
282buildMonoidInstallExesArgName :: Text
283buildMonoidInstallExesArgName = "copy-bins"
284
285buildMonoidInstallCompilerToolArgName :: Text
286buildMonoidInstallCompilerToolArgName = "copy-compiler-tool"
287
288buildMonoidPreFetchArgName :: Text
289buildMonoidPreFetchArgName = "prefetch"
290
291buildMonoidKeepGoingArgName :: Text
292buildMonoidKeepGoingArgName = "keep-going"
293
294buildMonoidKeepTmpFilesArgName :: Text
295buildMonoidKeepTmpFilesArgName = "keep-tmp-files"
296
297buildMonoidForceDirtyArgName :: Text
298buildMonoidForceDirtyArgName = "force-dirty"
299
300buildMonoidTestsArgName :: Text
301buildMonoidTestsArgName = "test"
302
303buildMonoidTestOptsArgName :: Text
304buildMonoidTestOptsArgName = "test-arguments"
305
306buildMonoidBenchmarksArgName :: Text
307buildMonoidBenchmarksArgName = "bench"
308
309buildMonoidBenchmarkOptsArgName :: Text
310buildMonoidBenchmarkOptsArgName = "benchmark-opts"
311
312buildMonoidReconfigureArgName :: Text
313buildMonoidReconfigureArgName = "reconfigure"
314
315buildMonoidCabalVerboseArgName :: Text
316buildMonoidCabalVerboseArgName = "cabal-verbose"
317
318buildMonoidSplitObjsName :: Text
319buildMonoidSplitObjsName = "split-objs"
320
321buildMonoidSkipComponentsName :: Text
322buildMonoidSkipComponentsName = "skip-components"
323
324buildMonoidInterleavedOutputName :: Text
325buildMonoidInterleavedOutputName = "interleaved-output"
326
327buildMonoidDdumpDirName :: Text
328buildMonoidDdumpDirName = "ddump-dir"
329
330instance Semigroup BuildOptsMonoid where
331    (<>) = mappenddefault
332
333instance Monoid BuildOptsMonoid where
334    mempty = memptydefault
335    mappend = (<>)
336
337-- | Which subset of packages to build
338data BuildSubset
339    = BSAll
340    | BSOnlySnapshot
341    -- ^ Only install packages in the snapshot database, skipping
342    -- packages intended for the local database.
343    | BSOnlyDependencies
344    | BSOnlyLocals
345    -- ^ Refuse to build anything in the snapshot database, see
346    -- https://github.com/commercialhaskell/stack/issues/5272
347    deriving (Show, Eq)
348
349-- | Options for the 'FinalAction' 'DoTests'
350data TestOpts =
351  TestOpts {toRerunTests :: !Bool -- ^ Whether successful tests will be run gain
352           ,toAdditionalArgs :: ![String] -- ^ Arguments passed to the test program
353           ,toCoverage :: !Bool -- ^ Generate a code coverage report
354           ,toDisableRun :: !Bool -- ^ Disable running of tests
355           ,toMaximumTimeSeconds :: !(Maybe Int) -- ^ test suite timeout in seconds
356           } deriving (Eq,Show)
357
358defaultTestOpts :: TestOpts
359defaultTestOpts = TestOpts
360    { toRerunTests = defaultFirstTrue toMonoidRerunTests
361    , toAdditionalArgs = []
362    , toCoverage = defaultFirstFalse toMonoidCoverage
363    , toDisableRun = defaultFirstFalse toMonoidDisableRun
364    , toMaximumTimeSeconds = Nothing
365    }
366
367data TestOptsMonoid =
368  TestOptsMonoid
369    { toMonoidRerunTests :: !FirstTrue
370    , toMonoidAdditionalArgs :: ![String]
371    , toMonoidCoverage :: !FirstFalse
372    , toMonoidDisableRun :: !FirstFalse
373    , toMonoidMaximumTimeSeconds :: !(First (Maybe Int))
374    } deriving (Show, Generic)
375
376instance FromJSON (WithJSONWarnings TestOptsMonoid) where
377  parseJSON = withObjectWarnings "TestOptsMonoid"
378    (\o -> do toMonoidRerunTests <- FirstTrue <$> o ..:? toMonoidRerunTestsArgName
379              toMonoidAdditionalArgs <- o ..:? toMonoidAdditionalArgsName ..!= []
380              toMonoidCoverage <- FirstFalse <$> o ..:? toMonoidCoverageArgName
381              toMonoidDisableRun <- FirstFalse <$> o ..:? toMonoidDisableRunArgName
382              toMonoidMaximumTimeSeconds <- First <$> o ..:? toMonoidMaximumTimeSecondsArgName
383              return TestOptsMonoid{..})
384
385toMonoidRerunTestsArgName :: Text
386toMonoidRerunTestsArgName = "rerun-tests"
387
388toMonoidAdditionalArgsName :: Text
389toMonoidAdditionalArgsName = "additional-args"
390
391toMonoidCoverageArgName :: Text
392toMonoidCoverageArgName = "coverage"
393
394toMonoidDisableRunArgName :: Text
395toMonoidDisableRunArgName = "no-run-tests"
396
397toMonoidMaximumTimeSecondsArgName :: Text
398toMonoidMaximumTimeSecondsArgName = "test-suite-timeout"
399
400instance Semigroup TestOptsMonoid where
401  (<>) = mappenddefault
402
403instance Monoid TestOptsMonoid where
404  mempty = memptydefault
405  mappend = (<>)
406
407
408
409-- | Haddock Options
410newtype HaddockOpts =
411  HaddockOpts { hoAdditionalArgs :: [String] -- ^ Arguments passed to haddock program
412              } deriving (Eq,Show)
413
414newtype HaddockOptsMonoid =
415  HaddockOptsMonoid {hoMonoidAdditionalArgs :: [String]
416                    } deriving (Show, Generic)
417
418defaultHaddockOpts :: HaddockOpts
419defaultHaddockOpts = HaddockOpts {hoAdditionalArgs = []}
420
421instance FromJSON (WithJSONWarnings HaddockOptsMonoid) where
422  parseJSON = withObjectWarnings "HaddockOptsMonoid"
423    (\o -> do hoMonoidAdditionalArgs <- o ..:? hoMonoidAdditionalArgsName ..!= []
424              return HaddockOptsMonoid{..})
425
426instance Semigroup HaddockOptsMonoid where
427  (<>) = mappenddefault
428
429instance Monoid HaddockOptsMonoid where
430  mempty = memptydefault
431  mappend = (<>)
432
433hoMonoidAdditionalArgsName :: Text
434hoMonoidAdditionalArgsName = "haddock-args"
435
436
437-- | Options for the 'FinalAction' 'DoBenchmarks'
438data BenchmarkOpts =
439  BenchmarkOpts
440    { beoAdditionalArgs :: !(Maybe String) -- ^ Arguments passed to the benchmark program
441    , beoDisableRun :: !Bool -- ^ Disable running of benchmarks
442    } deriving (Eq,Show)
443
444defaultBenchmarkOpts :: BenchmarkOpts
445defaultBenchmarkOpts = BenchmarkOpts
446    { beoAdditionalArgs = Nothing
447    , beoDisableRun = False
448    }
449
450data BenchmarkOptsMonoid =
451  BenchmarkOptsMonoid
452     { beoMonoidAdditionalArgs :: !(First String)
453     , beoMonoidDisableRun :: !(First Bool)
454     } deriving (Show, Generic)
455
456instance FromJSON (WithJSONWarnings BenchmarkOptsMonoid) where
457  parseJSON = withObjectWarnings "BenchmarkOptsMonoid"
458    (\o -> do beoMonoidAdditionalArgs <- First <$> o ..:? beoMonoidAdditionalArgsArgName
459              beoMonoidDisableRun <- First <$> o ..:? beoMonoidDisableRunArgName
460              return BenchmarkOptsMonoid{..})
461
462beoMonoidAdditionalArgsArgName :: Text
463beoMonoidAdditionalArgsArgName = "benchmark-arguments"
464
465beoMonoidDisableRunArgName :: Text
466beoMonoidDisableRunArgName = "no-run-benchmarks"
467
468instance Semigroup BenchmarkOptsMonoid where
469  (<>) = mappenddefault
470
471instance Monoid BenchmarkOptsMonoid where
472  mempty = memptydefault
473  mappend = (<>)
474
475data FileWatchOpts
476  = NoFileWatch
477  | FileWatch
478  | FileWatchPoll
479  deriving (Show,Eq)
480