pipes-cliff-0.4.0.0: Streaming to and from subprocesses using Pipes

Safe HaskellSafe-Inferred
LanguageHaskell2010

Pipes.Cliff

Contents

Description

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 Inherited or if you want to UseHandle. You then send or receive information using the returned Proxy.

Use the -threaded GHC option when compiling your programs or when using GHCi. Internally, this module uses waitForProcess from the System.Process module; it's also quite likely that you will use this function when you write code using this library. As the documentation for waitForProcess states, you must use the -threaded option to prevent every thread in the system from suspending when you use waitForProcess. So, if your program experiences deadlocks, be sure you used the -threaded option.

This module relies on the Pipes, Pipes.Safe, and System.Process modules. You will want to have basic familiarity with what all of those modules do before using this module. It uses Control.Concurrent.Async and Pipes.Concurrent behind the scenes; you don't need to know how these work unless you're curious.

All communcation with subprocesses is done with strict ByteStrings. 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

https://github.com/massysett/pipes-cliff

There you will find references to other libraries that you might find more useful than this one.

For some simple examples, consult Pipes.Cliff.Examples.

Synopsis

Specifying a subprocess's properties

data NonPipe Source

How will the subprocess get its information for this stream?

Constructors

Inherit

Use whatever stream that the parent process has.

UseHandle Handle

Use the given handle for input or output

data CreateProcess Source

Like CreateProcess in System.Process, this gives the necessary information to create a subprocess. All but one of these fields is also present in CreateProcess, and they all have the same meaning; the only field that is different is the quiet field.

Constructors

CreateProcess 

Fields

cmdspec :: CmdSpec

Executable and arguments, or shell command

cwd :: Maybe FilePath

A new current working directory for the subprocess; if Nothing, use the calling process's working directory.

env :: Maybe [(String, String)]

The environment for the subprocess; if Nothing, use the calling process's working directory.

close_fds :: Bool

If True, close all file descriptors other than the standard descriptors. See the documentation for close_fds for details on how this works in Windows.

create_group :: Bool

If True, create a new process group.

delegate_ctlc :: Bool

See delegate_ctlc in the System.Process module for details.

quiet :: Bool

If True, does not print messages to standard error when IO exceptions arise when closing handles or terminating processes. Sometimes these errors arise due to broken pipes; this can be normal, depending on the circumstances. For example, if you are streaming a large set of values to a pager such as less and you expect that the user will often quit the pager without viewing the whole result, a broken pipe will result, which will print a warning message. That can be a nuisance. If you don't want to see these errors, set quiet to True.

procSpec Source

Arguments

:: String

The name of the program to run, such as less.

-> [String]

Command-line arguments

-> CreateProcess 

Create a CreateProcess record with default settings. The default settings are:

  • a raw command (as opposed to a shell command) is created
  • the current working directory is not changed from the parent process
  • the environment is not changed from the parent process
  • the parent's file descriptors (other than standard input, standard output, and standard error) are inherited
  • no new process group is created
  • delegate_ctlc is False
  • quiet is False

Creating processes

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 does not create a Pipe for any of the standard streams, use pipeNone. You must describe what you want done with standard input, standard output, and standard error. To create a subprocess that creates a Pipe 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.

Do NOT attempt to use any of the resources created by this function outside of the MonadSafe computation. The MonadSafe computation will destroy all resources when the MonadSafe computation is complete. This means that all these functions are exception safe: all resources--threads and processes included--are destroyed when the MonadSafe computation is complete, even if an exception is thrown. However, this does mean that you need to stay in the MonadSafe computation if you need to keep a resource around. waitForProcess can be handy for this. All functions in this section return a ProcessHandle for use with waitForProcess.

Each Proxy automatically destroys associated file handles and other behind-the-scenes resources after its computation finishes running; that's why the monad stack of each Proxy must contain a MonadSafe. For an example of how to deal with the MonadSafe class, consult Pipes.Cliff.Examples.

