Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExitCodeException smart constructors #80

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 57 additions & 6 deletions src/System/Process/Typed.hs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ module System.Process.Typed

-- * Exceptions
, ExitCodeException (..)
, exitCodeExceptionWithOutput
, exitCodeExceptionNoOutput
, ByteStringOutputException (..)

-- * Re-exports
Expand Down Expand Up @@ -634,12 +636,7 @@ checkExitCodeSTM p = do
ec <- readTMVar (pExitCode p)
case ec of
ExitSuccess -> return ()
_ -> throwSTM ExitCodeException
{ eceExitCode = ec
, eceProcessConfig = clearStreams (pConfig p)
, eceStdout = L.empty
, eceStderr = L.empty
}
_ -> throwSTM $ exitCodeExceptionNoOutput p ec

-- | Internal
clearStreams :: ProcessConfig stdin stdout stderr -> ProcessConfig () () ()
Expand Down Expand Up @@ -667,6 +664,18 @@ getStdout = pStdout
getStderr :: Process stdin stdout stderr -> stderr
getStderr = pStderr

-- | Get a process's configuration.
--
-- This is useful for constructing 'ExitCodeException's.
--
-- Note that the stdin, stdout, and stderr streams are stored in the 'Process',
-- not the 'ProcessConfig', so the returned 'ProcessConfig' will always have
-- empty stdin, stdout, and stderr values.
--
-- @since 0.2.12.0
getProcessConfig :: Process stdin stdout stderr -> ProcessConfig () () ()
getProcessConfig = pConfig

-- | Take 'System.Process.ProcessHandle' out of the 'Process'.
-- This method is needed in cases one need to use low level functions
-- from the @process@ package. Use cases for this method are:
Expand All @@ -688,3 +697,45 @@ getStderr = pStderr
-- @since 0.1.1
unsafeProcessHandle :: Process stdin stdout stderr -> P.ProcessHandle
unsafeProcessHandle = pHandle

-- | Get an 'ExitCodeException' containing the process's stdout and stderr data.
--
-- Note that this will call 'waitExitCode' to block until the process exits, if
-- it has not exited already.
--
-- Unlike 'checkExitCode' and similar, this will return an 'ExitCodeException'
-- even if the process exits with 'ExitSuccess'.
--
-- @since 0.2.12.0
exitCodeExceptionWithOutput :: MonadIO m
=> Process stdin (STM L.ByteString) (STM L.ByteString)
-> m ExitCodeException
exitCodeExceptionWithOutput process = liftIO $ atomically $ do
exitCode <- waitExitCodeSTM process
stdout <- getStdout process
stderr <- getStderr process
pure ExitCodeException
{ eceExitCode = exitCode
, eceProcessConfig = pConfig process
, eceStdout = stdout
, eceStderr = stderr
}

-- | Get an 'ExitCodeException' containing no data other than the exit code and
-- process config.
--
-- Unlike 'checkExitCode' and similar, this will return an 'ExitCodeException'
-- even if the process exits with 'ExitSuccess'.
--
-- @since 0.2.12.0
exitCodeExceptionNoOutput :: Process stdin stdout stderr
-> ExitCode
-> ExitCodeException
exitCodeExceptionNoOutput process exitCode =
ExitCodeException
{ eceExitCode = exitCode
, eceProcessConfig = pConfig process
, eceStdout = L.empty
, eceStderr = L.empty
}

10 changes: 7 additions & 3 deletions src/System/Process/Typed/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -590,13 +590,17 @@ useHandleOpen h = mkStreamSpec (P.UseHandle h) $ \_ _ -> return ((), return ())
useHandleClose :: Handle -> StreamSpec anyStreamType ()
useHandleClose h = mkStreamSpec (P.UseHandle h) $ \_ _ -> return ((), hClose h)

-- | Exception thrown by 'checkExitCode' in the event of a non-success
-- exit code. Note that 'checkExitCode' is called by other functions
-- as well, like 'runProcess_' or 'readProcess_'.
-- | Exception thrown by 'System.Process.Typed.checkExitCode' in the event of a
-- non-success exit code. Note that 'System.Process.Typed.checkExitCode' is
-- called by other functions as well, like 'System.Process.Typed.runProcess_'
-- or 'System.Process.Typed.readProcess_'.
--
-- Note that several functions that throw an 'ExitCodeException' intentionally do not populate 'eceStdout' or 'eceStderr'.
-- This prevents unbounded memory usage for large stdout and stderrs.
--
-- Functions which do include 'eceStdout' or 'eceStderr' (like
-- 'System.Process.Typed.readProcess_') state so in their documentation.
--
-- @since 0.1.0.0
data ExitCodeException = ExitCodeException
{ eceExitCode :: ExitCode
Expand Down
Loading