Suggested new function for System.Process - robustReadProcessWithExitCode

Hi, I include my proposal for a new function, for System.Process , robustReadProcessWithExitCode, below. Best wishes, Andrew Miller Motivation for change: using readProcessWithExitCode risks terminating the program due to uncaught IOException (ResourceExhausted) if the input string is not read entirely by the new process before the new process exits, because readProcessWithExitCode will attempt to write to a process that doesn't exist. Often, it is the exit code and standard input and standard error that matters to a programmer, and not whether a process read all the input. There is therefore a case for a function like readProcessWithExitCode which is robust to the new process exiting before all input is read. Suggested implementation: {- | robustReadProcessWithExitCode creates an external process, reads its standard output and standard error strictly, waits until the process terminates, and then returns the 'ExitCode' of the process, the standard output, and the standard error. 'robustReadProcessWithExitCode' is a fairly simple wrapper around 'createProcess'. Constructing variants of these functions is quite easy: follow the link to the source code to see how 'robustReadProcessWithExitCode' is implemented. 'robustReadProcessWithExitCode' differs from 'readProcessWithExitCode' because it ignores IOExceptions encountered when writing the input to the new process. This can be useful if you don't know if the process reads all your input, but you want to get the output and exit code even if it exits before reading all input. -} robustReadProcessWithExitCode :: FilePath -- ^ command to run -> [String] -- ^ any arguments -> String -- ^ standard input -> IO (ExitCode,String,String) -- ^ exitcode, stdout, stderr robustReadProcessWithExitCode cmd args input = do (Just inh, Just outh, Just errh, pid) <- createProcess (proc cmd args){ std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe } outMVar <- newEmptyMVar -- fork off a thread to start consuming stdout out <- hGetContents outh _ <- forkIO $ C.evaluate (length out) >> putMVar outMVar () -- fork off a thread to start consuming stderr err <- hGetContents errh _ <- forkIO $ C.evaluate (length err) >> putMVar outMVar () -- now write and flush any input, ignoring errors when (not (null input)) $ C.handle ((\e -> return ()) :: (C.IOException -> IO ())) $ do hPutStr inh input; hFlush inh hClose inh -- done with stdin -- wait on the output takeMVar outMVar takeMVar outMVar hClose outh -- wait on the process ex <- waitForProcess pid return (ex, out, err)

Andrew Miller
Hi,
I include my proposal for a new function, for System.Process , robustReadProcessWithExitCode, below.
+1, but I'd like to have it as a feature of current readProcessWithExitCode. If somebody needs old behavior, it can be crafted with createProcess.
Best wishes, Andrew Miller

On 17/12/2010 04:09, Andrew Miller wrote:
Hi,
I include my proposal for a new function, for System.Process , robustReadProcessWithExitCode, below.
Best wishes, Andrew Miller
Motivation for change: using readProcessWithExitCode risks terminating the program due to uncaught IOException (ResourceExhausted) if the input string is not read entirely by the new process before the new process exits, because readProcessWithExitCode will attempt to write to a process that doesn't exist.
Often, it is the exit code and standard input and standard error that matters to a programmer, and not whether a process read all the input. There is therefore a case for a function like readProcessWithExitCode which is robust to the new process exiting before all input is read.
Perhaps this should be the default behaviour of readProcessWithExitCode? Or perhaps it should return (Maybe IOException) representing any exception caught while sending input to the process? I'm not too keen on the name "robustReadProcessWithExitCode", it's not clear what "robust" refers to. Cheers, Simon
participants (3)
-
Andrew Miller
-
Gracjan Polak
-
Simon Marlow