Support GHC 9.12
[cabal.git] / Cabal / src / Distribution / Verbosity.hs
blobbab48bbed2147b8b0a0337ddbe71cd39213d09e9
1 {-# LANGUAGE DeriveDataTypeable #-}
2 {-# LANGUAGE DeriveGeneric #-}
4 -----------------------------------------------------------------------------
6 -- Verbosity for Cabal functions.
8 -- |
9 -- Module : Distribution.Verbosity
10 -- Copyright : Ian Lynagh 2007
11 -- License : BSD3
13 -- Maintainer : cabal-devel@haskell.org
14 -- Portability : portable
16 -- A 'Verbosity' type with associated utilities.
18 -- There are 4 standard verbosity levels from 'silent', 'normal',
19 -- 'verbose' up to 'deafening'. This is used for deciding what logging
20 -- messages to print.
22 -- Verbosity also is equipped with some internal settings which can be
23 -- used to control at a fine granularity the verbosity of specific
24 -- settings (e.g., so that you can trace only particular things you
25 -- are interested in.) It's important to note that the instances
26 -- for 'Verbosity' assume that this does not exist.
27 module Distribution.Verbosity
28 ( -- * Verbosity
29 Verbosity
30 , silent
31 , normal
32 , verbose
33 , deafening
34 , moreVerbose
35 , lessVerbose
36 , isVerboseQuiet
37 , intToVerbosity
38 , flagToVerbosity
39 , showForCabal
40 , showForGHC
41 , verboseNoFlags
42 , verboseHasFlags
43 , modifyVerbosity
45 -- * Call stacks
46 , verboseCallSite
47 , verboseCallStack
48 , isVerboseCallSite
49 , isVerboseCallStack
51 -- * Output markets
52 , verboseMarkOutput
53 , isVerboseMarkOutput
54 , verboseUnmarkOutput
56 -- * Line wrapping
57 , verboseNoWrap
58 , isVerboseNoWrap
60 -- * Time stamps
61 , verboseTimestamp
62 , isVerboseTimestamp
63 , verboseNoTimestamp
65 -- * Stderr
66 , verboseStderr
67 , isVerboseStderr
68 , verboseNoStderr
70 -- * No warnings
71 , verboseNoWarn
72 , isVerboseNoWarn
73 ) where
75 import Distribution.Compat.Prelude
76 import Prelude ()
78 import Distribution.ReadE
80 import Data.List (elemIndex)
81 import Distribution.Parsec
82 import Distribution.Pretty
83 import Distribution.Utils.Generic (isAsciiAlpha)
84 import Distribution.Verbosity.Internal
86 import qualified Data.Set as Set
87 import qualified Distribution.Compat.CharParsing as P
88 import qualified Text.PrettyPrint as PP
90 data Verbosity = Verbosity
91 { vLevel :: VerbosityLevel
92 , vFlags :: Set VerbosityFlag
93 , vQuiet :: Bool
95 deriving (Generic, Show, Read, Typeable)
97 mkVerbosity :: VerbosityLevel -> Verbosity
98 mkVerbosity l = Verbosity{vLevel = l, vFlags = Set.empty, vQuiet = False}
100 instance Eq Verbosity where
101 x == y = vLevel x == vLevel y
103 instance Ord Verbosity where
104 compare x y = compare (vLevel x) (vLevel y)
106 instance Enum Verbosity where
107 toEnum = mkVerbosity . toEnum
108 fromEnum = fromEnum . vLevel
110 instance Bounded Verbosity where
111 minBound = mkVerbosity minBound
112 maxBound = mkVerbosity maxBound
114 instance Binary Verbosity
115 instance Structured Verbosity
117 -- | In 'silent' mode, we should not print /anything/ unless an error occurs.
118 silent :: Verbosity
119 silent = mkVerbosity Silent
121 -- | Print stuff we want to see by default.
122 normal :: Verbosity
123 normal = mkVerbosity Normal
125 -- | Be more verbose about what's going on.
126 verbose :: Verbosity
127 verbose = mkVerbosity Verbose
129 -- | Not only are we verbose ourselves (perhaps even noisier than when
130 -- being 'verbose'), but we tell everything we run to be verbose too.
131 deafening :: Verbosity
132 deafening = mkVerbosity Deafening
134 -- | Increase verbosity level, but stay 'silent' if we are.
135 moreVerbose :: Verbosity -> Verbosity
136 moreVerbose v =
137 case vLevel v of
138 Silent -> v -- silent should stay silent
139 Normal -> v{vLevel = Verbose}
140 Verbose -> v{vLevel = Deafening}
141 Deafening -> v
143 -- | Decrease verbosity level, but stay 'deafening' if we are.
144 lessVerbose :: Verbosity -> Verbosity
145 lessVerbose v =
146 verboseQuiet $
147 case vLevel v of
148 Deafening -> v -- deafening stays deafening
149 Verbose -> v{vLevel = Normal}
150 Normal -> v{vLevel = Silent}
151 Silent -> v
153 -- | Combinator for transforming verbosity level while retaining the
154 -- original hidden state.
156 -- For instance, the following property holds
158 -- prop> isVerboseNoWrap (modifyVerbosity (max verbose) v) == isVerboseNoWrap v
160 -- __Note__: you can use @modifyVerbosity (const v1) v0@ to overwrite
161 -- @v1@'s flags with @v0@'s flags.
163 -- @since 2.0.1.0
164 modifyVerbosity :: (Verbosity -> Verbosity) -> Verbosity -> Verbosity
165 modifyVerbosity f v = v{vLevel = vLevel (f v)}
167 -- | Numeric verbosity level @0..3@: @0@ is 'silent', @3@ is 'deafening'.
168 intToVerbosity :: Int -> Maybe Verbosity
169 intToVerbosity 0 = Just (mkVerbosity Silent)
170 intToVerbosity 1 = Just (mkVerbosity Normal)
171 intToVerbosity 2 = Just (mkVerbosity Verbose)
172 intToVerbosity 3 = Just (mkVerbosity Deafening)
173 intToVerbosity _ = Nothing
175 -- | Parser verbosity
177 -- >>> explicitEitherParsec parsecVerbosity "normal"
178 -- Right (Verbosity {vLevel = Normal, vFlags = fromList [], vQuiet = False})
180 -- >>> explicitEitherParsec parsecVerbosity "normal+nowrap "
181 -- Right (Verbosity {vLevel = Normal, vFlags = fromList [VNoWrap], vQuiet = False})
183 -- >>> explicitEitherParsec parsecVerbosity "normal+nowrap +markoutput"
184 -- Right (Verbosity {vLevel = Normal, vFlags = fromList [VNoWrap,VMarkOutput], vQuiet = False})
186 -- >>> explicitEitherParsec parsecVerbosity "normal +nowrap +markoutput"
187 -- Right (Verbosity {vLevel = Normal, vFlags = fromList [VNoWrap,VMarkOutput], vQuiet = False})
189 -- >>> explicitEitherParsec parsecVerbosity "normal+nowrap+markoutput"
190 -- Right (Verbosity {vLevel = Normal, vFlags = fromList [VNoWrap,VMarkOutput], vQuiet = False})
192 -- >>> explicitEitherParsec parsecVerbosity "deafening+nowrap+stdout+stderr+callsite+callstack"
193 -- Right (Verbosity {vLevel = Deafening, vFlags = fromList [VCallStack,VCallSite,VNoWrap,VStderr], vQuiet = False})
195 -- /Note:/ this parser will eat trailing spaces.
196 instance Parsec Verbosity where
197 parsec = parsecVerbosity
199 instance Pretty Verbosity where
200 pretty = PP.text . showForCabal
202 parsecVerbosity :: CabalParsing m => m Verbosity
203 parsecVerbosity = parseIntVerbosity <|> parseStringVerbosity
204 where
205 parseIntVerbosity = do
206 i <- P.integral
207 case intToVerbosity i of
208 Just v -> return v
209 Nothing -> P.unexpected $ "Bad integral verbosity: " ++ show i ++ ". Valid values are 0..3"
211 parseStringVerbosity = do
212 level <- parseVerbosityLevel
213 _ <- P.spaces
214 flags <- many (parseFlag <* P.spaces)
215 return $ foldl' (flip ($)) (mkVerbosity level) flags
217 parseVerbosityLevel = do
218 token <- P.munch1 isAsciiAlpha
219 case token of
220 "silent" -> return Silent
221 "normal" -> return Normal
222 "verbose" -> return Verbose
223 "debug" -> return Deafening
224 "deafening" -> return Deafening
225 _ -> P.unexpected $ "Bad verbosity level: " ++ token
226 parseFlag = do
227 _ <- P.char '+'
228 token <- P.munch1 isAsciiAlpha
229 case token of
230 "callsite" -> return verboseCallSite
231 "callstack" -> return verboseCallStack
232 "nowrap" -> return verboseNoWrap
233 "markoutput" -> return verboseMarkOutput
234 "timestamp" -> return verboseTimestamp
235 "stderr" -> return verboseStderr
236 "stdout" -> return verboseNoStderr
237 "nowarn" -> return verboseNoWarn
238 _ -> P.unexpected $ "Bad verbosity flag: " ++ token
240 flagToVerbosity :: ReadE Verbosity
241 flagToVerbosity = parsecToReadE id parsecVerbosity
243 showForCabal :: Verbosity -> String
244 showForCabal v
245 | Set.null (vFlags v) =
246 maybe (error "unknown verbosity") show $
247 elemIndex v [silent, normal, verbose, deafening]
248 | otherwise =
249 unwords $
250 showLevel (vLevel v)
251 : concatMap showFlag (Set.toList (vFlags v))
252 where
253 showLevel Silent = "silent"
254 showLevel Normal = "normal"
255 showLevel Verbose = "verbose"
256 showLevel Deafening = "debug"
258 showFlag VCallSite = ["+callsite"]
259 showFlag VCallStack = ["+callstack"]
260 showFlag VNoWrap = ["+nowrap"]
261 showFlag VMarkOutput = ["+markoutput"]
262 showFlag VTimestamp = ["+timestamp"]
263 showFlag VStderr = ["+stderr"]
264 showFlag VNoWarn = ["+nowarn"]
266 showForGHC :: Verbosity -> String
267 showForGHC v =
268 maybe (error "unknown verbosity") show $
269 elemIndex v [silent, normal, __, verbose, deafening]
270 where
271 __ = silent -- this will be always ignored by elemIndex
273 -- | Turn on verbose call-site printing when we log.
274 verboseCallSite :: Verbosity -> Verbosity
275 verboseCallSite = verboseFlag VCallSite
277 -- | Turn on verbose call-stack printing when we log.
278 verboseCallStack :: Verbosity -> Verbosity
279 verboseCallStack = verboseFlag VCallStack
281 -- | Turn on @-----BEGIN CABAL OUTPUT-----@ markers for output
282 -- from Cabal (as opposed to GHC, or system dependent).
283 verboseMarkOutput :: Verbosity -> Verbosity
284 verboseMarkOutput = verboseFlag VMarkOutput
286 -- | Turn off marking; useful for suppressing nondeterministic output.
287 verboseUnmarkOutput :: Verbosity -> Verbosity
288 verboseUnmarkOutput = verboseNoFlag VMarkOutput
290 -- | Disable line-wrapping for log messages.
291 verboseNoWrap :: Verbosity -> Verbosity
292 verboseNoWrap = verboseFlag VNoWrap
294 -- | Mark the verbosity as quiet.
295 verboseQuiet :: Verbosity -> Verbosity
296 verboseQuiet v = v{vQuiet = True}
298 -- | Turn on timestamps for log messages.
299 verboseTimestamp :: Verbosity -> Verbosity
300 verboseTimestamp = verboseFlag VTimestamp
302 -- | Turn off timestamps for log messages.
303 verboseNoTimestamp :: Verbosity -> Verbosity
304 verboseNoTimestamp = verboseNoFlag VTimestamp
306 -- | Switch logging to 'stderr'.
308 -- @since 3.4.0.0
309 verboseStderr :: Verbosity -> Verbosity
310 verboseStderr = verboseFlag VStderr
312 -- | Switch logging to 'stdout'.
314 -- @since 3.4.0.0
315 verboseNoStderr :: Verbosity -> Verbosity
316 verboseNoStderr = verboseNoFlag VStderr
318 -- | Turn off warnings for log messages.
319 verboseNoWarn :: Verbosity -> Verbosity
320 verboseNoWarn = verboseFlag VNoWarn
322 -- | Helper function for flag enabling functions.
323 verboseFlag :: VerbosityFlag -> (Verbosity -> Verbosity)
324 verboseFlag flag v = v{vFlags = Set.insert flag (vFlags v)}
326 -- | Helper function for flag disabling functions.
327 verboseNoFlag :: VerbosityFlag -> (Verbosity -> Verbosity)
328 verboseNoFlag flag v = v{vFlags = Set.delete flag (vFlags v)}
330 -- | Turn off all flags.
331 verboseNoFlags :: Verbosity -> Verbosity
332 verboseNoFlags v = v{vFlags = Set.empty}
334 verboseHasFlags :: Verbosity -> Bool
335 verboseHasFlags = not . Set.null . vFlags
337 -- | Test if we should output call sites when we log.
338 isVerboseCallSite :: Verbosity -> Bool
339 isVerboseCallSite = isVerboseFlag VCallSite
341 -- | Test if we should output call stacks when we log.
342 isVerboseCallStack :: Verbosity -> Bool
343 isVerboseCallStack = isVerboseFlag VCallStack
345 -- | Test if we should output markets.
346 isVerboseMarkOutput :: Verbosity -> Bool
347 isVerboseMarkOutput = isVerboseFlag VMarkOutput
349 -- | Test if line-wrapping is disabled for log messages.
350 isVerboseNoWrap :: Verbosity -> Bool
351 isVerboseNoWrap = isVerboseFlag VNoWrap
353 -- | Test if we had called 'lessVerbose' on the verbosity.
354 isVerboseQuiet :: Verbosity -> Bool
355 isVerboseQuiet = vQuiet
357 -- | Test if we should output timestamps when we log.
358 isVerboseTimestamp :: Verbosity -> Bool
359 isVerboseTimestamp = isVerboseFlag VTimestamp
361 -- | Test if we should output to 'stderr' when we log.
363 -- @since 3.4.0.0
364 isVerboseStderr :: Verbosity -> Bool
365 isVerboseStderr = isVerboseFlag VStderr
367 -- | Test if we should output warnings when we log.
368 isVerboseNoWarn :: Verbosity -> Bool
369 isVerboseNoWarn = isVerboseFlag VNoWarn
371 -- | Helper function for flag testing functions.
372 isVerboseFlag :: VerbosityFlag -> Verbosity -> Bool
373 isVerboseFlag flag = (Set.member flag) . vFlags
375 -- $setup
376 -- >>> import Test.QuickCheck (Arbitrary (..), arbitraryBoundedEnum)
377 -- >>> instance Arbitrary VerbosityLevel where arbitrary = arbitraryBoundedEnum
378 -- >>> instance Arbitrary Verbosity where arbitrary = fmap mkVerbosity arbitrary