@@ -77,6 +77,8 @@ module Streamly.Internal.System.Process
7777 , inheritStdin
7878 , inheritStdout
7979 , pipeStdErr
80+ , pipeStdin
81+ , pipeStdout
8082
8183 -- * Exceptions
8284 , ProcessFailure (.. )
@@ -226,6 +228,12 @@ mkConfig _ _ = Config False
226228pipeStdErr :: Config -> Config
227229pipeStdErr (Config _) = Config True
228230
231+ pipeStdin :: Config -> Config
232+ pipeStdin (Config _) = Config True
233+
234+ pipeStdout :: Config -> Config
235+ pipeStdout (Config _) = Config True
236+
229237inheritStdin :: Config -> Config
230238inheritStdin (Config _) = Config True
231239
@@ -465,6 +473,12 @@ waitForChildTree = waitForDescendants
465473pipeStdErr :: Config -> Config
466474pipeStdErr (Config cfg) = Config $ cfg { std_err = CreatePipe }
467475
476+ pipeStdin :: Config -> Config
477+ pipeStdin (Config cfg) = Config $ cfg { std_in = CreatePipe }
478+
479+ pipeStdout :: Config -> Config
480+ pipeStdout (Config cfg) = Config $ cfg { std_out = CreatePipe }
481+
468482inheritStdin :: Config -> Config
469483inheritStdin (Config cfg) = Config $ cfg { std_in = Inherit }
470484
@@ -530,7 +544,7 @@ cleanupNormal (_, _, _, procHandle) = do
530544-- still hanging around.
531545cleanupException ::
532546 (Maybe Handle , Maybe Handle , Maybe Handle , ProcessHandle ) -> IO ()
533- cleanupException (Just stdinH, Just stdoutH , stderrMaybe, ph) = do
547+ cleanupException (stdinMaybe, stdoutMaybe , stderrMaybe, ph) = do
534548 -- Send a SIGTERM to the process
535549#ifdef USE_NATIVE
536550 terminate ph
@@ -541,8 +555,8 @@ cleanupException (Just stdinH, Just stdoutH, stderrMaybe, ph) = do
541555 -- Ideally we should be closing the handle without flushing the buffers so
542556 -- that we cannot get a SIGPIPE. But there seems to be no way to do that as
543557 -- of now so we just ignore the SIGPIPE.
544- hClose stdinH `catch` eatSIGPIPE
545- hClose stdoutH
558+ whenJust ( \ stdinH -> hClose stdinH `catch` eatSIGPIPE) stdinMaybe
559+ whenJust hClose stdoutMaybe
546560 whenJust hClose stderrMaybe
547561
548562 -- Non-blocking wait for the process to go away
@@ -565,7 +579,6 @@ cleanupException (Just stdinH, Just stdoutH, stderrMaybe, ph) = do
565579 _ -> False
566580
567581 eatSIGPIPE e = unless (isSIGPIPE e) $ throwIO e
568- cleanupException _ = error " cleanupProcess: Not reachable"
569582
570583-- | Creates a system process from an executable path and arguments. For the
571584-- default attributes used to create the process see 'mkConfig'.
@@ -630,6 +643,11 @@ pipeChunksWithAction run modCfg path args =
630643
631644 alloc = createProc' modCfg path args
632645
646+ -- Note: It is allowed to inheritStdout or inheritStderr but not both as that
647+ -- would not generate a stream for further processing.
648+ -- inheritStdin has no affect, we always pipe the input stream to the process's
649+ -- stdin
650+
633651-- | Like 'pipeChunksEither' but use the specified configuration to run the
634652-- process.
635653{-# INLINE pipeChunksEitherWith #-}
@@ -641,10 +659,12 @@ pipeChunksEitherWith ::
641659 -> Stream m (Array Word8 ) -- ^ Input stream
642660 -> Stream m (Either (Array Word8 ) (Array Word8 )) -- ^ Output stream
643661pipeChunksEitherWith modifier path args input =
644- pipeChunksWithAction run (modifier . pipeStdErr) path args
662+ pipeChunksWithAction run (pipeStdin . modifier . pipeStdErr) path args
645663
646664 where
647665
666+ run (_, Nothing , Nothing , _) =
667+ error " pipeChunksEitherWith: only one of stdout or stderr can be inherited"
648668 run (Just stdinH, Just stdoutH, Just stderrH, _) =
649669 putChunksClose stdinH input
650670 `parallel` fmap Left (toChunksClose stderrH)
@@ -704,6 +724,10 @@ pipeBytesEither path args input =
704724 rightRdr = fmap Right Array. reader
705725 in UNFOLD_EACH (Unfold. either leftRdr rightRdr) output
706726
727+ -- Note: inheritStdin, inheritStdout have no affect, we always pipe
728+ -- the input stream to the process's stdin and pipe the stdout to the
729+ -- resulting stream
730+
707731-- | Like 'pipeChunks' but use the specified configuration to run the process.
708732{-# INLINE pipeChunksWith #-}
709733pipeChunksWith ::
@@ -714,13 +738,14 @@ pipeChunksWith ::
714738 -> Stream m (Array Word8 ) -- ^ Input stream
715739 -> Stream m (Array Word8 ) -- ^ Output stream
716740pipeChunksWith modifier path args input =
717- pipeChunksWithAction run modifier path args
741+ pipeChunksWithAction run (pipeStdout . pipeStdin . modifier) path args
718742
719743 where
720744
721745 run (Just stdinH, Just stdoutH, _, _) =
722- putChunksClose stdinH input `parallel` toChunksClose stdoutH
723- run _ = error " pipeChunksWith: Not reachable"
746+ putChunksClose stdinH input
747+ `parallel` toChunksClose stdoutH
748+ run _ = error " pipeChunksWith: unreachable"
724749
725750-- | @pipeChunks file args input@ runs the executable @file@ specified by
726751-- its name or path using @args@ as arguments and @input@ stream as its
@@ -810,6 +835,9 @@ processBytes ::
810835 -> Stream m Word8 -- ^ Output Stream
811836processBytes = pipeBytes
812837
838+ whenJustS :: Applicative m => (a -> Stream m b ) -> Maybe a -> Stream m b
839+ whenJustS action mb = maybe Stream. nil action mb
840+
813841-- | Like 'pipeChunks' except that its input and output is stream of chars
814842-- instead of a stream of chunks. The input to the pipe is buffered with a
815843-- buffer size of 'defaultChunkSize'.
@@ -853,6 +881,10 @@ pipeChars path args input =
853881-- Generation
854882-------------------------------------------------------------------------------
855883
884+ -- Note: It is allowed to inheritStdout or inheritStderr but not both as that
885+ -- would not generate a stream for further processing and would result in unintuitive
886+ -- behaviour
887+
856888-- | Like 'toChunksEither' but use the specified configuration to run the
857889-- process.
858890{-# INLINE toChunksEitherWith #-}
@@ -863,14 +895,18 @@ toChunksEitherWith ::
863895 -> [String ] -- ^ Arguments
864896 -> Stream m (Either (Array Word8 ) (Array Word8 )) -- ^ Output stream
865897toChunksEitherWith modifier path args =
866- pipeChunksWithAction run (modifier . inheritStdin . pipeStdErr) path args
898+ pipeChunksWithAction run (modifier . inheritStdin . pipeStdErr . pipeStdout ) path args
867899
868900 where
869901
870- run (_, Just stdoutH, Just stderrH, _) =
871- fmap Left (toChunksClose stderrH)
872- `parallel` fmap Right (toChunksClose stdoutH)
873- run _ = error " toChunksEitherWith: Not reachable"
902+ run (_, Nothing , Nothing , _) =
903+ error " toChunksEitherWith: only one of stdout or stderr can be inherited"
904+ run (_, stdoutMaybe, stderrMaybe, _) =
905+ fmap Left (whenJustS toChunksClose stderrMaybe)
906+ `parallel` fmap Right (whenJustS toChunksClose stdoutMaybe)
907+
908+ -- Note: inheritStdout has no affect, we always pipe stdout to the resulting
909+ -- stream
874910
875911-- | Like 'toChunks' but use the specified configuration to run the process.
876912{-# INLINE toChunksWith #-}
@@ -881,12 +917,12 @@ toChunksWith ::
881917 -> [String ] -- ^ Arguments
882918 -> Stream m (Array Word8 ) -- ^ Output stream
883919toChunksWith modifier path args =
884- pipeChunksWithAction run (modifier . inheritStdin) path args
920+ pipeChunksWithAction run (pipeStdout . modifier . inheritStdin) path args
885921
886922 where
887923
888924 run (_, Just stdoutH, _, _) = toChunksClose stdoutH
889- run _ = error " toChunksWith: Not reachable"
925+ run _ = error " toChunksWith: Not reachable"
890926
891927-- | @toBytesEither path args@ runs the executable at @path@ using @args@ as
892928-- arguments and returns the output of the process as a stream of 'Either'
0 commit comments