|
|
@@ -25,6 +25,7 @@ import "unix" System.Posix.IO.ByteString |
|
|
|
import qualified System.Posix.Process.ByteString |
|
|
|
as SPPB |
|
|
|
import System.Posix.Directory.ByteString |
|
|
|
import System.Posix.Process ( ProcessStatus(..) ) |
|
|
|
import System.Posix.Types |
|
|
|
|
|
|
|
import qualified Streamly.Internal.Memory.ArrayStream |
|
|
@@ -42,10 +43,17 @@ import Control.Concurrent |
|
|
|
import System.Posix.FD as FD |
|
|
|
|
|
|
|
|
|
|
|
data ProcessError = NonZeroExit Int |
|
|
|
| PTerminated |
|
|
|
| PStopped |
|
|
|
| NoSuchPid |
|
|
|
deriving Show |
|
|
|
|
|
|
|
|
|
|
|
data CapturedProcess = CapturedProcess { |
|
|
|
_exitCode :: ExitCode |
|
|
|
, _stdOut :: L.ByteString |
|
|
|
, _stdErr :: L.ByteString |
|
|
|
, _stdOut :: ByteString |
|
|
|
, _stdErr :: ByteString |
|
|
|
} deriving (Eq, Show) |
|
|
|
|
|
|
|
makeLenses ''CapturedProcess |
|
|
@@ -92,10 +100,9 @@ executeOut :: Path Rel -- ^ command as filename, e.g. 'ls' |
|
|
|
-> [ByteString] -- ^ arguments to the command |
|
|
|
-> Maybe (Path Abs) -- ^ chdir to this path |
|
|
|
-> IO (Maybe CapturedProcess) |
|
|
|
executeOut path args chdir = withRelPath path |
|
|
|
$ \fp -> captureOutStreams $ do |
|
|
|
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir |
|
|
|
SPPB.executeFile fp True args Nothing |
|
|
|
executeOut path args chdir = withRelPath path $ \fp -> captureOutStreams $ do |
|
|
|
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir |
|
|
|
SPPB.executeFile fp True args Nothing |
|
|
|
|
|
|
|
|
|
|
|
-- | Capture the stdout and stderr of the given action, which |
|
|
@@ -108,9 +115,6 @@ captureOutStreams action = |
|
|
|
actionWithPipes $ \(parentStdoutRead, childStdoutWrite) -> |
|
|
|
actionWithPipes $ \(parentStderrRead, childStderrWrite) -> do |
|
|
|
pid <- SPPB.forkProcess $ do |
|
|
|
-- don't mess up stdin from the parent |
|
|
|
closeFd stdInput |
|
|
|
|
|
|
|
-- dup stdout |
|
|
|
void $ dupTo childStdoutWrite stdOutput |
|
|
|
closeFd childStdoutWrite |
|
|
@@ -131,8 +135,8 @@ captureOutStreams action = |
|
|
|
SPPB.getProcessStatus True True pid >>= \case |
|
|
|
-- readFd will take care of closing the fd |
|
|
|
Just (SPPB.Exited es) -> do |
|
|
|
stdout' <- readFd parentStdoutRead |
|
|
|
stderr' <- readFd parentStderrRead |
|
|
|
stdout' <- L.toStrict <$> readFd parentStdoutRead |
|
|
|
stderr' <- L.toStrict <$> readFd parentStderrRead |
|
|
|
pure $ Just $ CapturedProcess { _exitCode = es |
|
|
|
, _stdOut = stdout' |
|
|
|
, _stdErr = stderr' |
|
|
@@ -153,3 +157,26 @@ captureOutStreams action = |
|
|
|
createRegularFileFd :: FileMode -> Path b -> IO Fd |
|
|
|
createRegularFileFd fm dest = |
|
|
|
FD.openFd (toFilePath dest) WriteOnly [oExcl] (Just fm) |
|
|
|
|
|
|
|
|
|
|
|
exe :: ByteString |
|
|
|
-> [ByteString] |
|
|
|
-> Bool |
|
|
|
-> Maybe (Path Abs) |
|
|
|
-> IO (Either ProcessError ()) |
|
|
|
exe exe' args spath chdir = do |
|
|
|
pid <- SPPB.forkProcess $ do |
|
|
|
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir |
|
|
|
SPPB.executeFile exe' spath args Nothing |
|
|
|
|
|
|
|
fmap toProcessError $ SPPB.getProcessStatus True True pid |
|
|
|
|
|
|
|
|
|
|
|
toProcessError :: Maybe ProcessStatus -> Either ProcessError () |
|
|
|
toProcessError mps = case mps of |
|
|
|
Just (SPPB.Exited (ExitFailure i)) -> Left $ NonZeroExit i |
|
|
|
Just (SPPB.Exited ExitSuccess ) -> Right () |
|
|
|
Just (Terminated _ _ ) -> Left $ PTerminated |
|
|
|
Just (Stopped _ ) -> Left $ PStopped |
|
|
|
Nothing -> Left $ NoSuchPid |
|
|
|
|