Skip to content

Commit ae3f4d9

Browse files
authored
Merge pull request #10573 from 9999years/validate-verbose
`cabal-validate`: Better output verbosity defaults
2 parents 1586aaa + 86c4525 commit ae3f4d9

File tree

5 files changed

+108
-99
lines changed

5 files changed

+108
-99
lines changed

.github/workflows/validate.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,6 @@ jobs:
192192
fi
193193
echo "FLAGS=$FLAGS" >> "$GITHUB_ENV"
194194
195-
- name: Validate print-config
196-
run: sh validate.sh $FLAGS -s print-config
197-
198-
- name: Validate print-tool-versions
199-
run: sh validate.sh $FLAGS -s print-tool-versions
200-
201195
- name: Validate build
202196
run: sh validate.sh $FLAGS -s build
203197

@@ -454,9 +448,6 @@ jobs:
454448
- name: Untar the cabal executable
455449
run: tar -xzf "./cabal-head/cabal-head-${{ runner.os }}-$CABAL_ARCH.tar.gz" -C cabal-head
456450

457-
- name: print-config using cabal HEAD
458-
run: sh validate.sh ${{ env.COMMON_FLAGS }} --with-cabal ./cabal-head/cabal -s print-config
459-
460451
# We dont use cache to force a build with a fresh store dir and build dir
461452
# This way we check cabal can build all its dependencies
462453
- name: Build using cabal HEAD

cabal-validate/src/Cli.hs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ module Cli
55
, HackageTests (..)
66
, Compiler (..)
77
, VersionParseException (..)
8+
, Verbosity (..)
9+
, whenVerbose
810
)
911
where
1012

@@ -53,7 +55,7 @@ import Step (Step (..), displayStep, parseStep)
5355

