Skip to content

Commit 3109782

Browse files
authored
Merge pull request #80 from 9999years/make-exit-code-exception-constructable
Add `ExitCodeException` smart constructors
2 parents de19b4e + c4505b1 commit 3109782

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

src/System/Process/Typed.hs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ module System.Process.Typed
119119

120120
-- * Exceptions
121121
, ExitCodeException (..)
122+
, exitCodeExceptionWithOutput
123+
, exitCodeExceptionNoOutput
122124
, ByteStringOutputException (..)
123125

124126
-- * Re-exports
@@ -638,12 +640,7 @@ checkExitCodeSTM p = do
638640
ec <- readTMVar (pExitCode p)
639641
case ec of
640642
ExitSuccess -> return ()
641-
_ -> throwSTM ExitCodeException
642-
{ eceExitCode = ec
643-
, eceProcessConfig = clearStreams (pConfig p)
644-
, eceStdout = L.empty
645-
, eceStderr = L.empty
646-
}
643+
_ -> throwSTM $ exitCodeExceptionNoOutput p ec
647644

648645
-- | Returns the PID (process ID) of a subprocess.
649646
--
@@ -682,6 +679,18 @@ getStdout = pStdout
682679
getStderr :: Process stdin stdout stderr -> stderr
683680
getStderr = pStderr
684681

682+
-- | Get a process's configuration.
683+
--
684+
-- This is useful for constructing 'ExitCodeException's.
685+
--
686+
-- Note that the stdin, stdout, and stderr streams are stored in the 'Process',
687+
-- not the 'ProcessConfig', so the returned 'ProcessConfig' will always have
688+
-- empty stdin, stdout, and stderr values.
689+
--
690+
-- @since 0.2.12.0
691+
getProcessConfig :: Process stdin stdout stderr -> ProcessConfig () () ()
692+
getProcessConfig = pConfig
693+
685694
-- | Take 'System.Process.ProcessHandle' out of the 'Process'.
686695
-- This method is needed in cases one need to use low level functions
687696
-- from the @process@ package. Use cases for this method are:
@@ -703,3 +712,45 @@ getStderr = pStderr
703712
-- @since 0.1.1
704713
unsafeProcessHandle :: Process stdin stdout stderr -> P.ProcessHandle
705714
unsafeProcessHandle = pHandle
715+
716+
-- | Get an 'ExitCodeException' containing the process's stdout and stderr data.
717+
--
718+
-- Note that this will call 'waitExitCode' to block until the process exits, if
719+
-- it has not exited already.
720+
--
721+
-- Unlike 'checkExitCode' and similar, this will return an 'ExitCodeException'
722+
-- even if the process exits with 'ExitSuccess'.
723+
--
724+
-- @since 0.2.12.0
725+
exitCodeExceptionWithOutput :: MonadIO m
726+
=> Process stdin (STM L.ByteString) (STM L.ByteString)
727+
-> m ExitCodeException
728+
exitCodeExceptionWithOutput process = liftIO $ atomically $ do
729+
exitCode <- waitExitCodeSTM process
730+
stdout <- getStdout process
731+
stderr <- getStderr process
732+
pure ExitCodeException
733+
{ eceExitCode = exitCode
734+
, eceProcessConfig = pConfig process
735+
, eceStdout = stdout
736+
, eceStderr = stderr
737+
}
738+
739+
-- | Get an 'ExitCodeException' containing no data other than the exit code and
740+
-- process config.
741+
--
742+
-- Unlike 'checkExitCode' and similar, this will return an 'ExitCodeException'
743+
-- even if the process exits with 'ExitSuccess'.
744+
--
745+
-- @since 0.2.12.0
746+
exitCodeExceptionNoOutput :: Process stdin stdout stderr
747+
-> ExitCode
748+
-> ExitCodeException
749+
exitCodeExceptionNoOutput process exitCode =
750+
ExitCodeException
751+
{ eceExitCode = exitCode
752+
, eceProcessConfig = pConfig process
753+
, eceStdout = L.empty
754+
, eceStderr = L.empty
755+
}
756+

src/System/Process/Typed/Internal.hs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -590,13 +590,17 @@ useHandleOpen h = mkStreamSpec (P.UseHandle h) $ \_ _ -> return ((), return ())
590590
useHandleClose :: Handle -> StreamSpec anyStreamType ()
591591
useHandleClose h = mkStreamSpec (P.UseHandle h) $ \_ _ -> return ((), hClose h)
592592

593-
-- | Exception thrown by 'checkExitCode' in the event of a non-success
594-
-- exit code. Note that 'checkExitCode' is called by other functions
595-
-- as well, like 'runProcess_' or 'readProcess_'.
593+
-- | Exception thrown by 'System.Process.Typed.checkExitCode' in the event of a
594+
-- non-success exit code. Note that 'System.Process.Typed.checkExitCode' is
595+
-- called by other functions as well, like 'System.Process.Typed.runProcess_'
596+
-- or 'System.Process.Typed.readProcess_'.
596597
--
597598
-- Note that several functions that throw an 'ExitCodeException' intentionally do not populate 'eceStdout' or 'eceStderr'.
598599
-- This prevents unbounded memory usage for large stdout and stderrs.
599600
--
601+
-- Functions which do include 'eceStdout' or 'eceStderr' (like
602+
-- 'System.Process.Typed.readProcess_') state so in their documentation.
603+
--
600604
-- @since 0.1.0.0
601605
data ExitCodeException = ExitCodeException
602606
{ eceExitCode :: ExitCode

0 commit comments

Comments
 (0)