pipeNone Source

Arguments

:: MonadSafe m 
=> NonPipe

Standard input

-> NonPipe

Standard output

-> NonPipe

Standard error

-> CreateProcess 
-> m ProcessHandle 

Do not create any Proxy to or from the process.

pipeInput Source

Arguments

:: (MonadSafe mi, MonadSafe m) 
=> NonPipe

Standard output

-> NonPipe

Standard error

-> CreateProcess 
-> m (Consumer ByteString mi (), ProcessHandle)

A Consumer for standard input, and the ProcessHandle

Create a Consumer for standard input.

pipeOutput Source

Arguments

:: (MonadSafe mi, MonadSafe m) 
=> NonPipe

Standard input

-> NonPipe

Standard error

-> CreateProcess 
-> m (Producer ByteString mi (), ProcessHandle)

A Producer for standard output, and the ProcessHandle

Create a Producer for standard output.

pipeError Source

Arguments

:: (MonadSafe mi, MonadSafe m) 
=> NonPipe

Standard input

-> NonPipe

Standard output

-> CreateProcess 
-> m (Producer ByteString mi (), ProcessHandle)

A Producer for standard error, and the ProcessHandle

Create a Producer for standard error.

pipeInputOutput Source

Arguments

:: (MonadSafe mi, MonadSafe mo, MonadSafe m) 
=> NonPipe

Standard error

-> CreateProcess 
-> m (Consumer ByteString mi (), Producer ByteString mo (), ProcessHandle)

A Consumer for standard input, a Producer for standard output, and a ProcessHandle

Create a Consumer for standard input and a Producer for standard output.

pipeInputError Source

Arguments

:: (MonadSafe mi, MonadSafe mo, MonadSafe m) 
=> NonPipe

Standard output

-> CreateProcess 
-> m (Consumer ByteString mi (), Producer ByteString mo (), ProcessHandle)

A Consumer for standard input, a Producer for standard error, and a ProcessHandle

Create a Consumer for standard input and a Producer for standard error.

pipeOutputError Source

Arguments

:: (MonadSafe mi, MonadSafe mo, MonadSafe m) 
=> NonPipe

Standard input

-> CreateProcess 
-> m (Producer ByteString mi (), Producer ByteString mo (), ProcessHandle)

A Producer for standard output, a Producer for standard error, and a ProcessHandle

Create a Producer for standard output and a Producer for standard error.

pipeInputOutputError Source

Arguments

:: (MonadSafe mi, MonadSafe mo, MonadSafe me, MonadSafe m) 
=> CreateProcess 
-> m (Consumer ByteString mi (), Producer ByteString mo (), Producer ByteString me (), ProcessHandle)

A Consumer for standard input, a Producer for standard output, a Producer for standard error, and a ProcessHandle

Create a Consumer for standard input, a Producer for standard output, and a Producer for standard error.

Background operations

Often it is necessary to run threads in the background; in addition, all subprocesses run in the background. These functions allow you to launch threads in the background and to wait on background threads and subprocesses.

conveyor :: Effect (SafeT IO) () -> SafeT IO () Source

Runs in the background an effect, typically one that is moving data from one process to another. For examples of its usage, see Pipes.Cliff.Examples. The associated thread is killed when the SafeT computation completes.

background :: MonadSafe m => IO a -> m (Async a) Source

Runs a thread in the background. Initializes a finalizer that will cancel the thread if it is still running when the MonadSafe computation completes.

waitForProcess :: MonadIO m => ProcessHandle -> m ExitCode Source

A version of waitForProcess with an overloaded MonadIO return type.

waitForThread :: MonadIO m => Async a -> m a Source

A version of wait with an overloaded MonadIO return type. Allows you to wait for the return value of threads launched with background. If the thread throws an exception, waitForThread will throw that same exception.

Re-exports

module Pipes

module Pipes.Safe