{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RecursiveDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Reflex.Process
( createProcess
, createProcessBufferingInput
, defProcessConfig
, unsafeCreateProcessWithHandles
, Process(..)
, ProcessConfig(..)
, SendPipe (..)
, createRedirectedProcess
) where
import Control.Concurrent.Async (Async, async, race_, waitBoth)
import Control.Concurrent.Chan (newChan, readChan, writeChan)
import Control.Exception (finally)
import Control.Monad (void, when)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Fix (MonadFix)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Default (Default, def)
import Data.Function (fix)
import Data.Traversable (for)
import GHC.IO.Handle (Handle)
import qualified GHC.IO.Handle as H
import System.Exit (ExitCode)
import qualified System.Posix.Signals as P
import System.Process hiding (createProcess)
import qualified System.Process as P
import Reflex
data SendPipe i
= SendPipe_Message i
| SendPipe_EOF
| SendPipe_LastMessage i
data ProcessConfig t i = ProcessConfig
{ ProcessConfig t i -> Event t i
_processConfig_stdin :: Event t i
, ProcessConfig t i -> Event t Signal
_processConfig_signal :: Event t P.Signal
}
instance Reflex t => Default (ProcessConfig t i) where
def :: ProcessConfig t i
def = ProcessConfig t i
forall t i. Reflex t => ProcessConfig t i
defProcessConfig
defProcessConfig :: Reflex t => ProcessConfig t i
defProcessConfig :: ProcessConfig t i
defProcessConfig = Event t i -> Event t Signal -> ProcessConfig t i
forall t i. Event t i -> Event t Signal -> ProcessConfig t i
ProcessConfig Event t i
forall k (t :: k) a. Reflex t => Event t a
never Event t Signal
forall k (t :: k) a. Reflex t => Event t a
never
data Process t o e = Process
{ Process t o e -> ProcessHandle
_process_handle :: P.ProcessHandle
, Process t o e -> Event t o
_process_stdout :: Event t o
, Process t o e -> Event t e
_process_stderr :: Event t e
, Process t o e -> Event t ExitCode
_process_exit :: Event t ExitCode
, Process t o e -> Event t Signal
_process_signal :: Event t P.Signal
}
createProcess
:: (MonadIO m, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m), MonadFix m)
=> P.CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
createProcess :: CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
createProcess CreateProcess
p ProcessConfig t (SendPipe ByteString)
procConfig = do
Chan (SendPipe ByteString)
channel <- IO (Chan (SendPipe ByteString)) -> m (Chan (SendPipe ByteString))
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO (Chan (SendPipe ByteString))
forall a. IO (Chan a)
newChan
IO (SendPipe ByteString)
-> (SendPipe ByteString -> IO ())
-> CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
forall (m :: * -> *) t.
(MonadIO m, TriggerEvent t m, PerformEvent t m,
MonadIO (Performable m), MonadFix m) =>
IO (SendPipe ByteString)
-> (SendPipe ByteString -> IO ())
-> CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
createProcessBufferingInput (Chan (SendPipe ByteString) -> IO (SendPipe ByteString)
forall a. Chan a -> IO a
readChan Chan (SendPipe ByteString)
channel) (Chan (SendPipe ByteString) -> SendPipe ByteString -> IO ()
forall a. Chan a -> a -> IO ()
writeChan Chan (SendPipe ByteString)
channel) CreateProcess
p ProcessConfig t (SendPipe ByteString)
procConfig
createProcessBufferingInput
:: (MonadIO m, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m), MonadFix m)
=> IO (SendPipe ByteString)
-> (SendPipe ByteString -> IO ())
-> P.CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
createProcessBufferingInput :: IO (SendPipe ByteString)
-> (SendPipe ByteString -> IO ())
-> CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
createProcessBufferingInput IO (SendPipe ByteString)
readBuffer SendPipe ByteString -> IO ()
writeBuffer CreateProcess
spec ProcessConfig t (SendPipe ByteString)
config = do
rec Process t ByteString ByteString
p <- (Handle -> IO (SendPipe ByteString -> IO ()))
-> (Handle -> (ByteString -> IO ()) -> IO (IO ()))
-> (Handle -> (ByteString -> IO ()) -> IO (IO ()))
-> CreateProcess
-> ProcessConfig t (SendPipe ByteString)
-> m (Process t ByteString ByteString)
forall t (m :: * -> *) i o e.
(MonadIO m, TriggerEvent t m, PerformEvent t m,
MonadIO (Performable m)) =>
(Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
unsafeCreateProcessWithHandles (ProcessHandle -> Handle -> IO (SendPipe ByteString -> IO ())
input (ProcessHandle -> Handle -> IO (SendPipe ByteString -> IO ()))
-> ProcessHandle -> Handle -> IO (SendPipe ByteString -> IO ())
forall a b. (a -> b) -> a -> b
$ Process t ByteString ByteString -> ProcessHandle
forall t o e. Process t o e -> ProcessHandle
_process_handle Process t ByteString ByteString
p) Handle -> (ByteString -> IO ()) -> IO (IO ())
forall a. Handle -> (ByteString -> IO a) -> IO (IO ())
output Handle -> (ByteString -> IO ()) -> IO (IO ())
forall a. Handle -> (ByteString -> IO a) -> IO (IO ())
output CreateProcess
spec ProcessConfig t (SendPipe ByteString)
config
Process t ByteString ByteString
-> m (Process t ByteString ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Process t ByteString ByteString
p
where
input :: ProcessHandle -> Handle -> IO (SendPipe ByteString -> IO ())
input :: ProcessHandle -> Handle -> IO (SendPipe ByteString -> IO ())
input ProcessHandle
ph Handle
h = do
Handle -> BufferMode -> IO ()
H.hSetBuffering Handle
h BufferMode
H.NoBuffering
IO (Async ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Async ()) -> IO ()) -> IO (Async ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ IO (Async ()) -> IO (Async ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Async ()) -> IO (Async ())) -> IO (Async ()) -> IO (Async ())
forall a b. (a -> b) -> a -> b
$ IO () -> IO (Async ())
forall a. IO a -> IO (Async a)
async (IO () -> IO (Async ())) -> IO () -> IO (Async ())
forall a b. (a -> b) -> a -> b
$ IO ExitCode -> IO () -> IO ()
forall a b. IO a -> IO b -> IO ()
race_ (ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
ph) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ (IO () -> IO ()) -> IO ()
forall a. (a -> a) -> a
fix ((IO () -> IO ()) -> IO ()) -> (IO () -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \IO ()
loop -> do
SendPipe ByteString
newMessage <- IO (SendPipe ByteString)
readBuffer
Bool
open <- Handle -> IO Bool
H.hIsOpen Handle
h
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
open (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Bool
writable <- Handle -> IO Bool
H.hIsWritable Handle
h
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
writable (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
case SendPipe ByteString
newMessage of
SendPipe_Message ByteString
m -> Handle -> ByteString -> IO ()
BS.hPutStr Handle
h ByteString
m IO () -> IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> IO ()
loop
SendPipe_LastMessage ByteString
m -> Handle -> ByteString -> IO ()
BS.hPutStr Handle
h ByteString
m IO () -> IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Handle -> IO ()
H.hClose Handle
h
SendPipe ByteString
SendPipe_EOF -> Handle -> IO ()
H.hClose Handle
h
(SendPipe ByteString -> IO ()) -> IO (SendPipe ByteString -> IO ())
forall (m :: * -> *) a. Monad m => a -> m a
return SendPipe ByteString -> IO ()
writeBuffer
output :: Handle -> (ByteString -> IO a) -> IO (IO ())
output Handle
h ByteString -> IO a
trigger = do
Handle -> BufferMode -> IO ()
H.hSetBuffering Handle
h BufferMode
H.LineBuffering
IO () -> IO (IO ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure (IO () -> IO (IO ())) -> IO () -> IO (IO ())
forall a b. (a -> b) -> a -> b
$ (IO () -> IO ()) -> IO ()
forall a. (a -> a) -> a
fix ((IO () -> IO ()) -> IO ()) -> (IO () -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \IO ()
go -> do
Bool
open <- Handle -> IO Bool
H.hIsOpen Handle
h
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
open (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Bool
readable <- Handle -> IO Bool
H.hIsReadable Handle
h
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
readable (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
ByteString
out <- Handle -> Int -> IO ByteString
BS.hGetSome Handle
h Int
32768
if ByteString -> Bool
BS.null ByteString
out
then Handle -> IO ()
H.hClose Handle
h
else IO a -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ByteString -> IO a
trigger ByteString
out) IO () -> IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> IO ()
go
unsafeCreateProcessWithHandles
:: forall t m i o e. (MonadIO m, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m))
=> (Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> P.CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
unsafeCreateProcessWithHandles :: (Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
unsafeCreateProcessWithHandles Handle -> IO (i -> IO ())
mkWriteStdInput Handle -> (o -> IO ()) -> IO (IO ())
mkReadStdOutput Handle -> (e -> IO ()) -> IO (IO ())
mkReadStdError CreateProcess
p (ProcessConfig Event t i
input Event t Signal
signal) = do
(Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
po <- IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
-> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
-> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle))
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
-> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
forall a b. (a -> b) -> a -> b
$ CreateProcess
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
P.createProcess CreateProcess
p { std_in :: StdStream
std_in = StdStream
P.CreatePipe, std_out :: StdStream
std_out = StdStream
P.CreatePipe, std_err :: StdStream
std_err = StdStream
P.CreatePipe }
(Handle
hIn, Handle
hOut, Handle
hErr, ProcessHandle
ph) <- case (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
po of
(Just Handle
hIn, Just Handle
hOut, Just Handle
hErr, ProcessHandle
ph) -> (Handle, Handle, Handle, ProcessHandle)
-> m (Handle, Handle, Handle, ProcessHandle)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Handle
hIn, Handle
hOut, Handle
hErr, ProcessHandle
ph)
(Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
_ -> [Char] -> m (Handle, Handle, Handle, ProcessHandle)
forall a. HasCallStack => [Char] -> a
error [Char]
"Reflex.Process.unsafeCreateProcessWithHandles: Created pipes were not returned by System.Process.createProcess."
Event t (Maybe Signal)
sigOut :: Event t (Maybe P.Signal) <- Event t (Performable m (Maybe Signal))
-> m (Event t (Maybe Signal))
forall t (m :: * -> *) a.
PerformEvent t m =>
Event t (Performable m a) -> m (Event t a)
performEvent (Event t (Performable m (Maybe Signal))
-> m (Event t (Maybe Signal)))
-> Event t (Performable m (Maybe Signal))
-> m (Event t (Maybe Signal))
forall a b. (a -> b) -> a -> b
$ Event t Signal
-> (Signal -> Performable m (Maybe Signal))
-> Event t (Performable m (Maybe Signal))
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
ffor Event t Signal
signal ((Signal -> Performable m (Maybe Signal))
-> Event t (Performable m (Maybe Signal)))
-> (Signal -> Performable m (Maybe Signal))
-> Event t (Performable m (Maybe Signal))
forall a b. (a -> b) -> a -> b
$ \Signal
sig -> IO (Maybe Signal) -> Performable m (Maybe Signal)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe Signal) -> Performable m (Maybe Signal))
-> IO (Maybe Signal) -> Performable m (Maybe Signal)
forall a b. (a -> b) -> a -> b
$ do
Maybe Pid
mpid <- ProcessHandle -> IO (Maybe Pid)
P.getPid ProcessHandle
ph
Maybe Pid -> (Pid -> IO Signal) -> IO (Maybe Signal)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for Maybe Pid
mpid ((Pid -> IO Signal) -> IO (Maybe Signal))
-> (Pid -> IO Signal) -> IO (Maybe Signal)
forall a b. (a -> b) -> a -> b
$ \Pid
pid -> Signal
sig Signal -> IO () -> IO Signal
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Signal -> Pid -> IO ()
P.signalProcess Signal
sig Pid
pid
let
output :: Handle -> m (Event t o, Async ())
output :: Handle -> m (Event t o, Async ())
output Handle
h = do
(Event t o
e, o -> IO ()
trigger) <- m (Event t o, o -> IO ())
forall t (m :: * -> *) a.
TriggerEvent t m =>
m (Event t a, a -> IO ())
newTriggerEvent
IO ()
reader <- IO (IO ()) -> m (IO ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (IO ()) -> m (IO ())) -> IO (IO ()) -> m (IO ())
forall a b. (a -> b) -> a -> b
$ Handle -> (o -> IO ()) -> IO (IO ())
mkReadStdOutput Handle
h o -> IO ()
trigger
Async ()
t <- IO (Async ()) -> m (Async ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Async ()) -> m (Async ())) -> IO (Async ()) -> m (Async ())
forall a b. (a -> b) -> a -> b
$ IO () -> IO (Async ())
forall a. IO a -> IO (Async a)
async IO ()
reader
(Event t o, Async ()) -> m (Event t o, Async ())
forall (m :: * -> *) a. Monad m => a -> m a
return (Event t o
e, Async ()
t)
errOutput :: Handle -> m (Event t e, Async ())
errOutput :: Handle -> m (Event t e, Async ())
errOutput Handle
h = do
(Event t e
e, e -> IO ()
trigger) <- m (Event t e, e -> IO ())
forall t (m :: * -> *) a.
TriggerEvent t m =>
m (Event t a, a -> IO ())
newTriggerEvent
IO ()
reader <- IO (IO ()) -> m (IO ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (IO ()) -> m (IO ())) -> IO (IO ()) -> m (IO ())
forall a b. (a -> b) -> a -> b
$ Handle -> (e -> IO ()) -> IO (IO ())
mkReadStdError Handle
h e -> IO ()
trigger
Async ()
t <- IO (Async ()) -> m (Async ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Async ()) -> m (Async ())) -> IO (Async ()) -> m (Async ())
forall a b. (a -> b) -> a -> b
$ IO () -> IO (Async ())
forall a. IO a -> IO (Async a)
async IO ()
reader
(Event t e, Async ()) -> m (Event t e, Async ())
forall (m :: * -> *) a. Monad m => a -> m a
return (Event t e
e, Async ()
t)
(Event t o
out, Async ()
outThread) <- Handle -> m (Event t o, Async ())
output Handle
hOut
(Event t e
err, Async ()
errThread) <- Handle -> m (Event t e, Async ())
errOutput Handle
hErr
(Event t ExitCode
ecOut, ExitCode -> IO ()
ecTrigger) <- m (Event t ExitCode, ExitCode -> IO ())
forall t (m :: * -> *) a.
TriggerEvent t m =>
m (Event t a, a -> IO ())
newTriggerEvent
m (Async ()) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (Async ()) -> m ()) -> m (Async ()) -> m ()
forall a b. (a -> b) -> a -> b
$ IO (Async ()) -> m (Async ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Async ()) -> m (Async ())) -> IO (Async ()) -> m (Async ())
forall a b. (a -> b) -> a -> b
$ IO () -> IO (Async ())
forall a. IO a -> IO (Async a)
async (IO () -> IO (Async ())) -> IO () -> IO (Async ())
forall a b. (a -> b) -> a -> b
$ (IO () -> IO () -> IO ()) -> IO () -> IO () -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
finally ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO ()
P.cleanupProcess (Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
hIn, Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
hOut, Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
hErr, ProcessHandle
ph)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
ExitCode
waited <- ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
ph
((), ())
_ <- Async () -> Async () -> IO ((), ())
forall a b. Async a -> Async b -> IO (a, b)
waitBoth Async ()
outThread Async ()
errThread
ExitCode -> IO ()
ecTrigger ExitCode
waited
i -> IO ()
writeInput :: i -> IO () <- IO (i -> IO ()) -> m (i -> IO ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (i -> IO ()) -> m (i -> IO ()))
-> IO (i -> IO ()) -> m (i -> IO ())
forall a b. (a -> b) -> a -> b
$ Handle -> IO (i -> IO ())
mkWriteStdInput Handle
hIn
Event t (Performable m ()) -> m ()
forall t (m :: * -> *).
PerformEvent t m =>
Event t (Performable m ()) -> m ()
performEvent_ (Event t (Performable m ()) -> m ())
-> Event t (Performable m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ IO () -> Performable m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Performable m ())
-> (i -> IO ()) -> i -> Performable m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. i -> IO ()
writeInput (i -> Performable m ()) -> Event t i -> Event t (Performable m ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Event t i
input
Process t o e -> m (Process t o e)
forall (m :: * -> *) a. Monad m => a -> m a
return (Process t o e -> m (Process t o e))
-> Process t o e -> m (Process t o e)
forall a b. (a -> b) -> a -> b
$ Process :: forall t o e.
ProcessHandle
-> Event t o
-> Event t e
-> Event t ExitCode
-> Event t Signal
-> Process t o e
Process
{ _process_exit :: Event t ExitCode
_process_exit = Event t ExitCode
ecOut
, _process_stdout :: Event t o
_process_stdout = Event t o
out
, _process_stderr :: Event t e
_process_stderr = Event t e
err
, _process_signal :: Event t Signal
_process_signal = (Maybe Signal -> Maybe Signal)
-> Event t (Maybe Signal) -> Event t Signal
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
fmapMaybe Maybe Signal -> Maybe Signal
forall a. a -> a
id Event t (Maybe Signal)
sigOut
, _process_handle :: ProcessHandle
_process_handle = ProcessHandle
ph
}
{-# DEPRECATED createRedirectedProcess "Use unsafeCreateProcessWithHandles instead." #-}
createRedirectedProcess
:: forall t m i o e. (MonadIO m, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m))
=> (Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> P.CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
createRedirectedProcess :: (Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
createRedirectedProcess = (Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
forall t (m :: * -> *) i o e.
(MonadIO m, TriggerEvent t m, PerformEvent t m,
MonadIO (Performable m)) =>
(Handle -> IO (i -> IO ()))
-> (Handle -> (o -> IO ()) -> IO (IO ()))
-> (Handle -> (e -> IO ()) -> IO (IO ()))
-> CreateProcess
-> ProcessConfig t i
-> m (Process t o e)
unsafeCreateProcessWithHandles