Skip to content

Commit 2fc553b

Browse files
committed
Fix #1369 Add build option --cabal-verbosity=VERBOSITY
Retains the existing `--[no-]cabal-verbose`, as an alternative flag on the command line. As with the existing flag, the new option can be set in configuration files. The new option has priority in configuration files. Error messages are provided if the specified verbosity is not recognised by Cabal (the library). The `ChangeLog.md` and documentation are updated accordingly. Unit tests are updated accordingly. Tested by building Stack and using it with various combinations of options at the command line and/or in a `stack.yaml` file.
1 parent c99a821 commit 2fc553b

File tree

7 files changed

+134
-14
lines changed

7 files changed

+134
-14
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Other enhancements:
3232
* Fuller help is provided at the command line if a subcommand is missing (for
3333
example, `stack ls` now yields the equivalent of `stack ls --help`). See
3434
[#809](https://github.com/commercialhaskell/stack/issues/809)
35+
* Add build option `--cabal-verbosity=VERBOSITY` to specify the Cabal verbosity
36+
level (the option accepts Cabal's numerical and extended syntax).
37+
See [#1369](https://github.com/commercialhaskell/stack/issues/809)
3538

3639
Bug fixes:
3740

doc/yaml_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ build:
864864
no-run-benchmarks: false
865865
force-dirty: false
866866
reconfigure: false
867+
cabal-verbosity: normal
867868
cabal-verbose: false
868869
split-objs: false
869870

src/Stack/Build/Execute.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import Distribution.System (OS (Windows),
6060
import qualified Distribution.Text as C
6161
import Distribution.Types.PackageName (mkPackageName)
6262
import Distribution.Types.UnqualComponentName (mkUnqualComponentName)
63+
import Distribution.Verbosity (showForCabal)
6364
import Distribution.Version (mkVersion)
6465
import Path
6566
import Path.CheckInstall
@@ -1355,7 +1356,10 @@ withSingleContext ActionContext {..} ee@ExecuteEnv {..} task@Task {..} allDeps m
13551356
liftIO $ atomicModifyIORef' eeCustomBuilt $
13561357
\oldCustomBuilt -> (Set.insert (packageName package) oldCustomBuilt, ())
13571358
return outputFile
1358-
runExe exeName $ (if boptsCabalVerbose eeBuildOpts then ("--verbose":) else id) setupArgs
1359+
let cabalVerboseArg =
1360+
let CabalVerbosity cv = boptsCabalVerbose eeBuildOpts
1361+
in "--verbose=" <> showForCabal cv
1362+
runExe exeName $ cabalVerboseArg:setupArgs
13591363

13601364
-- Implements running a package's build, used to implement 'ATBuild' and
13611365
-- 'ATBuildFinal' tasks. In particular this does the following:

src/Stack/Config/Build.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Stack.Config.Build where
66

77
import Stack.Prelude
88
import Stack.Types.Config
9+
import Distribution.Verbosity (normal)
910

1011
-- | Interprets BuildOptsMonoid options.
1112
buildOptsFromMonoid :: BuildOptsMonoid -> BuildOpts
@@ -41,7 +42,7 @@ buildOptsFromMonoid BuildOptsMonoid{..} = BuildOpts
4142
, boptsBenchmarkOpts =
4243
benchmarkOptsFromMonoid buildMonoidBenchmarkOpts additionalArgs
4344
, boptsReconfigure = fromFirstFalse buildMonoidReconfigure
44-
, boptsCabalVerbose = fromFirstFalse buildMonoidCabalVerbose
45+
, boptsCabalVerbose = fromFirst (CabalVerbosity normal) buildMonoidCabalVerbose
4546
, boptsSplitObjs = fromFirstFalse buildMonoidSplitObjs
4647
, boptsSkipComponents = buildMonoidSkipComponents
4748
, boptsInterleavedOutput = fromFirstTrue buildMonoidInterleavedOutput

src/Stack/Options/BuildMonoidParser.hs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
module Stack.Options.BuildMonoidParser where
44

55
import qualified Data.Text as T
6+
import Distribution.Parsec (eitherParsec)
67
import Options.Applicative
78
import Options.Applicative.Builder.Extra
8-
import Stack.Build (splitObjsWarning)
9+
import Stack.Build (splitObjsWarning)
910
import Stack.Prelude
1011
import Stack.Options.BenchParser
1112
import Stack.Options.TestParser
@@ -155,11 +156,7 @@ buildOptsMonoidParser hide0 =
155156
"reconfigure"
156157
"Perform the configure step even if unnecessary. Useful in some corner cases with custom Setup.hs files"
157158
hide
158-
cabalVerbose =
159-
firstBoolFlagsFalse
160-
"cabal-verbose"
161-
"Ask Cabal to be verbose in its output"
162-
hide
159+
cabalVerbose = cabalVerbosityOptsParser hideBool
163160
splitObjs =
164161
firstBoolFlagsFalse
165162
"split-objs"
@@ -183,3 +180,27 @@ buildOptsMonoidParser hide0 =
183180
(long "ddump-dir" <>
184181
help "Specify output ddump-files" <>
185182
hide))
183+
184+
-- | Parser for Cabal verbosity options
185+
cabalVerbosityOptsParser :: Bool -> Parser (First CabalVerbosity)
186+
cabalVerbosityOptsParser hide =
187+
cabalVerbosityParser hide <|> cabalVerboseParser hide
188+
189+
-- | Parser for Cabal verbosity option
190+
cabalVerbosityParser :: Bool -> Parser (First CabalVerbosity)
191+
cabalVerbosityParser hide =
192+
let pCabalVerbosity = option (eitherReader eitherParsec)
193+
( long "cabal-verbosity"
194+
<> metavar "VERBOSITY"
195+
<> help "Cabal verbosity (accepts Cabal's numerical and extended syntax)"
196+
<> hideMods hide)
197+
in First . Just <$> pCabalVerbosity
198+
199+
-- | Parser for the Cabal verbose flag, retained for backward compatibility
200+
cabalVerboseParser :: Bool -> Parser (First CabalVerbosity)
201+
cabalVerboseParser hide =
202+
let pVerboseFlag = firstBoolFlagsFalse
203+
"cabal-verbose"
204+
"Ask Cabal to be verbose in its output"
205+
(hideMods hide)
206+
in toFirstCabalVerbosity <$> pVerboseFlag

src/Stack/Types/Config/Build.hs

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE NoImplicitPrelude #-}
2+
{-# LANGUAGE CPP #-}
23
{-# LANGUAGE DeriveGeneric #-}
34
{-# LANGUAGE FlexibleInstances #-}
45
{-# LANGUAGE OverloadedStrings #-}
@@ -27,12 +28,27 @@ module Stack.Types.Config.Build
2728
, BuildSubset(..)
2829
, ApplyCLIFlag (..)
2930
, boptsCLIFlagsByName
31+
, CabalVerbosity (..)
32+
, toFirstCabalVerbosity
3033
)
3134
where
3235

33-
import Pantry.Internal.AesonExtended
3436
import qualified Data.Map.Strict as Map
37+
import qualified Data.Text as T
38+
#if MIN_VERSION_Cabal(3,4,0)
39+
import Distribution.Parsec (Parsec (..), simpleParsec)
40+
import Distribution.Verbosity (Verbosity, normal, verbose)
41+
#else
42+
import qualified Distribution.Compat.CharParsing as P
43+
import Distribution.Parsec (CabalParsing(..), Parsec (..)
44+
, simpleParsec)
45+
import Distribution.Utils.Generic (isAsciiAlpha)
46+
import Distribution.Verbosity (Verbosity, deafening, intToVerbosity
47+
, normal, silent, verbose, verboseCallSite, verboseCallStack
48+
, verboseMarkOutput, verboseNoWrap, verboseTimestamp)
49+
#endif
3550
import Generics.Deriving.Monoid (memptydefault, mappenddefault)
51+
import Pantry.Internal.AesonExtended
3652
import Stack.Prelude
3753

3854
-- | Build options that is interpreted by the build command.
@@ -82,7 +98,7 @@ data BuildOpts =
8298
-- ^ Only perform the configure step when building
8399
,boptsReconfigure :: !Bool
84100
-- ^ Perform the configure step even if already configured
85-
,boptsCabalVerbose :: !Bool
101+
,boptsCabalVerbose :: !CabalVerbosity
86102
-- ^ Ask Cabal to be verbose in its builds
87103
,boptsSplitObjs :: !Bool
88104
-- ^ Whether to enable split-objs.
@@ -118,7 +134,7 @@ defaultBuildOpts = BuildOpts
118134
, boptsBenchmarks = defaultFirstFalse buildMonoidBenchmarks
119135
, boptsBenchmarkOpts = defaultBenchmarkOpts
120136
, boptsReconfigure = defaultFirstFalse buildMonoidReconfigure
121-
, boptsCabalVerbose = defaultFirstFalse buildMonoidCabalVerbose
137+
, boptsCabalVerbose = CabalVerbosity normal
122138
, boptsSplitObjs = defaultFirstFalse buildMonoidSplitObjs
123139
, boptsSkipComponents = []
124140
, boptsInterleavedOutput = defaultFirstTrue buildMonoidInterleavedOutput
@@ -209,7 +225,7 @@ data BuildOptsMonoid = BuildOptsMonoid
209225
, buildMonoidBenchmarks :: !FirstFalse
210226
, buildMonoidBenchmarkOpts :: !BenchmarkOptsMonoid
211227
, buildMonoidReconfigure :: !FirstFalse
212-
, buildMonoidCabalVerbose :: !FirstFalse
228+
, buildMonoidCabalVerbose :: !(First CabalVerbosity)
213229
, buildMonoidSplitObjs :: !FirstFalse
214230
, buildMonoidSkipComponents :: ![Text]
215231
, buildMonoidInterleavedOutput :: !FirstTrue
@@ -242,7 +258,9 @@ instance FromJSON (WithJSONWarnings BuildOptsMonoid) where
242258
buildMonoidBenchmarks <- FirstFalse <$> o ..:? buildMonoidBenchmarksArgName
243259
buildMonoidBenchmarkOpts <- jsonSubWarnings (o ..:? buildMonoidBenchmarkOptsArgName ..!= mempty)
244260
buildMonoidReconfigure <- FirstFalse <$> o ..:? buildMonoidReconfigureArgName
245-
buildMonoidCabalVerbose <- FirstFalse <$> o ..:? buildMonoidCabalVerboseArgName
261+
cabalVerbosity <- First <$> o ..:? buildMonoidCabalVerbosityArgName
262+
cabalVerbose <- FirstFalse <$> o ..:? buildMonoidCabalVerboseArgName
263+
let buildMonoidCabalVerbose = cabalVerbosity <> toFirstCabalVerbosity cabalVerbose
246264
buildMonoidSplitObjs <- FirstFalse <$> o ..:? buildMonoidSplitObjsName
247265
buildMonoidSkipComponents <- o ..:? buildMonoidSkipComponentsName ..!= mempty
248266
buildMonoidInterleavedOutput <- FirstTrue <$> o ..:? buildMonoidInterleavedOutputName
@@ -312,6 +330,9 @@ buildMonoidBenchmarkOptsArgName = "benchmark-opts"
312330
buildMonoidReconfigureArgName :: Text
313331
buildMonoidReconfigureArgName = "reconfigure"
314332

333+
buildMonoidCabalVerbosityArgName :: Text
334+
buildMonoidCabalVerbosityArgName = "cabal-verbosity"
335+
315336
buildMonoidCabalVerboseArgName :: Text
316337
buildMonoidCabalVerboseArgName = "cabal-verbose"
317338

@@ -477,3 +498,71 @@ data FileWatchOpts
477498
| FileWatch
478499
| FileWatchPoll
479500
deriving (Show,Eq)
501+
502+
newtype CabalVerbosity = CabalVerbosity Verbosity
503+
deriving (Eq, Show)
504+
505+
toFirstCabalVerbosity :: FirstFalse -> First CabalVerbosity
506+
toFirstCabalVerbosity vf = First $ getFirstFalse vf <&> \p ->
507+
if p then verboseLevel else normalLevel
508+
where
509+
verboseLevel = CabalVerbosity verbose
510+
normalLevel = CabalVerbosity normal
511+
512+
instance FromJSON CabalVerbosity where
513+
514+
parseJSON = withText "CabalVerbosity" $ \t ->
515+
let s = T.unpack t
516+
errMsg = fail $ "Unrecognised Cabal verbosity: " ++ s
517+
in maybe errMsg pure (simpleParsec s)
518+
519+
instance Parsec CabalVerbosity where
520+
521+
-- The Cabal package does not provide a Verbosity instance of Parsec before
522+
-- Cabal-3.4.0.0. The code below is adapted from the instance provided in
523+
-- Cabal-3.4.0.0.
524+
#if MIN_VERSION_Cabal(3,4,0)
525+
526+
parsec = CabalVerbosity <$> parsec
527+
528+
#else
529+
530+
parsec = CabalVerbosity <$> parsecVerbosity
531+
532+
parsecVerbosity :: CabalParsing m => m Verbosity
533+
parsecVerbosity = parseIntVerbosity <|> parseStringVerbosity
534+
where
535+
parseIntVerbosity = do
536+
i <- P.integral
537+
case intToVerbosity i of
538+
Just v -> return v
539+
Nothing -> P.unexpected $ "Bad integral verbosity: " ++ show i ++
540+
". Valid values are 0..3"
541+
542+
parseStringVerbosity = do
543+
level <- parseVerbosityLevel
544+
_ <- P.spaces
545+
flags <- many (parseFlag <* P.spaces)
546+
return $ foldl' (flip ($)) level flags
547+
548+
parseVerbosityLevel = do
549+
token <- P.munch1 isAsciiAlpha
550+
case token of
551+
"silent" -> return silent
552+
"normal" -> return normal
553+
"verbose" -> return verbose
554+
"debug" -> return deafening
555+
"deafening" -> return deafening
556+
_ -> P.unexpected $ "Bad verbosity level: " ++ token
557+
558+
parseFlag = do
559+
_ <- P.char '+'
560+
token <- P.munch1 isAsciiAlpha
561+
case token of
562+
"callsite" -> return verboseCallSite
563+
"callstack" -> return verboseCallStack
564+
"nowrap" -> return verboseNoWrap
565+
"markoutput" -> return verboseMarkOutput
566+
"timestamp" -> return verboseTimestamp
567+
_ -> P.unexpected $ "Bad verbosity flag: " ++ token
568+
#endif

src/test/Stack/ConfigSpec.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
module Stack.ConfigSpec where
77

88
import Control.Arrow
9+
import Distribution.Verbosity (verbose)
910
import Pantry.Internal.AesonExtended
1011
import Data.Yaml
1112
import Pantry.Internal (pcHpackExecutable)
@@ -182,7 +183,7 @@ spec = beforeAll setup $ do
182183
boptsBenchmarkOpts `shouldBe` BenchmarkOpts {beoAdditionalArgs = Just "-O2"
183184
,beoDisableRun = True}
184185
boptsReconfigure `shouldBe` True
185-
boptsCabalVerbose `shouldBe` True
186+
boptsCabalVerbose `shouldBe` CabalVerbosity verbose
186187

187188
it "finds the config file in a parent directory" $ inTempDir $ do
188189
writeFile "package.yaml" "name: foo"

0 commit comments

Comments
 (0)