-- | A module adapting the functions from "System.Process" to work with
-- @io-streams@.
module System.IO.Streams.Process
  ( module System.Process
  , runInteractiveCommand
  , runInteractiveProcess
  ) where

------------------------------------------------------------------------------
import           Data.ByteString.Char8         (ByteString)
import           System.IO                     (hClose)
import           System.Process                (CmdSpec (..), CreateProcess (CreateProcess, close_fds, cmdspec, create_group, cwd, std_err, std_in, std_out), ProcessHandle, StdStream (..), createProcess, getProcessExitCode, interruptProcessGroupOf, proc, rawSystem, readProcess, readProcessWithExitCode, runCommand, shell, showCommandForUser, system, terminateProcess, waitForProcess)
------------------------------------------------------------------------------
import qualified System.IO.Streams.Combinators as Streams
import qualified System.IO.Streams.Handle      as Streams
import           System.IO.Streams.Internal    (InputStream, OutputStream)
import qualified System.IO.Streams.Internal    as Streams

import qualified System.Process                as P


------------------------------------------------------------------------------
-- | Runs a command using the shell, and returns streams that may be used to
-- communicate with the process via its stdin, stdout, and stderr respectively.
--
-- The streams returned by this command are guarded by locks and are therefore
-- safe to use in multithreaded code.
--
-- /Since: 1.0.2.0/
--
runInteractiveCommand :: String
                      -> IO (OutputStream ByteString,
                             InputStream ByteString,
                             InputStream ByteString,
                             ProcessHandle)
runInteractiveCommand :: String
-> IO
     (OutputStream ByteString, InputStream ByteString,
      InputStream ByteString, ProcessHandle)
runInteractiveCommand String
scmd = do
    (Handle
hin, Handle
hout, Handle
herr, ProcessHandle
ph) <- String -> IO (Handle, Handle, Handle, ProcessHandle)
P.runInteractiveCommand String
scmd
    OutputStream ByteString
