streaming-commons 0.1.3.1 → 0.1.4
raw patch · 3 files changed
+178/−1 lines, 3 filesdep +processdep +stm
Dependencies added: process, stm
Files
- Data/Streaming/Process.hs +137/−0
- Data/Streaming/Process/Internal.hs +36/−0
- streaming-commons.cabal +5/−1
+ Data/Streaming/Process.hs view
@@ -0,0 +1,137 @@+-- | A full tutorial for this module is available on FP School of Haskell:+-- <https://www.fpcomplete.com/user/snoyberg/library-documentation/data-streaming-process>.+--+-- Note that, while the tutorial covers @Data.Streaming.Process@, this module is+-- the basis of the streaming version, and almost all concepts there apply here.+module Data.Streaming.Process+ ( -- * Functions+ streamingProcess+ -- * Specialized streaming types+ , Inherited (..)+ , ClosedStream (..)+ , UseProvidedHandle (..)+ -- * Process handle+ , StreamingProcessHandle+ , waitForStreamingProcess+ , waitForStreamingProcessSTM+ , getStreamingProcessExitCode+ , getStreamingProcessExitCodeSTM+ , streamingProcessHandleRaw+ , streamingProcessHandleTMVar+ -- * Type classes+ , InputSource+ , OutputSink+ -- * Reexport+ , module System.Process+ ) where++import Control.Applicative ((<$>), (<*>))+import Control.Concurrent (forkIO)+import Control.Concurrent.STM (STM, TMVar, atomically,+ newEmptyTMVar, putTMVar,+ readTMVar, tryReadTMVar)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Maybe (fromMaybe)+import Data.Streaming.Process.Internal+import System.Exit (ExitCode)+import System.IO (hClose)+import System.Process++-- | Use the @Handle@ provided by the @CreateProcess@ value. This would allow+-- you, for example, to open up a @Handle@ to a file, set it as @std_out@, and+-- avoid any additional overhead of dealing with providing that data to your+-- process.+--+-- Since 0.1.4+data UseProvidedHandle = UseProvidedHandle++-- | Inherit the stream from the current process.+--+-- Since 0.1.4+data Inherited = Inherited++-- | Close the stream with the child process.+--+-- Since 0.1.4+data ClosedStream = ClosedStream++instance InputSource ClosedStream where+ isStdStream = (\(Just h) -> hClose h >> return ClosedStream, Just CreatePipe)+instance InputSource Inherited where+ isStdStream = (\Nothing -> return Inherited, Just Inherit)+instance InputSource UseProvidedHandle where+ isStdStream = (\Nothing -> return UseProvidedHandle, Nothing)++instance OutputSink ClosedStream where+ osStdStream = (\(Just h) -> hClose h >> return ClosedStream, Just CreatePipe)+instance OutputSink Inherited where+ osStdStream = (\Nothing -> return Inherited, Just Inherit)+instance OutputSink UseProvidedHandle where+ osStdStream = (\Nothing -> return UseProvidedHandle, Nothing)++-- | Blocking call to wait for a process to exit.+--+-- Since 0.1.4+waitForStreamingProcess :: MonadIO m => StreamingProcessHandle -> m ExitCode+waitForStreamingProcess = liftIO . atomically . waitForStreamingProcessSTM++-- | STM version of @waitForStreamingProcess@.+--+-- Since 0.1.4+waitForStreamingProcessSTM :: StreamingProcessHandle -> STM ExitCode+waitForStreamingProcessSTM = readTMVar . streamingProcessHandleTMVar++-- | Non-blocking call to check for a process exit code.+--+-- Since 0.1.4+getStreamingProcessExitCode :: MonadIO m => StreamingProcessHandle -> m (Maybe ExitCode)+getStreamingProcessExitCode = liftIO . atomically . getStreamingProcessExitCodeSTM++-- | STM version of @getStreamingProcessExitCode@.+--+-- Since 0.1.4+getStreamingProcessExitCodeSTM :: StreamingProcessHandle -> STM (Maybe ExitCode)+getStreamingProcessExitCodeSTM = tryReadTMVar . streamingProcessHandleTMVar++-- | Get the raw @ProcessHandle@ from a @StreamingProcessHandle@. Note that+-- you should avoid using this to get the process exit code, and instead+-- use the provided functions.+--+-- Since 0.1.4+streamingProcessHandleRaw :: StreamingProcessHandle -> ProcessHandle+streamingProcessHandleRaw (StreamingProcessHandle ph _) = ph++-- | Get the @TMVar@ storing the process exit code. In general, one of the+-- above functions should be used instead to avoid accidentally corrupting the variable\'s state..+--+-- Since 0.1.4+streamingProcessHandleTMVar :: StreamingProcessHandle -> TMVar ExitCode+streamingProcessHandleTMVar (StreamingProcessHandle _ var) = var++-- | The primary function for running a process. Note that, with the+-- exception of 'UseProvidedHandle', the values for @std_in@, @std_out@+-- and @std_err@ will be ignored by this function.+--+-- Since 0.1.4+streamingProcess :: (MonadIO m, InputSource stdin, OutputSink stdout, OutputSink stderr)+ => CreateProcess+ -> m (stdin, stdout, stderr, StreamingProcessHandle)+streamingProcess cp = liftIO $ do+ let (getStdin, stdinStream) = isStdStream+ (getStdout, stdoutStream) = osStdStream+ (getStderr, stderrStream) = osStdStream++ (stdinH, stdoutH, stderrH, ph) <- createProcess cp+ { std_in = fromMaybe (std_in cp) stdinStream+ , std_out = fromMaybe (std_out cp) stdoutStream+ , std_err = fromMaybe (std_err cp) stderrStream+ }++ ec <- atomically newEmptyTMVar+ _ <- forkIO $ waitForProcess ph >>= atomically . putTMVar ec++ (,,,)+ <$> getStdin stdinH+ <*> getStdout stdoutH+ <*> getStderr stderrH+ <*> return (StreamingProcessHandle ph ec)
+ Data/Streaming/Process/Internal.hs view
@@ -0,0 +1,36 @@+module Data.Streaming.Process.Internal+ ( StreamingProcessHandle (..)+ , InputSource (..)+ , OutputSink (..)+ ) where++import Control.Concurrent.STM (TMVar)+import System.Exit (ExitCode)+import System.IO (Handle)+import System.Process (ProcessHandle, StdStream (CreatePipe))++-- | Class for all things which can be used to provide standard input.+--+-- Since 0.1.4+class InputSource a where+ isStdStream :: (Maybe Handle -> IO a, Maybe StdStream)+instance InputSource Handle where+ isStdStream = (\(Just h) -> return h, Just CreatePipe)++-- | Class for all things which can be used to consume standard output or+-- error.+--+-- Since 0.1.4+class OutputSink a where+ osStdStream :: (Maybe Handle -> IO a, Maybe StdStream)+instance OutputSink Handle where+ osStdStream = (\(Just h) -> return h, Just CreatePipe)++-- | Wraps up the standard @ProcessHandle@ to avoid the @waitForProcess@+-- deadlock. See the linked documentation from the module header for more+-- information.+--+-- Since 0.1.4+data StreamingProcessHandle = StreamingProcessHandle+ ProcessHandle+ (TMVar ExitCode)
streaming-commons.cabal view
@@ -1,5 +1,5 @@ name: streaming-commons-version: 0.1.3.1+version: 0.1.4 synopsis: Common lower-level functions needed by various streaming data libraries description: Provides low-dependency functionality commonly needed by various streaming data libraries, such as conduit and pipes. homepage: https://github.com/fpco/streaming-commons@@ -24,6 +24,8 @@ Data.Streaming.Filesystem Data.Streaming.Network Data.Streaming.Network.Internal+ Data.Streaming.Process+ Data.Streaming.Process.Internal Data.Streaming.Text Data.Streaming.Zlib Data.Streaming.Zlib.Lowlevel@@ -43,6 +45,8 @@ , directory , network , random+ , process+ , stm , text , transformers , zlib