typed-process 0.2.11.1 → 0.2.13.0
raw patch · 4 files changed
Files
- ChangeLog.md +15/−0
- src/System/Process/Typed.hs +72/−6
- src/System/Process/Typed/Internal.hs +16/−6
- typed-process.cabal +6/−3
ChangeLog.md view
@@ -1,5 +1,20 @@ # ChangeLog for typed-process +## 0.2.13.0++* Format stdout and stderr in `ExitCodeException` assuming they are in+ UTF-8. See [#87](https://github.com/fpco/typed-process/pull/87).+ Thanks to @9999years for the legwork on this change.++## 0.2.12.0++* Add `getPid`, `exitCodeExceptionWithOutput`,+ `exitCodeExceptionNoOutput`,++* Re-export `System.Process.Pid`++* Thanks to Rebecca Turner @9999years+ ## 0.2.11.1 * No user-visible changes
src/System/Process/Typed.hs view
@@ -109,6 +109,9 @@ , checkExitCode , checkExitCodeSTM + -- ** Process ID+ , getPid+ -- ** Process streams , getStdin , getStdout@@ -116,11 +119,14 @@ -- * Exceptions , ExitCodeException (..)+ , exitCodeExceptionWithOutput+ , exitCodeExceptionNoOutput , ByteStringOutputException (..) -- * Re-exports , ExitCode (..) , P.StdStream (..)+ , P.Pid -- * Unsafe functions , unsafeProcessHandle@@ -634,13 +640,19 @@ 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 +-- | Returns the PID (process ID) of a subprocess.+--+-- 'Nothing' is returned if the underlying 'P.ProcessHandle' was already closed.+-- Otherwise a PID is returned that remains valid as long as the handle is+-- open. The operating system may reuse the PID as soon as the last handle to+-- the process is closed.+--+-- @since 0.2.12.0+getPid :: Process stdin stdout stderr -> IO (Maybe P.Pid)+getPid = P.getPid . pHandle+ -- | Internal clearStreams :: ProcessConfig stdin stdout stderr -> ProcessConfig () () () clearStreams pc = pc@@ -667,6 +679,18 @@ 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:@@ -688,3 +712,45 @@ -- @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+ }+
src/System/Process/Typed/Internal.hs view
@@ -23,9 +23,11 @@ import Control.Concurrent.STM (newEmptyTMVarIO, atomically, putTMVar, readTMVar, STM, tryPutTMVar, throwSTM) import System.Exit (ExitCode) import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Lazy.Char8 as L8 import Data.String (IsString (fromString)) import Control.Monad.IO.Unlift+import qualified Data.Text.Encoding.Error as TEE+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TLE #if MIN_VERSION_process(1, 4, 0) && !WINDOWS import System.Posix.Types (GroupID, UserID)@@ -590,13 +592,17 @@ 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@@ -616,11 +622,15 @@ , show (eceProcessConfig ece) { pcEnv = Nothing } , if L.null (eceStdout ece) then ""- else "Standard output:\n\n" ++ L8.unpack (eceStdout ece)+ else "Standard output:\n\n" ++ unpack (eceStdout ece) , if L.null (eceStderr ece) then ""- else "Standard error:\n\n" ++ L8.unpack (eceStderr ece)+ else "Standard error:\n\n" ++ unpack (eceStderr ece) ]+ where+ -- Format with UTF-8, because we have to choose some encoding,+ -- and UTF-8 is the least likely to be wrong in general.+ unpack = TL.unpack . TLE.decodeUtf8With TEE.lenientDecode -- | Wrapper for when an exception is thrown when reading from a child -- process, used by 'byteStringOutput'.
typed-process.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.38.0. -- -- see: https://github.com/sol/hpack name: typed-process-version: 0.2.11.1+version: 0.2.13.0 synopsis: Run external processes, with strong typing of streams description: Please see the tutorial at <https://github.com/fpco/typed-process#readme> category: System@@ -38,11 +38,12 @@ , bytestring , process >=1.2 , stm+ , text , transformers , unliftio-core+ default-language: Haskell2010 if os(windows) cpp-options: -DWINDOWS- default-language: Haskell2010 test-suite typed-process-test type: exitcode-stdio-1.0@@ -64,6 +65,7 @@ , process >=1.2 , stm , temporary+ , text , transformers , typed-process , unliftio-core@@ -88,6 +90,7 @@ , process >=1.2 , stm , temporary+ , text , transformers , typed-process , unliftio-core