Skip to content

Commit bac975e

Browse files
authored
Merge pull request #5789 from mpilgrem/fix1369
Fix #1369 Add build option `--cabal-verbosity=VERBOSITY`
2 parents 6a7bd5d + d46bf1a commit bac975e

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
@@ -31,6 +31,9 @@ Other enhancements:
3131
* Fuller help is provided at the command line if a subcommand is missing (for
3232
example, `stack ls` now yields the equivalent of `stack ls --help`). See
3333
[#809](https://github.com/commercialhaskell/stack/issues/809)
34+
* Add build option `--cabal-verbosity=VERBOSITY` to specify the Cabal verbosity
35+
level (the option accepts Cabal's numerical and extended syntax).
36+
See [#1369](https://github.com/commercialhaskell/stack/issues/809)
3437
* Add the possibility of a `sh` script to customise fully GHC installation. See
3538
[#5585](https://github.com/commercialhaskell/stack/pull/5585)
3639
* `tools` subcommand added to `stack ls`, to list stack's installed tools.

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)