@@ -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 cleanupCfg cfg) = Config cleanupCfg $ cfg { std_in = CreatePipe }
478+
479+ pipeStdout :: Config -> Config
480+ pipeStdout (Config cleanupCfg cfg) = Config cleanupCfg $ 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
@@ -853,6 +878,10 @@ pipeChars path args input =
853878-- Generation
854879-------------------------------------------------------------------------------
855880
881+ -- Note: It is allowed to inheritStdout or inheritStderr but not both as that
882+ -- would not generate a stream for further processing and would result in unintuitive
883+ -- behaviour
884+
856885-- | Like 'toChunksEither' but use the specified configuration to run the
857886-- process.
858887{-# INLINE toChunksEitherWith #-}
@@ -863,14 +892,18 @@ toChunksEitherWith ::
863892 -> [String ] -- ^ Arguments
864893 -> Stream m (Either (Array Word8 ) (Array Word8 )) -- ^ Output stream
865894toChunksEitherWith modifier path args =
866- pipeChunksWithAction run (modifier . inheritStdin . pipeStdErr) path args
895+ pipeChunksWithAction run (modifier . inheritStdin . pipeStdErr . pipeStdout ) path args
867896
868897 where
869898
870- run (_, Just stdoutH, Just stderrH, _) =
871- fmap Left (toChunksClose stderrH)
872- `parallel` fmap Right (toChunksClose stdoutH)
873- run _ = error " toChunksEitherWith: Not reachable"
899+ run (_, Nothing , Nothing , _) =
900+ error " toChunksEitherWith: only one of stdout or stderr can be inherited"
901+ run (_, stdoutMaybe, stderrMaybe, _) =
902+ fmap Left (whenJustS toChunksClose stderrMaybe)
903+ `parallel` fmap Right (whenJustS toChunksClose stdoutMaybe)
904+
905+ -- Note: inheritStdout has no affect, we always pipe stdout to the resulting
906+ -- stream
874907
875908-- | Like 'toChunks' but use the specified configuration to run the process.
876909{-# INLINE toChunksWith #-}
@@ -881,12 +914,12 @@ toChunksWith ::
881914 -> [String ] -- ^ Arguments
882915 -> Stream m (Array Word8 ) -- ^ Output stream
883916toChunksWith modifier path args =
884- pipeChunksWithAction run (modifier . inheritStdin) path args
917+ pipeChunksWithAction run (pipeStdout . modifier . inheritStdin) path args
885918
886919 where
887920
888921 run (_, Just stdoutH, _, _) = toChunksClose stdoutH
889- run _ = error " toChunksWith: Not reachable"
922+ run _ = error " toChunksWith: Not reachable"
890923
891924-- | @toBytesEither path args@ runs the executable at @path@ using @args@ as
892925-- arguments and returns the output of the process as a stream of 'Either'
@@ -1193,3 +1226,7 @@ daemon modCfg path args =
11931226 (setSession NewSession . modCfg)
11941227 path args
11951228 in fmap (either undefined id ) r
1229+
1230+
1231+ whenJustS :: Applicative m => (a -> Stream m b ) -> Maybe a -> Stream m b
1232+ whenJustS action mb = maybe Stream. nil action mb
0 commit comments