    {- System.Process enhancements, including additional ways of running
     - processes, and logging.
     -
     - Copyright 2012-2015 Joey Hess <id@joeyh.name>
     -
     - License: BSD-2-clause
     -}

    {-# LANGUAGE CPP, Rank2Types #-}
    {-# OPTIONS_GHC -fno-warn-tabs #-}

    module Utility.Process (
    	module X,
    	CreateProcess(..),
    	StdHandle(..),
    	readProcess,
    	readProcess',
    	readProcessEnv,
    	writeReadProcessEnv,
    	forceSuccessProcess,
    	forceSuccessProcess',
    	checkSuccessProcess,
    	ignoreFailureProcess,
    	createProcessSuccess,
    	createProcessChecked,
    	createBackgroundProcess,
    	withHandle,
    	withIOHandles,
    	withOEHandles,
    	withNullHandle,
    	withQuietOutput,
    	feedWithQuietOutput,
    	createProcess,
    	waitForProcess,
    	startInteractiveProcess,
    	stdinHandle,
    	stdoutHandle,
    	stderrHandle,
    	ioHandles,
    	processHandle,
    	devNull,
    ) where

    import qualified Utility.Process.Shim
    import qualified Utility.Process.Shim as X hiding (CreateProcess(..), createProcess, runInteractiveProcess, readProcess, readProcessWithExitCode, system, rawSystem, runInteractiveCommand, runProcess)
    import Utility.Process.Shim hiding (createProcess, readProcess, waitForProcess)
    import Utility.Misc
    import Utility.Exception

    import System.Exit
    import System.IO
    import System.Log.Logger
    import Control.Concurrent
    import qualified Control.Exception as E
    import Control.Monad

    type CreateProcessRunner = forall a. CreateProcess -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a) -> IO a

    data StdHandle = StdinHandle | StdoutHandle | StderrHandle
    	deriving (StdHandle -> StdHandle -> Bool
    (StdHandle -> StdHandle -> Bool)
    -> (StdHandle -> StdHandle -> Bool) -> Eq StdHandle
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: StdHandle -> StdHandle -> Bool
    == :: StdHandle -> StdHandle -> Bool
    $c/= :: StdHandle -> StdHandle -> Bool
    /= :: StdHandle -> StdHandle -> Bool
    Eq)

    -- | Normally, when reading from a process, it does not need to be fed any
    -- standard input.
    readProcess :: FilePath	-> [String] -> IO String
    readProcess :: FilePath -> [FilePath] -> IO FilePath
    readProcess FilePath
    cmd [FilePath]
    args = FilePath
    -> [FilePath] -> Maybe [(FilePath, FilePath)] -> IO FilePath
    readProcessEnv FilePath
    cmd [FilePath]
    args Maybe [(FilePath, FilePath)]
    forall a. Maybe a
    Nothing

    readProcessEnv :: FilePath -> [String] -> Maybe [(String, String)] -> IO String
    readProcessEnv :: FilePath
    -> [FilePath] -> Maybe [(FilePath, FilePath)] -> IO FilePath
    readProcessEnv FilePath
    cmd [FilePath]
    args Maybe [(FilePath, FilePath)]
    environ = CreateProcess -> IO FilePath
    readProcess' CreateProcess
    p
      where
    	p :: CreateProcess
    p = (FilePath -> [FilePath] -> CreateProcess
    proc FilePath
    cmd [FilePath]
    args)
    		{ std_out = CreatePipe
    		, env = environ
    		}

    readProcess' :: CreateProcess -> IO String
    readProcess' :: CreateProcess -> IO FilePath
    readProcess' CreateProcess
    p = StdHandle
    -> CreateProcessRunner
    -> CreateProcess
    -> (Handle -> IO FilePath)
    -> IO FilePath
    forall a.
    StdHandle
    -> CreateProcessRunner -> CreateProcess -> (Handle -> IO a) -> IO a
    withHandle StdHandle
    StdoutHandle CreateProcess
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    CreateProcessRunner
    createProcessSuccess CreateProcess
    p ((Handle -> IO FilePath) -> IO FilePath)
    -> (Handle -> IO FilePath) -> IO FilePath
    forall a b. (a -> b) -> a -> b
    $ \Handle
    h -> do
    	FilePath
    output  <- Handle -> IO FilePath
    hGetContentsStrict Handle
    h
    	Handle -> IO ()
    hClose Handle
    h
    	FilePath -> IO FilePath
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return FilePath
    output

    -- | Runs an action to write to a process on its stdin,
    -- returns its output, and also allows specifying the environment.
    writeReadProcessEnv
    	:: FilePath
    	-> [String]
    	-> Maybe [(String, String)]
    	-> (Maybe (Handle -> IO ()))
    	-> (Maybe (Handle -> IO ()))
    	-> IO String
    writeReadProcessEnv :: FilePath
    -> [FilePath]
    -> Maybe [(FilePath, FilePath)]
    -> Maybe (Handle -> IO ())
    -> Maybe (Handle -> IO ())
    -> IO FilePath
    writeReadProcessEnv FilePath
    cmd [FilePath]
    args Maybe [(FilePath, FilePath)]
    environ Maybe (Handle -> IO ())
    writestdin Maybe (Handle -> IO ())
    adjusthandle = do
    	(Just Handle
    inh, Just Handle
    outh, Maybe Handle
    _, ProcessHandle
    pid) <- CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess CreateProcess
    p

    	IO ()
    -> ((Handle -> IO ()) -> IO ()) -> Maybe (Handle -> IO ()) -> IO ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (() -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()) (\Handle -> IO ()
    a -> Handle -> IO ()
    a Handle
    inh) Maybe (Handle -> IO ())
    adjusthandle
    	IO ()
    -> ((Handle -> IO ()) -> IO ()) -> Maybe (Handle -> IO ()) -> IO ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (() -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()) (\Handle -> IO ()
    a -> Handle -> IO ()
    a Handle
    outh) Maybe (Handle -> IO ())
    adjusthandle

    	-- fork off a thread to start consuming the output
    	FilePath
    output  <- Handle -> IO FilePath
    hGetContents Handle
    outh
    	MVar ()
    outMVar <- IO (MVar ())
    forall a. IO (MVar a)
    newEmptyMVar
    	ThreadId
    _ <- IO () -> IO ThreadId
    forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
    forall a b. (a -> b) -> a -> b
    $ Int -> IO Int
    forall a. a -> IO a
    E.evaluate (FilePath -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length FilePath
    output) IO Int -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> MVar () -> () -> IO ()
    forall a. MVar a -> a -> IO ()
    putMVar MVar ()
    outMVar ()

    	-- now write and flush any input
    	IO ()
    -> ((Handle -> IO ()) -> IO ()) -> Maybe (Handle -> IO ()) -> IO ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (() -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()) (\Handle -> IO ()
    a -> Handle -> IO ()
    a Handle
    inh IO () -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Handle -> IO ()
    hFlush Handle
    inh) Maybe (Handle -> IO ())
    writestdin
    	Handle -> IO ()
    hClose Handle
    inh -- done with stdin

    	-- wait on the output
    	MVar () -> IO ()
    forall a. MVar a -> IO a
    takeMVar MVar ()
    outMVar
    	Handle -> IO ()
    hClose Handle
    outh

    	-- wait on the process
    	CreateProcess -> ProcessHandle -> IO ()
    forceSuccessProcess CreateProcess
    p ProcessHandle
    pid

    	FilePath -> IO FilePath
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return FilePath
    output

      where
    	p :: CreateProcess
    p = (FilePath -> [FilePath] -> CreateProcess
    proc FilePath
    cmd [FilePath]
    args)
    		{ std_in = CreatePipe
    		, std_out = CreatePipe
    		, std_err = Inherit
    		, env = environ
    		}

    -- | Waits for a ProcessHandle, and throws an IOError if the process
    -- did not exit successfully.
    forceSuccessProcess :: CreateProcess -> ProcessHandle -> IO ()
    forceSuccessProcess :: CreateProcess -> ProcessHandle -> IO ()
    forceSuccessProcess CreateProcess
    p ProcessHandle
    pid = ProcessHandle -> IO ExitCode
    waitForProcess ProcessHandle
    pid IO ExitCode -> (ExitCode -> IO ()) -> IO ()
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= CreateProcess -> ExitCode -> IO ()
    forceSuccessProcess' CreateProcess
    p

    forceSuccessProcess' :: CreateProcess -> ExitCode -> IO ()
    forceSuccessProcess' :: CreateProcess -> ExitCode -> IO ()
    forceSuccessProcess' CreateProcess
    _ ExitCode
    ExitSuccess = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    forceSuccessProcess' CreateProcess
    p (ExitFailure Int
    n) = FilePath -> IO ()
    forall a. FilePath -> IO a
    forall (m :: * -> *) a. MonadFail m => FilePath -> m a
    fail (FilePath -> IO ()) -> FilePath -> IO ()
    forall a b. (a -> b) -> a -> b
    $
    	CreateProcess -> FilePath
    showCmd CreateProcess
    p FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    " exited " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ Int -> FilePath
    forall a. Show a => a -> FilePath
    show Int
    n

    -- | Waits for a ProcessHandle and returns True if it exited successfully.
    -- Note that using this with createProcessChecked will throw away
    -- the Bool, and is only useful to ignore the exit code of a process,
    -- while still waiting for it. -}
    checkSuccessProcess :: ProcessHandle -> IO Bool
    checkSuccessProcess :: ProcessHandle -> IO Bool
    checkSuccessProcess ProcessHandle
    pid = do
    	ExitCode
    code <- ProcessHandle -> IO ExitCode
    waitForProcess ProcessHandle
    pid
    	Bool -> IO Bool
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Bool -> IO Bool) -> Bool -> IO Bool
    forall a b. (a -> b) -> a -> b
    $ ExitCode
    code ExitCode -> ExitCode -> Bool
    forall a. Eq a => a -> a -> Bool
    == ExitCode
    ExitSuccess

    ignoreFailureProcess :: ProcessHandle -> IO Bool
    ignoreFailureProcess :: ProcessHandle -> IO Bool
    ignoreFailureProcess ProcessHandle
    pid = do
    	IO ExitCode -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO ExitCode -> IO ()) -> IO ExitCode -> IO ()
    forall a b. (a -> b) -> a -> b
    $ ProcessHandle -> IO ExitCode
    waitForProcess ProcessHandle
    pid
    	Bool -> IO Bool
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True

    -- | Runs createProcess, then an action on its handles, and then
    -- forceSuccessProcess.
    createProcessSuccess :: CreateProcessRunner
    createProcessSuccess :: CreateProcessRunner
    createProcessSuccess CreateProcess
    p (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a
    a = (ProcessHandle -> IO ()) -> CreateProcessRunner
    forall b. (ProcessHandle -> IO b) -> CreateProcessRunner
    createProcessChecked (CreateProcess -> ProcessHandle -> IO ()
    forceSuccessProcess CreateProcess
    p) CreateProcess
    p (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a
    a

    -- | Runs createProcess, then an action on its handles, and then
    -- a checker action on its exit code, which must wait for the process.
    createProcessChecked :: (ProcessHandle -> IO b) -> CreateProcessRunner
    createProcessChecked :: forall b. (ProcessHandle -> IO b) -> CreateProcessRunner
    createProcessChecked ProcessHandle -> IO b
    checker CreateProcess
    p (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a
    a = do
    	t :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    t@(Maybe Handle
    _, Maybe Handle
    _, Maybe Handle
    _, ProcessHandle
    pid) <- CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess CreateProcess
    p
    	Either SomeException a
    r <- IO a -> IO (Either SomeException a)
    forall (m :: * -> *) a.
    MonadCatch m =>
    m a -> m (Either SomeException a)
    tryNonAsync (IO a -> IO (Either SomeException a))
    -> IO a -> IO (Either SomeException a)
    forall a b. (a -> b) -> a -> b
    $ (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a
    a (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    t
    	b
    _ <- ProcessHandle -> IO b
    checker ProcessHandle
    pid
    	(SomeException -> IO a)
    -> (a -> IO a) -> Either SomeException a -> IO a
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either SomeException -> IO a
    forall a e. Exception e => e -> a
    E.throw a -> IO a
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Either SomeException a
    r

    -- | Leaves the process running, suitable for lazy streaming.
    -- Note: Zombies will result, and must be waited on.
    createBackgroundProcess :: CreateProcessRunner
    createBackgroundProcess :: CreateProcessRunner
    createBackgroundProcess CreateProcess
    p (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a
    a = (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a
    a ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a)
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO a
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess CreateProcess
    p

    -- | Runs a CreateProcessRunner, on a CreateProcess structure, that
    -- is adjusted to pipe only from/to a single StdHandle, and passes
    -- the resulting Handle to an action.
    withHandle
    	:: StdHandle
    	-> CreateProcessRunner
    	-> CreateProcess
    	-> (Handle -> IO a)
    	-> IO a
    withHandle :: forall a.
    StdHandle
    -> CreateProcessRunner -> CreateProcess -> (Handle -> IO a) -> IO a
    withHandle StdHandle
    h CreateProcessRunner
    creator CreateProcess
    p Handle -> IO a
    a = CreateProcess
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    CreateProcessRunner
    creator CreateProcess
    p' (((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
      -> IO a)
     -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    forall a b. (a -> b) -> a -> b
    $ Handle -> IO a
    a (Handle -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> Handle)
    -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    select
      where
    	base :: CreateProcess
    base = CreateProcess
    p
    		{ std_in = Inherit
    		, std_out = Inherit
    		, std_err = Inherit
    		}
    	((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    select, CreateProcess
    p') = case StdHandle
    h of
    		StdHandle
    StdinHandle -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stdinHandle, CreateProcess
    base { std_in = CreatePipe })
    		StdHandle
    StdoutHandle -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stdoutHandle, CreateProcess
    base { std_out = CreatePipe })
    		StdHandle
    StderrHandle -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stderrHandle, CreateProcess
    base { std_err = CreatePipe })

    -- | Like withHandle, but passes (stdin, stdout) handles to the action.
    withIOHandles
    	:: CreateProcessRunner
    	-> CreateProcess
    	-> ((Handle, Handle) -> IO a)
    	-> IO a
    withIOHandles :: forall a.
    CreateProcessRunner
    -> CreateProcess -> ((Handle, Handle) -> IO a) -> IO a
    withIOHandles CreateProcessRunner
    creator CreateProcess
    p (Handle, Handle) -> IO a
    a = CreateProcess
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    CreateProcessRunner
    creator CreateProcess
    p' (((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
      -> IO a)
     -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    forall a b. (a -> b) -> a -> b
    $ (Handle, Handle) -> IO a
    a ((Handle, Handle) -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> (Handle, Handle))
    -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> (Handle, Handle)
    ioHandles
      where
    	p' :: CreateProcess
    p' = CreateProcess
    p
    		{ std_in = CreatePipe
    		, std_out = CreatePipe
    		, std_err = Inherit
    		}

    -- | Like withHandle, but passes (stdout, stderr) handles to the action.
    withOEHandles
    	:: CreateProcessRunner
    	-> CreateProcess
    	-> ((Handle, Handle) -> IO a)
    	-> IO a
    withOEHandles :: forall a.
    CreateProcessRunner
    -> CreateProcess -> ((Handle, Handle) -> IO a) -> IO a
    withOEHandles CreateProcessRunner
    creator CreateProcess
    p (Handle, Handle) -> IO a
    a = CreateProcess
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    CreateProcessRunner
    creator CreateProcess
    p' (((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
      -> IO a)
     -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    forall a b. (a -> b) -> a -> b
    $ (Handle, Handle) -> IO a
    a ((Handle, Handle) -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> (Handle, Handle))
    -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> (Handle, Handle)
    oeHandles
      where
    	p' :: CreateProcess
    p' = CreateProcess
    p
    		{ std_in = Inherit
    		, std_out = CreatePipe
    		, std_err = CreatePipe
    		}

    withNullHandle :: (Handle -> IO a) -> IO a
    withNullHandle :: forall a. (Handle -> IO a) -> IO a
    withNullHandle = FilePath -> IOMode -> (Handle -> IO a) -> IO a
    forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
    withFile FilePath
    devNull IOMode
    WriteMode

    -- | Forces the CreateProcessRunner to run quietly;
    -- both stdout and stderr are discarded.
    withQuietOutput
    	:: CreateProcessRunner
    	-> CreateProcess
    	-> IO ()
    withQuietOutput :: CreateProcessRunner -> CreateProcess -> IO ()
    withQuietOutput CreateProcessRunner
    creator CreateProcess
    p = (Handle -> IO ()) -> IO ()
    forall a. (Handle -> IO a) -> IO a
    withNullHandle ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Handle
    nullh -> do
    	let p' :: CreateProcess
    p' = CreateProcess
    p
    		{ std_out = UseHandle nullh
    		, std_err = UseHandle nullh
    		}
    	CreateProcess
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO ())
    -> IO ()
    CreateProcessRunner
    creator CreateProcess
    p' (((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
      -> IO ())
     -> IO ())
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO ())
    -> IO ()
    forall a b. (a -> b) -> a -> b
    $ IO ()
    -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO ()
    forall a b. a -> b -> a
    const (IO ()
     -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
     -> IO ())
    -> IO ()
    -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO ()
    forall a b. (a -> b) -> a -> b
    $ () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    -- | Stdout and stderr are discarded, while the process is fed stdin
    -- from the handle.
    feedWithQuietOutput
    	:: CreateProcessRunner
    	-> CreateProcess
    	-> (Handle -> IO a)
    	-> IO a
    feedWithQuietOutput :: forall a.
    CreateProcessRunner -> CreateProcess -> (Handle -> IO a) -> IO a
    feedWithQuietOutput CreateProcessRunner
    creator CreateProcess
    p Handle -> IO a
    a = FilePath -> IOMode -> (Handle -> IO a) -> IO a
    forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
    withFile FilePath
    devNull IOMode
    WriteMode ((Handle -> IO a) -> IO a) -> (Handle -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \Handle
    nullh -> do
    	let p' :: CreateProcess
    p' = CreateProcess
    p
    		{ std_in = CreatePipe
    		, std_out = UseHandle nullh
    		, std_err = UseHandle nullh
    		}
    	CreateProcess
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    CreateProcessRunner
    creator CreateProcess
    p' (((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
      -> IO a)
     -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> IO a)
    -> IO a
    forall a b. (a -> b) -> a -> b
    $ Handle -> IO a
    a (Handle -> IO a)
    -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
        -> Handle)
    -> (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stdinHandle

    devNull :: FilePath
    #ifndef mingw32_HOST_OS
    devNull :: FilePath
    devNull = FilePath
    "/dev/null"
    #else
    -- Use device namespace to prevent GHC from rewriting path
    devNull = "\\\\.\\NUL"
    #endif

    -- | Extract a desired handle from createProcess's tuple.
    -- These partial functions are safe as long as createProcess is run
    -- with appropriate parameters to set up the desired handle.
    -- Get it wrong and the runtime crash will always happen, so should be
    -- easily noticed.
    type HandleExtractor = (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stdinHandle :: HandleExtractor
    stdinHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stdinHandle (Just Handle
    h, Maybe Handle
    _, Maybe Handle
    _, ProcessHandle
    _) = Handle
    h
    stdinHandle (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    _ = FilePath -> Handle
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "expected stdinHandle"
    stdoutHandle :: HandleExtractor
    stdoutHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stdoutHandle (Maybe Handle
    _, Just Handle
    h, Maybe Handle
    _, ProcessHandle
    _) = Handle
    h
    stdoutHandle (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    _ = FilePath -> Handle
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "expected stdoutHandle"
    stderrHandle :: HandleExtractor
    stderrHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
    stderrHandle (Maybe Handle
    _, Maybe Handle
    _, Just Handle
    h, ProcessHandle
    _) = Handle
    h
    stderrHandle (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    _ = FilePath -> Handle
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "expected stderrHandle"
    ioHandles :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> (Handle, Handle)
    ioHandles :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> (Handle, Handle)
    ioHandles (Just Handle
    hin, Just Handle
    hout, Maybe Handle
    _, ProcessHandle
    _) = (Handle
    hin, Handle
    hout)
    ioHandles (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    _ = FilePath -> (Handle, Handle)
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "expected ioHandles"
    oeHandles :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> (Handle, Handle)
    oeHandles :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> (Handle, Handle)
    oeHandles (Maybe Handle
    _, Just Handle
    hout, Just Handle
    herr, ProcessHandle
    _) = (Handle
    hout, Handle
    herr)
    oeHandles (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    _ = FilePath -> (Handle, Handle)
    forall a. HasCallStack => FilePath -> a
    error FilePath
    "expected oeHandles"

    processHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> ProcessHandle
    processHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    -> ProcessHandle
    processHandle (Maybe Handle
    _, Maybe Handle
    _, Maybe Handle
    _, ProcessHandle
    pid) = ProcessHandle
    pid

    -- | Shows the command that a CreateProcess will run.
    showCmd :: CreateProcess -> String
    showCmd :: CreateProcess -> FilePath
    showCmd = CmdSpec -> FilePath
    go (CmdSpec -> FilePath)
    -> (CreateProcess -> CmdSpec) -> CreateProcess -> FilePath
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CreateProcess -> CmdSpec
    cmdspec
      where
    	go :: CmdSpec -> FilePath
    go (ShellCommand FilePath
    s) = FilePath
    s
    	go (RawCommand FilePath
    c [FilePath]
    ps) = FilePath
    c FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    " " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ [FilePath] -> FilePath
    forall a. Show a => a -> FilePath
    show [FilePath]
    ps

    -- | Starts an interactive process. Unlike runInteractiveProcess in
    -- System.Process, stderr is inherited.
    startInteractiveProcess
    	:: FilePath
    	-> [String]
    	-> Maybe [(String, String)]
    	-> IO (ProcessHandle, Handle, Handle)
    startInteractiveProcess :: FilePath
    -> [FilePath]
    -> Maybe [(FilePath, FilePath)]
    -> IO (ProcessHandle, Handle, Handle)
    startInteractiveProcess FilePath
    cmd [FilePath]
    args Maybe [(FilePath, FilePath)]
    environ = do
    	let p :: CreateProcess
    p = (FilePath -> [FilePath] -> CreateProcess
    proc FilePath
    cmd [FilePath]
    args)
    		{ std_in = CreatePipe
    		, std_out = CreatePipe
    		, std_err = Inherit
    		, env = environ
    		}
    	(Just Handle
    from, Just Handle
    to, Maybe Handle
    _, ProcessHandle
    pid) <- CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess CreateProcess
    p
    	(ProcessHandle, Handle, Handle)
    -> IO (ProcessHandle, Handle, Handle)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ProcessHandle
    pid, Handle
    to, Handle
    from)

    -- | Wrapper around 'System.Process.createProcess' that does debug logging.
    createProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess :: CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess CreateProcess
    p = do
    	CreateProcess -> IO ()
    debugProcess CreateProcess
    p
    	CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    Utility.Process.Shim.createProcess CreateProcess
    p

    -- | Debugging trace for a CreateProcess.
    debugProcess :: CreateProcess -> IO ()
    debugProcess :: CreateProcess -> IO ()
    debugProcess CreateProcess
    p = FilePath -> FilePath -> IO ()
    debugM FilePath
    "Utility.Process" (FilePath -> IO ()) -> FilePath -> IO ()
    forall a b. (a -> b) -> a -> b
    $ [FilePath] -> FilePath
    unwords
    	[ FilePath
    action FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    ":"
    	, CreateProcess -> FilePath
    showCmd CreateProcess
    p
    	]
      where
    	action :: FilePath
    action
    		| StdStream -> Bool
    piped (CreateProcess -> StdStream
    std_in CreateProcess
    p) Bool -> Bool -> Bool
    && StdStream -> Bool
    piped (CreateProcess -> StdStream
    std_out CreateProcess
    p) = FilePath
    "chat"
    		| StdStream -> Bool
    piped (CreateProcess -> StdStream
    std_in CreateProcess
    p)                      = FilePath
    "feed"
    		| StdStream -> Bool
    piped (CreateProcess -> StdStream
    std_out CreateProcess
    p)                     = FilePath
    "read"
    		| Bool
    otherwise                             = FilePath
    "call"
    	piped :: StdStream -> Bool
    piped StdStream
    Inherit = Bool
    False
    	piped StdStream
    _ = Bool
    True

    -- | Wrapper around 'System.Process.waitForProcess' that does debug logging.
    waitForProcess ::  ProcessHandle -> IO ExitCode
    waitForProcess :: ProcessHandle -> IO ExitCode
    waitForProcess ProcessHandle
    h = do
    	ExitCode
    r <- ProcessHandle -> IO ExitCode
    Utility.Process.Shim.waitForProcess ProcessHandle
    h
    	FilePath -> FilePath -> IO ()
    debugM FilePath
    "Utility.Process" (FilePath
    "process done " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ ExitCode -> FilePath
    forall a. Show a => a -> FilePath
    show ExitCode
    r)
    	ExitCode -> IO ExitCode
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ExitCode
    r