-- | Spawn subprocesses and interact with them using "Pipes" -- -- The interface in this module deliberately resembles the interface -- in "System.Process". However, one consequence of this is that you -- will not want to have unqualified names from this module and from -- "System.Process" in scope at the same time. -- -- As in "System.Process", you create a subprocess by creating a -- 'CreateProcess' record and then applying a function to that -- record. Unlike "System.Process", you use functions such as -- 'pipeInput' or 'pipeInputOutput' to specify what streams you want -- to use a 'Proxy' for and what streams you wish to be 'Inherit'ed -- or if you want to 'UseHandle'. You then send or receive -- information using one or more 'Proxy'. -- -- __Use the @-threaded@ GHC option__ when compiling your programs or -- when using GHCi. Internally, this module uses -- 'System.Process.waitForProcess' from the "System.Process" module. -- As the documentation for 'waitForProcess' states, you must use the -- @-threaded@ option to prevent every thread in the system from -- suspending when 'waitForProcess' is used. So, if your program -- experiences deadlocks, be sure you used the @-threaded@ option. -- -- This module relies on the "Pipes", "Pipes.Safe", -- "Control.Concurrent.Async", and "System.Process" modules. You will -- want to have basic familiarity with what all of those modules do -- before using this module. -- -- All communcation with subprocesses is done with strict -- 'ByteString's. If you are dealing with textual data, the @text@ -- library has functions to convert a 'ByteString' to a @Text@; you -- will want to look at @Data.Text.Encoding@. -- -- Nobody would mistake this module for a shell; nothing beats the -- shell as a language for starting other programs, as the shell is -- designed for that. This module allows you to perform simple -- streaming with subprocesses without leaving the comfort of Haskell. -- Take a look at the README.md file, which is distributed with the -- tarball or is available at Github at -- -- -- -- There you will find references to other libraries that you might -- find more useful than this one. -- -- You will want to consult "Pipes.Cliff.Examples" for some examples -- before getting started. There are some important notes in there -- about how to run pipelines. module Pipes.Cliff ( -- * Specifying a subprocess's properties CmdSpec(..) , NonPipe(..) , CreateProcess(..) , procSpec , squelch -- * Creating processes -- $process , pipeInput , pipeOutput , pipeError , pipeInputOutput , pipeInputError , pipeOutputError , pipeInputOutputError -- * 'Proxy' combinators , conveyor , safeEffect -- * Querying and terminating the process , ProcessHandle , originalCreateProcess , isStillRunning , waitForProcess , terminateProcess -- * Exception safety -- | These are some simple combinators built with -- 'Control.Exception.bracket'; feel free to use your own favorite -- idioms for exception safety. , withProcess , withConveyor -- * Errors and warnings -- | You will only need what's in this section if you want to -- examine errors more closely. , Activity(..) , Outbound(..) , HandleDesc(..) , Oopsie(..) -- * Re-exports -- $reexports , module Control.Concurrent.Async , module Pipes , module Pipes.Safe , module System.Exit -- * Some design notes -- $designNotes ) where import Control.Concurrent.Async import Pipes.Cliff.Core import Pipes import Pipes.Safe (runSafeT) import System.Exit {- $process Each of these functions creates a process. The process begins running immediately in a separate process while your Haskell program continues concurrently. A function is provided for each possible combination of standard input, standard output, and standard error. Use the 'NonPipe' type to describe what you want to do with streams you do NOT want to create a stream for. For example, to create a subprocess that creates a 'Proxy' for standard input and standard output, use 'pipeInputOutput'. You must describe what you want done with standard error. A 'Producer' is returned for standard output and a 'Consumer' for standard input. Each function also returns a 'ProcessHandle'; this is not the same 'ProcessHandle' that you will find in "System.Process". You can use this 'ProcessHandle' to obtain some information about the process that is created and to get the eventual 'ExitCode'. Every time you create a process with one of these functions, some additional behind-the-scenes resources are created, such as some threads to move data to and from the process. In normal usage, these threads will be cleaned up after the process exits. However, if exceptions are thrown, there could be resource leaks. Applying 'terminateProcess' to a 'ProcessHandle' makes a best effort to clean up all the resources that Cliff may create, including the process itself and any additional threads. To guard against resource leaks, use the functions found in "Control.Exception" or in "Control.Monad.Catch". "Control.Monad.Catch" provides operations that are the same as those in "Control.Exception", but they are not limited to 'IO'. I say that 'terminateProcess' \"makes a best effort\" to release resources because in UNIX it merely sends a @SIGTERM@ to the process. That should kill well-behaved processes, but 'terminateProcess' does not send a @SIGKILL@. 'terminateProcess' always closes all handles associated with the process and it kills all Haskell threads that were moving data to and from the process. ('terminateProcess' does not kill threads it does not know about, such as threads you created with 'conveyor'.) There is no function that will create a process that has no 'Proxy' at all. For that, just use 'System.Process.createProcess' in "System.Process". -} {- $reexports * "Control.Concurrent.Async" reexports all bindings * "Pipes" reexports all bindings * "Pipes.Safe" reexports 'runSafeT' * "System.Exit" reexports all bindings -} {- $designNotes Two overarching principles guided the design of this library. First, I wanted the interface to use simple ByteStrings. That most closely represents what a UNIX process sees. If the user wants to use Text or String, it's easy enough to convert between those types and a ByteString. Then the user has to pay explicit attention to encoding issues--as she should, because not all UNIX processes deal with encoded textual data. Second, I paid meticulous attention to resource management. Resources are deterministically destroyed immediately after use. This eliminates many bugs. Even so, I decided to leave it up to the user to use something like 'Control.Exception.bracket' to ensure that all resources are cleaned up if there is an exception. Originally I tried to have the library do this, but that turned out not to be very composable. There are already many exception-handling mechanisms available in "Control.Exception", "Pipes.Safe", and "Control.Monad.Catch", and it seems best to let the user choose how to handle this issue; she can just perform a 'Control.Exception.bracket' and may combine this with the @ContT@ monad in @transformers@ or @mtl@ if she wishes, or perhaps with the @managed@ library. An earlier version of this library (see version 0.8.0.0) tried to use the return value of a 'Proxy' to indicate the return value of both processes in the pipeline, not just one. I removed this because it interfered heavily with composability. You might wonder why, if you are using an external process as a pipeline, why can't you create, well, a 'Pipe'? Wouldn't that be an obvious choice? Well, if such an interface is possible using Pipes in its current incarnation, nobody has figured it out yet. I don't think it's possible. See also for a discussion about this. -}