Skip to content

Commit

Permalink
Introduce CommandIOException
Browse files Browse the repository at this point in the history
This introduces a structured exception for the result of running an
external process. By using a structured type, the build system can catch
these exceptions and control how they are displayed to the user rather
than relying on the default shake formatting.
  • Loading branch information
mpickering committed Sep 22, 2021
1 parent 90a52d9 commit 38c0570
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/Development/Shake.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module Development.Shake(
Rules, action, withoutActions, alternatives, priority, versioned,
Action, traced,
liftIO, actionOnException, actionFinally, actionBracket, actionCatch, actionRetry, runAfter,
ShakeException(..),
ShakeException(..), CommandIOException(..),
-- * Configuration
ShakeOptions(..), Rebuild(..), Lint(..), Change(..),
getShakeOptions, getShakeOptionsRules, getHashedShakeVersion,
Expand Down
36 changes: 26 additions & 10 deletions src/Development/Shake/Command.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Development.Shake.Command(
command, command_, cmd, cmd_, unit, CmdArgument(..), CmdArguments(..), IsCmdArgument(..), (:->),
Stdout(..), StdoutTrim(..), Stderr(..), Stdouterr(..), Exit(..), Process(..), CmdTime(..), CmdLine(..), FSATrace(..),
CmdResult, CmdString, CmdOption(..),
addPath, addEnv,
addPath, addEnv, CommandIOException(..)
) where

import Data.Tuple.Extra
Expand Down Expand Up @@ -417,15 +417,31 @@ commandExplicitIO params = removeOptionShell params $ \params -> removeOptionFSA
Just v -> do
v <- canonicalizePath v `catchIO` const (pure v)
pure $ "Current directory: " ++ v ++ "\n"
liftIO $ errorIO $
"Development.Shake." ++ funcName ++ ", system command failed\n" ++
"Command line: " ++ optRealCommand ++ "\n" ++
(if optRealCommand /= optUserCommand then "Original command line: " ++ optUserCommand ++ "\n" else "") ++
cwd ++
"Exit code: " ++ show (case exit of ExitFailure i -> i; _ -> 0) ++ "\n" ++
if null captured then "Stderr not captured because WithStderr False was used\n"
else if null exceptionBuffer then intercalate " and " captured ++ " " ++ (if length captured == 1 then "was" else "were") ++ " empty"
else intercalate " and " captured ++ ":\n" ++ unlines (dropWhile null $ lines $ concat exceptionBuffer)
liftIO $ throwIO $ CommandIOException funcName optRealCommand optUserCommand
cwd exit captured exceptionBuffer

data CommandIOException =
CommandIOException { commandIO_funcName :: String
, commandIO_realCommand :: String
, commandIO_userCommand :: String
, commandIO_cwd :: FilePath
, commandIO_exit :: ExitCode
, commandIO_captured :: [String]
, commandIO_exceptionBuffer :: [String]
}

instance Exception CommandIOException

instance Show CommandIOException where
show CommandIOException{..} =
"Development.Shake." ++ commandIO_funcName ++ ", system command failed\n" ++
"Command line: " ++ commandIO_realCommand ++ "\n" ++
(if commandIO_realCommand /= commandIO_userCommand then "Original command line: " ++ commandIO_userCommand ++ "\n" else "") ++
commandIO_cwd ++
"Exit code: " ++ show (case commandIO_exit of ExitFailure i -> i; _ -> 0) ++ "\n" ++
if null commandIO_captured then "Stderr not captured because WithStderr False was used\n"
else if null commandIO_exceptionBuffer then intercalate " and " commandIO_captured ++ " " ++ (if length commandIO_captured == 1 then "was" else "were") ++ " empty"
else intercalate " and " commandIO_captured ++ ":\n" ++ unlines (dropWhile null $ lines $ concat commandIO_exceptionBuffer)


mergeCwd :: [FilePath] -> Maybe FilePath
Expand Down

0 comments on commit 38c0570

Please sign in to comment.