sIn  <- Handle -> IO (OutputStream ByteString)
Streams.handleToOutputStream Handle
hin IO (OutputStream ByteString)
-> (OutputStream ByteString -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            IO () -> OutputStream ByteString -> IO (OutputStream ByteString)
forall b a. IO b -> OutputStream a -> IO (OutputStream a)
Streams.atEndOfOutput (Handle -> IO ()
hClose Handle
hin) IO (OutputStream ByteString)
-> (OutputStream ByteString -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            OutputStream ByteString -> IO (OutputStream ByteString)
forall a. OutputStream a -> IO (OutputStream a)
Streams.lockingOutputStream
    InputStream ByteString
sOut <- Handle -> IO (InputStream ByteString)
Streams.handleToInputStream Handle
hout IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            IO () -> InputStream ByteString -> IO (InputStream ByteString)
forall b a. IO b -> InputStream a -> IO (InputStream a)
Streams.atEndOfInput (Handle -> IO ()
hClose Handle
hout) IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            InputStream ByteString -> IO (InputStream ByteString)
forall a. InputStream a -> IO (InputStream a)
Streams.lockingInputStream
    InputStream ByteString
sErr <- Handle -> IO (InputStream ByteString)
Streams.handleToInputStream Handle
herr IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            IO () -> InputStream ByteString -> IO (InputStream ByteString)
forall b a. IO b -> InputStream a -> IO (InputStream a)
Streams.atEndOfInput (Handle -> IO ()
hClose Handle
herr) IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            InputStream ByteString -> IO (InputStream ByteString)
forall a. InputStream a -> IO (InputStream a)
Streams.lockingInputStream
    (OutputStream ByteString, InputStream ByteString,
 InputStream ByteString, ProcessHandle)
-> IO
     (OutputStream ByteString, InputStream ByteString,
      InputStream ByteString, ProcessHandle)
forall (m :: * -> *) a. Monad m => a -> m a
return (OutputStream ByteString
sIn, InputStream ByteString
sOut, InputStream ByteString
sErr, ProcessHandle
ph)


------------------------------------------------------------------------------
-- | Runs a raw command, and returns streams that may be used to communicate
-- with the process via its @stdin@, @stdout@ and @stderr@ respectively.
--
-- For example, to start a process and feed a string to its stdin:
--
-- > (inp,out,err,pid) <- runInteractiveProcess "..."
-- > forkIO (Streams.write (Just str) inp)
--
-- The streams returned by this command are guarded by locks and are therefore
-- safe to use in multithreaded code.
--
-- /Since: 1.0.2.0/
--
runInteractiveProcess
    :: FilePath                 -- ^ Filename of the executable (see 'proc' for details)
    -> [String]                 -- ^ Arguments to pass to the executable
    -> Maybe FilePath           -- ^ Optional path to the working directory
    -> Maybe [(String,String)]  -- ^ Optional environment (otherwise inherit)
    -> IO (OutputStream ByteString,
           InputStream ByteString,
           InputStream ByteString,
           ProcessHandle)
runInteractiveProcess :: String
-> [String]
-> Maybe String
-> Maybe [(String, String)]
-> IO
     (OutputStream ByteString, InputStream ByteString,
      InputStream ByteString, ProcessHandle)
runInteractiveProcess String
cmd [String]
args Maybe String
wd Maybe [(String, String)]
env = do
    (Handle
hin, Handle
hout, Handle
herr, ProcessHandle
ph) <- String
-> [String]
-> Maybe String
-> Maybe [(String, String)]
-> IO (Handle, Handle, Handle, ProcessHandle)
P.runInteractiveProcess String
cmd [String]
args Maybe String
wd Maybe [(String, String)]
env
    OutputStream ByteString
sIn  <- Handle -> IO (OutputStream ByteString)
Streams.handleToOutputStream Handle
hin IO (OutputStream ByteString)
-> (OutputStream ByteString -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            IO () -> OutputStream ByteString -> IO (OutputStream ByteString)
forall b a. IO b -> OutputStream a -> IO (OutputStream a)
Streams.atEndOfOutput (Handle -> IO ()
hClose Handle
hin) IO (OutputStream ByteString)
-> (OutputStream ByteString -> IO (OutputStream ByteString))
-> IO (OutputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            OutputStream ByteString -> IO (OutputStream ByteString)
forall a. OutputStream a -> IO (OutputStream a)
Streams.lockingOutputStream
    InputStream ByteString
sOut <- Handle -> IO (InputStream ByteString)
Streams.handleToInputStream Handle
hout IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            IO () -> InputStream ByteString -> IO (InputStream ByteString)
forall b a. IO b -> InputStream a -> IO (InputStream a)
Streams.atEndOfInput (Handle -> IO ()
hClose Handle
hout) IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            InputStream ByteString -> IO (InputStream ByteString)
forall a. InputStream a -> IO (InputStream a)
Streams.lockingInputStream
    InputStream ByteString
sErr <- Handle -> IO (InputStream ByteString)
Streams.handleToInputStream Handle
herr IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            IO () -> InputStream ByteString -> IO (InputStream ByteString)
forall b a. IO b -> InputStream a -> IO (InputStream a)
Streams.atEndOfInput (Handle -> IO ()
hClose Handle
herr) IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream ByteString))
-> IO (InputStream ByteString)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
            InputStream ByteString -> IO (InputStream ByteString)
forall a. InputStream a -> IO (InputStream a)
Streams.lockingInputStream
    (OutputStream ByteString, InputStream ByteString,
 InputStream ByteString, ProcessHandle)
-> IO
     (OutputStream ByteString, InputStream ByteString,
      InputStream ByteString, ProcessHandle)
forall (m :: * -> *) a. Monad m => a -> m a
return (OutputStream ByteString
sIn, InputStream ByteString
sOut, InputStream ByteString
sErr, ProcessHandle
ph)