5456
-- | Command-line options, resolved with context from the environment.
5557
data Opts = Opts
56-
{ verbose :: Bool
58+
{ verbosity :: Verbosity
5759
-- ^ Whether to display build and test output.
5860
, jobs :: Int
5961
-- ^ How many jobs to use when running tests.
@@ -116,6 +118,17 @@ data Compiler = Compiler
116118
}
117119
deriving (Show)
118120

121+
-- | A verbosity level, for log output.
122+
data Verbosity
123+
= Quiet
124+
| Info
125+
| Verbose
126+
deriving (Show, Eq, Ord)
127+
128+
-- | Run an action only if the `verbosity` is `Verbose` or higher.
129+
whenVerbose :: Applicative f => Opts -> f () -> f ()
130+
whenVerbose opts action = when (verbosity opts >= Verbose) action
131+
119132
-- | An `Exception` thrown when parsing @--numeric-version@ output from a compiler.
120133
data VersionParseException = VersionParseException
121134
{ versionInput :: String
@@ -179,19 +192,14 @@ resolveOpts opts = do
179192
then rawSteps opts
180193
else
181194
concat
182-
[
183-
[ PrintConfig
184-
, PrintToolVersions
185-
, Build
186-
]
195+
[ [Build]
187196
, optional (rawDoctest opts) Doctest
188197
, optional (rawRunLibTests opts) LibTests
189198
, optional (rawRunLibSuite opts) LibSuite
190199
, optional (rawRunLibSuite opts && not (null (rawExtraCompilers opts))) LibSuiteExtras
191200
, optional (rawRunCliTests opts && not (rawLibOnly opts)) CliTests
192201
, optional (rawRunCliSuite opts && not (rawLibOnly opts)) CliSuite
193202
, optionals (rawSolverBenchmarks opts) [SolverBenchmarksTests, SolverBenchmarksRun]
194-
, [TimeSummary]
195203
]
196204

197205
targets' =
@@ -233,7 +241,12 @@ resolveOpts opts = do
233241
else "cabal.validate.project"
234242

235243
tastyArgs' =
236-
optional (rawTastyHideSuccesses opts) "--hide-successes"
244+
maybe
245+
-- If neither `--hide-successes` or `--no-hide-successes` was given, then
246+
-- only `--hide-successes` if `--quiet` is given.
247+
(optional (rawVerbosity opts <= Quiet) "--hide-successes")
248+
(\hideSuccesses -> optional hideSuccesses "--hide-successes")
249+
(rawTastyHideSuccesses opts)
237250
++ maybe
238251
[]
239252
(\tastyPattern -> ["--pattern", tastyPattern])
@@ -257,7 +270,7 @@ resolveOpts opts = do
257270

258271
pure
259272
Opts
260-
{ verbose = rawVerbose opts
273+
{ verbosity = rawVerbosity opts
261274
, jobs = jobs'
262275
, cwd = cwd'
263276
, startTime = startTime'
@@ -275,14 +288,14 @@ resolveOpts opts = do
275288
-- | Literate command-line options as supplied by the user, before resolving
276289
-- defaults and other values from the environment.
277290
data RawOpts = RawOpts
278-
{ rawVerbose :: Bool
291+
{ rawVerbosity :: Verbosity
279292
, rawJobs :: Maybe Int
280293
, rawCompiler :: FilePath
281294
, rawCabal :: FilePath
282295
, rawExtraCompilers :: [FilePath]
283296
, rawTastyPattern :: Maybe String
284297
, rawTastyArgs :: [String]
285-
, rawTastyHideSuccesses :: Bool
298+
, rawTastyHideSuccesses :: Maybe Bool
286299
, rawDoctest :: Bool
287300
, rawSteps :: [Step]
288301
, rawListSteps :: Bool
@@ -303,14 +316,14 @@ rawOptsParser :: Parser RawOpts
303316
rawOptsParser =
304317
RawOpts
305318
<$> ( flag'
306-
True
319+
Verbose
307320
( short 'v'
308321
<> long "verbose"
309322
<> help "Always display build and test output"
310323
)
311324
<|> flag
312-
False
313-
False
325+
Info
326+
Quiet
314327
( short 'q'
315328
<> long "quiet"
316329
<> help "Silence build and test output"
@@ -353,8 +366,7 @@ rawOptsParser =
353366
<> help "Extra arguments to pass to Tasty test suites"
354367
)
355368
)
356-
<*> boolOption
357-
True
369+
<*> maybeBoolOption
358370
"hide-successes"
359371
( help "Do not print tests that passed successfully"
360372
)
@@ -436,6 +448,12 @@ boolOption :: Bool -> String -> Mod FlagFields Bool -> Parser Bool
436448
boolOption defaultValue trueName =
437449
boolOption' defaultValue trueName ("no-" <> trueName)
438450

451+
-- | Like `boolOption`, but can tell if an option was passed or not.
452+
maybeBoolOption :: String -> Mod FlagFields (Maybe Bool) -> Parser (Maybe Bool)
453+
maybeBoolOption trueName modifiers =
454+
flag' (Just True) (modifiers <> long trueName)
455+
<|> flag Nothing (Just False) (modifiers <> hidden <> long ("no-" <> trueName))
456+
439457
-- | Full `Parser` for `RawOpts`, which includes a @--help@ argument and
440458
-- information about the program.
441459
fullRawOptsParser :: ParserInfo RawOpts

cabal-validate/src/Main.hs

Lines changed: 66 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,32 @@ import qualified Data.Text.Lazy as T (toStrict)
1414
import qualified Data.Text.Lazy.Encoding as T (decodeUtf8)
1515
import Data.Version (makeVersion, showVersion)
1616
import System.FilePath ((</>))
17+
import System.IO (BufferMode (LineBuffering), hSetBuffering, stderr, stdout)
1718
import System.Process.Typed (proc, readProcessStdout_)
1819

19-
import ANSI (SGR (Bold, BrightCyan, Reset), setSGR)
20-
import Cli (Compiler (..), HackageTests (..), Opts (..), parseOpts)
21-
import ClockUtil (diffAbsoluteTime, formatDiffTime, getAbsoluteTime)
20+
import Cli (Compiler (..), HackageTests (..), Opts (..), parseOpts, whenVerbose)
2221
import OutputUtil (printHeader, withTiming)
2322
import ProcessUtil (timed, timedWithCwd)
2423
import Step (Step (..), displayStep)
2524

2625
-- | Entry-point for @cabal-validate@.
2726
main :: IO ()
2827
main = do
28+
-- You'd _think_ that line-buffering for stdout and stderr would be the
29+
-- default behavior, and the documentation makes gestures at it, but it
30+
-- appears to not be the case!
31+
--
32+
-- > For most implementations, physical files will normally be
33+
-- > block-buffered and terminals will normally be line-buffered.
34+
--
35+
-- However, on GitHub Actions and on my machine (macOS M1), adding these
36+
-- lines makes output appear in the correct order!
37+
hSetBuffering stdout LineBuffering
38+
hSetBuffering stderr LineBuffering
39+
2940
opts <- parseOpts
41+
printConfig opts
42+
printToolVersions opts
3043
forM_ (steps opts) $ \step -> do
3144
runStep opts step
3245

@@ -36,8 +49,6 @@ runStep opts step = do
3649
let title = displayStep step
3750
printHeader title
3851
let action = case step of
39-
PrintConfig -> printConfig opts
40-
PrintToolVersions -> printToolVersions opts
4152
Build -> build opts
4253
Doctest -> doctest opts
4354
LibTests -> libTests opts
@@ -47,7 +58,6 @@ runStep opts step = do
4758
CliTests -> cliTests opts
4859
SolverBenchmarksTests -> solverBenchmarksTests opts
4960
SolverBenchmarksRun -> solverBenchmarksRun opts
50-
TimeSummary -> timeSummary opts
5161
withTiming (startTime opts) title action
5262
T.putStrLn ""
5363

@@ -106,11 +116,11 @@ cabalListBinArgs opts = "list-bin" : cabalArgs opts
106116
cabalListBin :: Opts -> String -> IO FilePath
107117
cabalListBin opts target = do
108118
let args = cabalListBinArgs opts ++ [target]
109-
stdout <-
119+
stdout' <-
110120
readProcessStdout_ $
111121
proc (cabal opts) args
112122

113-
pure (T.unpack $ T.strip $ T.toStrict $ T.decodeUtf8 stdout)
123+
pure (T.unpack $ T.strip $ T.toStrict $ T.decodeUtf8 stdout')
114124

115125
-- | Get the RTS arguments for invoking test suites.
116126
--
@@ -139,57 +149,62 @@ timedCabalBin opts package component args = do
139149

140150
-- | Print the configuration for CI logs.
141151
printConfig :: Opts -> IO ()
142-
printConfig opts = do
143-
putStr $
144-
unlines
145-
[ "compiler: "
146-
<> compilerExecutable (compiler opts)
147-
, "cabal-install: "
148-
<> cabal opts
149-
, "jobs: "
150-
<> show (jobs opts)
151-
, "steps: "
152-
<> unwords (map displayStep (steps opts))
153-
, "Hackage tests: "
154-
<> show (hackageTests opts)
155-
, "verbose: "
156-
<> show (verbose opts)
157-
, "extra compilers: "
158-
<> unwords (extraCompilers opts)
159-
, "extra RTS options: "
160-
<> unwords (rtsArgs opts)
161-
]
152+
printConfig opts =
153+
whenVerbose opts $ do
154+
printHeader "Configuration"
155+
putStr $
156+
unlines
157+
[ "compiler: "
158+
<> compilerExecutable (compiler opts)
159+
, "cabal-install: "
160+
<> cabal opts
161+
, "jobs: "
162+
<> show (jobs opts)
163+
, "steps: "
164+
<> unwords (map displayStep (steps opts))
165+
, "Hackage tests: "
166+
<> show (hackageTests opts)
167+
, "verbosity: "
168+
<> show (verbosity opts)
169+
, "extra compilers: "
170+
<> unwords (extraCompilers opts)
171+
, "extra RTS options: "
172+
<> unwords (rtsArgs opts)
173+
]
162174

163175
-- | Print the versions of tools being used.
164176
printToolVersions :: Opts -> IO ()
165-
printToolVersions opts = do
166-
timed opts (compilerExecutable (compiler opts)) ["--version"]
167-
timed opts (cabal opts) ["--version"]
177+
printToolVersions opts =
178+
whenVerbose opts $ do
179+
printHeader "Tool versions"
180+
timed opts (cabal opts) ["--version"]
181+
timed opts (compilerExecutable (compiler opts)) ["--version"]
168182

169-
forM_ (extraCompilers opts) $ \compiler' -> do
170-
timed opts compiler' ["--version"]
183+
forM_ (extraCompilers opts) $ \compiler' -> do
184+
timed opts compiler' ["--version"]
171185

172186
-- | Run the build step.
173187
build :: Opts -> IO ()
174188
build opts = do
175-
printHeader "build (dry run)"
176-
timed
177-
opts
178-
(cabal opts)
179-
( cabalNewBuildArgs opts
180-
++ targets opts
181-
++ ["--dry-run"]
182-
)
183-
184-
printHeader "build (full build plan; cached and to-be-built dependencies)"
185-
timed
186-
opts
187-
"jq"
188-
[ "-r"
189-
, -- TODO: Maybe use `cabal-plan`? It's a heavy dependency though...
190-
".\"install-plan\" | map(.\"pkg-name\" + \"-\" + .\"pkg-version\" + \" \" + .\"component-name\") | join(\"\n\")"
191-
, baseBuildDir opts </> "cache" </> "plan.json"
192-
]
189+
whenVerbose opts $ do
190+
printHeader "build (dry run)"
191+
timed
192+
opts
193+
(cabal opts)
194+
( cabalNewBuildArgs opts
195+
++ targets opts
196+
++ ["--dry-run"]
197+
)
198+
199+
printHeader "build (full build plan; cached and to-be-built dependencies)"
200+
timed
201+
opts
202+
"jq"
203+
[ "-r"
204+
, -- TODO: Maybe use `cabal-plan`? It's a heavy dependency though...
205+
".\"install-plan\" | map(.\"pkg-name\" + \"-\" + .\"pkg-version\" + \" \" + .\"component-name\") | join(\"\n\")"
206+
, baseBuildDir opts </> "cache" </> "plan.json"
207+
]
193208

194209
printHeader "build (actual build)"
195210
timed
@@ -413,14 +428,3 @@ solverBenchmarksRun opts = do
413428
, "--packages=Chart-diagrams"
414429
, "--print-trials"
415430
]
416-
417-
-- | Print the total time taken so far.
418-
timeSummary :: Opts -> IO ()
419-
timeSummary opts = do
420-
endTime <- getAbsoluteTime
421-
let totalDuration = diffAbsoluteTime endTime (startTime opts)
422-
putStrLn $
423-
setSGR [Bold, BrightCyan]
424-
<> "!!! Validation completed in "
425-
<> formatDiffTime totalDuration
426-
<> setSGR [Reset]

cabal-validate/src/ProcessUtil.hs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module ProcessUtil
55
) where
66

77
import Control.Exception (throwIO)
8-
import Control.Monad (unless)
8+
import Control.Monad (when)
99
import Data.ByteString.Lazy (ByteString)
1010
import qualified Data.ByteString.Lazy as ByteString
1111
import Data.Text (Text)
@@ -18,7 +18,7 @@ import System.Exit (ExitCode (ExitFailure, ExitSuccess))
1818
import System.Process.Typed (ExitCodeException (..), proc, readProcess, runProcess)
1919

2020
import ANSI (SGR (BrightBlue, BrightGreen, BrightRed, Reset), setSGR)
21-
import Cli (Opts (..))
21+
import Cli (Opts (..), Verbosity (..))
2222
import ClockUtil (diffAbsoluteTime, formatDiffTime, getAbsoluteTime)
2323

2424
-- | Like `timed`, but runs the command in a given directory.
@@ -62,7 +62,7 @@ timed opts command args = do
6262
<> setSGR [Reset]
6363

6464
(exitCode, rawStdout, rawStderr) <-
65-
if verbose opts
65+
if verbosity opts > Quiet
6666
then do
6767
exitCode <- runProcess process
6868
pure (exitCode, ByteString.empty, ByteString.empty)
@@ -81,7 +81,9 @@ timed opts command args = do
8181

8282
case exitCode of
8383
ExitSuccess -> do
84-
unless (verbose opts) $ do
84+
-- Output is captured when `--quiet` is used, so only print it here
85+
-- if `--quiet` _isn't_ used.
86+
when (verbosity opts > Quiet) $ do
8587
if hiddenLines <= 0
8688
then T.putStrLn output
8789
else
@@ -102,7 +104,7 @@ timed opts command args = do
102104
<> formatDiffTime totalDuration
103105
<> setSGR [Reset]
104106
ExitFailure exitCode' -> do
105-
unless (verbose opts) $ do
107+
when (verbosity opts <= Info) $ do
106108
T.putStrLn output
107109

108110
putStrLn $

0 commit comments

Comments
 (0)