packages feed

process 1.2.2.0 → 1.2.3.0

raw patch · 7 files changed

+191/−122 lines, 7 filesdep +processdep ~basedep ~filepath

Dependencies added: process

Dependency ranges changed: base, filepath

Files

System/Process.hsc view
@@ -40,7 +40,9 @@     callCommand,     spawnProcess,     spawnCommand,+    readCreateProcess,     readProcess,+    readCreateProcessWithExitCode,     readProcessWithExitCode,      -- ** Related utilities@@ -298,7 +300,7 @@ -- /Since: 1.2.0.0/ callProcess :: FilePath -> [String] -> IO () callProcess cmd args = do-    exit_code <- withCreateProcess_ "callCommand"+    exit_code <- withCreateProcess_ "callProcess"                    (proc cmd args) { delegate_ctlc = True } $ \_ _ _ p ->                    waitForProcess p     case exit_code of@@ -413,13 +415,28 @@     -> [String]                 -- ^ any arguments     -> String                   -- ^ standard input     -> IO String                -- ^ stdout-readProcess cmd args input = do-    let cp_opts = (proc cmd args) {+readProcess cmd args = readCreateProcess $ proc cmd args++-- | @readCreateProcess@ works exactly like 'readProcess' except that it+-- lets you pass 'CreateProcess' giving better flexibility.+--+-- >  > readCreateProcess (shell "pwd" { cwd = "/etc/" }) ""+-- >  "/etc\n"+--+-- Note that @Handle@s provided for @std_in@ or @std_out@ via the CreateProcess+-- record will be ignored.+-- /Since: 1.2.3.0/++readCreateProcess+    :: CreateProcess+    -> String                   -- ^ standard input+    -> IO String                -- ^ stdout+readCreateProcess cp input = do+    let cp_opts = cp {                     std_in  = CreatePipe,-                    std_out = CreatePipe,-                    std_err = Inherit+                    std_out = CreatePipe                   }-    (ex, output) <- withCreateProcess_ "readProcess" cp_opts $+    (ex, output) <- withCreateProcess_ "readCreateProcess" cp_opts $       \(Just inh) (Just outh) _ ph -> do          -- fork off a thread to start consuming the output@@ -442,16 +459,24 @@      case ex of      ExitSuccess   -> return output-     ExitFailure r -> processFailedException "readProcess" cmd args r+     ExitFailure r -> processFailedException "readCreateProcess" cmd args r+  where+    cmd = case cp of+            CreateProcess { cmdspec = ShellCommand sc } -> sc+            CreateProcess { cmdspec = RawCommand fp _ } -> fp+    args = case cp of+             CreateProcess { cmdspec = ShellCommand _ } -> []+             CreateProcess { cmdspec = RawCommand _ args' } -> args' + -- | @readProcessWithExitCode@ is like @readProcess@ but with two differences:--- +-- --  * it returns the 'ExitCode' of the process, and does not throw any --    exception if the code is not 'ExitSuccess'. -- --  * it reads and returns the output from process' standard error handle, --    rather than the process inheriting the standard error handle.--- +-- -- On Unix systems, see 'waitForProcess' for the meaning of exit codes -- when the process died as the result of a signal. --@@ -460,13 +485,27 @@     -> [String]                 -- ^ any arguments     -> String                   -- ^ standard input     -> IO (ExitCode,String,String) -- ^ exitcode, stdout, stderr-readProcessWithExitCode cmd args input = do-    let cp_opts = (proc cmd args) {+readProcessWithExitCode cmd args =+    readCreateProcessWithExitCode $ proc cmd args++-- | @readCreateProcessWithExitCode@ works exactly like 'readProcessWithExitCode' except that it+-- lets you pass 'CreateProcess' giving better flexibility.+--+-- Note that @Handle@s provided for @std_in@, @std_out@, or @std_err@ via the CreateProcess+-- record will be ignored.+--+-- /Since: 1.2.3.0/+readCreateProcessWithExitCode+    :: CreateProcess+    -> String                      -- ^ standard input+    -> IO (ExitCode,String,String) -- ^ exitcode, stdout, stderr+readCreateProcessWithExitCode cp input = do+    let cp_opts = cp {                     std_in  = CreatePipe,                     std_out = CreatePipe,                     std_err = CreatePipe                   }-    withCreateProcess_ "readProcessWithExitCode" cp_opts $+    withCreateProcess_ "readCreateProcessWithExitCode" cp_opts $       \(Just inh) (Just outh) (Just errh) ph -> do          out <- hGetContents outh
System/Process/Internals.hs view
@@ -463,11 +463,20 @@ runInteractiveProcess_lock :: MVar () runInteractiveProcess_lock = unsafePerformIO $ newMVar () +-- The following functions are always present in the export list. For+-- compatibility with the non-Windows code, we provide the same functions with+-- matching type signatures, but implemented as no-ops. For details, see:+-- <https://github.com/haskell/process/pull/21> startDelegateControlC :: IO () startDelegateControlC = return ()  endDelegateControlC :: ExitCode -> IO () endDelegateControlC _ = return ()++stopDelegateControlC :: IO ()+stopDelegateControlC = return ()++-- End no-op functions  foreign import ccall unsafe "runInteractiveProcess"   c_runInteractiveProcess
cbits/runProcess.c view
@@ -200,7 +200,9 @@             }             // XXX Not the pipe             for (i = 3; i < max_fd; i++) {-                close(i);+		if (i != forkCommunicationFds[1]) {+		    close(i);+		}             }         } 
changelog.md view
@@ -1,5 +1,12 @@ # Changelog for [`process` package](http://hackage.haskell.org/package/process) +## 1.2.3.0 *March 2015*++  * [Meaningful error message when exe not found on close\_fds is+  True](https://ghc.haskell.org/trac/ghc/ticket/3649#comment:10)++  * New functions `readCreateProcess` and `readCreateProcessWithExitCode`+ ## 1.2.2.0  *Jan 2015*    * Fix delegated CTRL-C handling in `createProcess` in case of failed
configure view
@@ -1,11 +1,13 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.69 for Haskell process package 1.0.+# Generated by GNU Autoconf 2.68 for Haskell process package 1.0. # # Report bugs to <libraries@haskell.org>. # #-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software+# Foundation, Inc. # # # This configure script is free software; the Free Software Foundation@@ -134,31 +136,6 @@ # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# Use a proper internal environment variable to ensure we don't fall-  # into an infinite loop, continuously re-executing ourselves.-  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then-    _as_can_reexec=no; export _as_can_reexec;-    # We cannot yet assume a decent shell, so we have to provide a-# neutralization value for shells without unset; and this also-# works around shells that cannot unset nonexistent variables.-# Preserve -v and -x to the replacement shell.-BASH_ENV=/dev/null-ENV=/dev/null-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV-case $- in # ((((-  *v*x* | *x*v* ) as_opts=-vx ;;-  *v* ) as_opts=-v ;;-  *x* ) as_opts=-x ;;-  * ) as_opts= ;;-esac-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}-# Admittedly, this is quite paranoid, since all the known shells bail-# out after a failed `exec'.-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2-as_fn_exit 255-  fi-  # We don't want this to propagate to other subprocesses.-          { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :   emulate sh@@ -192,8 +169,7 @@ else   exitcode=1; echo positional parameters were not saved. fi-test x\$exitcode = x0 || exit 1-test -x / || exit 1"+test x\$exitcode = x0 || exit 1"   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&@@ -238,25 +214,21 @@         if test "x$CONFIG_SHELL" != x; then :-  export CONFIG_SHELL-             # We cannot yet assume a decent shell, so we have to provide a-# neutralization value for shells without unset; and this also-# works around shells that cannot unset nonexistent variables.-# Preserve -v and -x to the replacement shell.-BASH_ENV=/dev/null-ENV=/dev/null-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV-case $- in # ((((-  *v*x* | *x*v* ) as_opts=-vx ;;-  *v* ) as_opts=-v ;;-  *x* ) as_opts=-x ;;-  * ) as_opts= ;;-esac-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}-# Admittedly, this is quite paranoid, since all the known shells bail-# out after a failed `exec'.-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2-exit 255+  # We cannot yet assume a decent shell, so we have to provide a+	# neutralization value for shells without unset; and this also+	# works around shells that cannot unset nonexistent variables.+	# Preserve -v and -x to the replacement shell.+	BASH_ENV=/dev/null+	ENV=/dev/null+	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV+	export CONFIG_SHELL+	case $- in # ((((+	  *v*x* | *x*v* ) as_opts=-vx ;;+	  *v* ) as_opts=-v ;;+	  *x* ) as_opts=-x ;;+	  * ) as_opts= ;;+	esac+	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi      if test x$as_have_required = xno; then :@@ -359,14 +331,6 @@   } # as_fn_mkdir_p--# as_fn_executable_p FILE-# ------------------------# Test if FILE is an executable regular file.-as_fn_executable_p ()-{-  test -f "$1" && test -x "$1"-} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take@@ -488,10 +452,6 @@   chmod +x "$as_me.lineno" ||     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } -  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have-  # already done that, so ensure we don't try to do so again and fall-  # in an infinite loop.  This has already happened in practice.-  _as_can_reexec=no; export _as_can_reexec   # Don't try to exec as it changes $[0], causing all sort of problems   # (the dirname of $[0] is not the place where we might find the   # original and so on.  Autoconf is especially sensitive to this).@@ -526,16 +486,16 @@     # ... but there are two gotchas:     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.-    # In both cases, we have to default to `cp -pR'.+    # In both cases, we have to default to `cp -p'.     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||-      as_ln_s='cp -pR'+      as_ln_s='cp -p'   elif ln conf$$.file conf$$ 2>/dev/null; then     as_ln_s=ln   else-    as_ln_s='cp -pR'+    as_ln_s='cp -p'   fi else-  as_ln_s='cp -pR'+  as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null@@ -547,8 +507,28 @@   as_mkdir_p=false fi -as_test_x='test -x'-as_executable_p=as_fn_executable_p+if test -x / >/dev/null 2>&1; then+  as_test_x='test -x'+else+  if ls -dL / >/dev/null 2>&1; then+    as_ls_L_option=L+  else+    as_ls_L_option=+  fi+  as_test_x='+    eval sh -c '\''+      if test -d "$1"; then+	test -d "$1/.";+      else+	case $1 in #(+	-*)set "./$1";;+	esac;+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((+	???[sx]*):;;*)false;;esac;fi+    '\'' sh+  '+fi+as_executable_p=$as_test_x  # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"@@ -1141,6 +1121,8 @@ if test "x$host_alias" != x; then   if test "x$build_alias" = x; then     cross_compiling=maybe+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.+    If a cross compiler is detected then cross compile mode will be used" >&2   elif test "x$build_alias" != "x$host_alias"; then     cross_compiling=yes   fi@@ -1373,9 +1355,9 @@ if $ac_init_version; then   cat <<\_ACEOF Haskell process package configure 1.0-generated by GNU Autoconf 2.69+generated by GNU Autoconf 2.68 -Copyright (C) 2012 Free Software Foundation, Inc.+Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF@@ -1706,7 +1688,7 @@ 	 test ! -s conftest.err        } && test -s conftest$ac_exeext && { 	 test "$cross_compiling" = yes ||-	 test -x conftest$ac_exeext+	 $as_test_x conftest$ac_exeext        }; then :   ac_retval=0 else@@ -1809,8 +1791,7 @@ main () { static int test_array [1 - 2 * !(($2) >= 0)];-test_array [0] = 0;-return test_array [0];+test_array [0] = 0    ;   return 0;@@ -1826,8 +1807,7 @@ main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)];-test_array [0] = 0;-return test_array [0];+test_array [0] = 0    ;   return 0;@@ -1853,8 +1833,7 @@ main () { static int test_array [1 - 2 * !(($2) < 0)];-test_array [0] = 0;-return test_array [0];+test_array [0] = 0    ;   return 0;@@ -1870,8 +1849,7 @@ main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)];-test_array [0] = 0;-return test_array [0];+test_array [0] = 0    ;   return 0;@@ -1905,8 +1883,7 @@ main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)];-test_array [0] = 0;-return test_array [0];+test_array [0] = 0    ;   return 0;@@ -1979,7 +1956,7 @@ running configure, to aid debugging if configure makes a mistake.  It was created by Haskell process package $as_me 1.0, which was-generated by GNU Autoconf 2.69.  Invocation command line was+generated by GNU Autoconf 2.68.  Invocation command line was    $ $0 $@ @@ -2361,7 +2338,7 @@   IFS=$as_save_IFS   test -z "$as_dir" && as_dir=.     for ac_exec_ext in '' $ac_executable_extensions; do-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then     ac_cv_prog_CC="${ac_tool_prefix}gcc"     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5     break 2@@ -2401,7 +2378,7 @@   IFS=$as_save_IFS   test -z "$as_dir" && as_dir=.     for ac_exec_ext in '' $ac_executable_extensions; do-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then     ac_cv_prog_ac_ct_CC="gcc"     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5     break 2@@ -2454,7 +2431,7 @@   IFS=$as_save_IFS   test -z "$as_dir" && as_dir=.     for ac_exec_ext in '' $ac_executable_extensions; do-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then     ac_cv_prog_CC="${ac_tool_prefix}cc"     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5     break 2@@ -2495,7 +2472,7 @@   IFS=$as_save_IFS   test -z "$as_dir" && as_dir=.     for ac_exec_ext in '' $ac_executable_extensions; do-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then        ac_prog_rejected=yes        continue@@ -2553,7 +2530,7 @@   IFS=$as_save_IFS   test -z "$as_dir" && as_dir=.     for ac_exec_ext in '' $ac_executable_extensions; do-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5     break 2@@ -2597,7 +2574,7 @@   IFS=$as_save_IFS   test -z "$as_dir" && as_dir=.     for ac_exec_ext in '' $ac_executable_extensions; do-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then     ac_cv_prog_ac_ct_CC="$ac_prog"     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5     break 2@@ -3043,7 +3020,8 @@ /* end confdefs.h.  */ #include <stdarg.h> #include <stdio.h>-struct stat;+#include <sys/types.h>+#include <sys/stat.h> /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int);@@ -3284,7 +3262,7 @@     for ac_prog in grep ggrep; do     for ac_exec_ext in '' $ac_executable_extensions; do       ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"-      as_fn_executable_p "$ac_path_GREP" || continue+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found.   # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in@@ -3350,7 +3328,7 @@     for ac_prog in egrep; do     for ac_exec_ext in '' $ac_executable_extensions; do       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"-      as_fn_executable_p "$ac_path_EGREP" || continue+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found.   # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in@@ -4214,16 +4192,16 @@     # ... but there are two gotchas:     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.-    # In both cases, we have to default to `cp -pR'.+    # In both cases, we have to default to `cp -p'.     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||-      as_ln_s='cp -pR'+      as_ln_s='cp -p'   elif ln conf$$.file conf$$ 2>/dev/null; then     as_ln_s=ln   else-    as_ln_s='cp -pR'+    as_ln_s='cp -p'   fi else-  as_ln_s='cp -pR'+  as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null@@ -4283,16 +4261,28 @@   as_mkdir_p=false fi --# as_fn_executable_p FILE-# ------------------------# Test if FILE is an executable regular file.-as_fn_executable_p ()-{-  test -f "$1" && test -x "$1"-} # as_fn_executable_p-as_test_x='test -x'-as_executable_p=as_fn_executable_p+if test -x / >/dev/null 2>&1; then+  as_test_x='test -x'+else+  if ls -dL / >/dev/null 2>&1; then+    as_ls_L_option=L+  else+    as_ls_L_option=+  fi+  as_test_x='+    eval sh -c '\''+      if test -d "$1"; then+	test -d "$1/.";+      else+	case $1 in #(+	-*)set "./$1";;+	esac;+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((+	???[sx]*):;;*)false;;esac;fi+    '\'' sh+  '+fi+as_executable_p=$as_test_x  # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"@@ -4314,7 +4304,7 @@ # values after options handling. ac_log=" This file was extended by Haskell process package $as_me 1.0, which was-generated by GNU Autoconf 2.69.  Invocation command line was+generated by GNU Autoconf 2.68.  Invocation command line was    CONFIG_FILES    = $CONFIG_FILES   CONFIG_HEADERS  = $CONFIG_HEADERS@@ -4367,10 +4357,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Haskell process package config.status 1.0-configured by $0, generated by GNU Autoconf 2.69,+configured by $0, generated by GNU Autoconf 2.68,   with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc.+Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -4450,7 +4440,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion   shift   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6   CONFIG_SHELL='$SHELL'
process.cabal view
@@ -1,5 +1,5 @@ name:          process-version:       1.2.2.0+version:       1.2.3.0 -- NOTE: Don't forget to update ./changelog.md license:       BSD3 license-file:  LICENSE@@ -61,10 +61,18 @@      build-depends: base      >= 4.4 && < 4.9,                    directory >= 1.1 && < 1.3,-                   filepath  >= 1.2 && < 1.4,+                   filepath  >= 1.2 && < 1.5,                    deepseq   >= 1.1 && < 1.5     if os(windows)         build-depends: Win32 >=2.2 && < 2.4         extra-libraries: kernel32     else         build-depends: unix >= 2.5 && < 2.8++test-suite test+  default-language: Haskell2010+  hs-source-dirs: test+  main-is: main.hs+  type: exitcode-stdio-1.0+  build-depends: base+               , process
+ test/main.hs view
@@ -0,0 +1,14 @@+import Control.Exception+import System.IO.Error+import System.Process++main :: IO ()+main = do+    res <- handle (return . Left . isDoesNotExistError) $ do+        (_, _, _, ph) <- createProcess (proc "definitelydoesnotexist" [])+            { close_fds = True+            }+        fmap Right $ waitForProcess ph+    case res of+        Left True -> return ()+        _ -> error $ show res