diff options
Diffstat (limited to 'Process.hs')
| -rw-r--r-- | Process.hs | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/Process.hs b/Process.hs new file mode 100644 index 0000000..e4f55d1 --- /dev/null +++ b/Process.hs @@ -0,0 +1,52 @@ +module Process (mkProcess) where + +import Control.Concurrent.Async (async, cancel) +import Control.Concurrent.Chan.Unagi (newChan, readChan, writeChan) +import Control.Exception (IOException) +import Control.Monad (forever, unless) +import Data.Bifunctor (bimap) +import Data.ByteString (ByteString) +import Data.ByteString.Char8 qualified as BS8 +import System.IO (hClose, hIsEOF) +import System.Process qualified as P + +mkProcess :: FilePath -> [String] -> IO (IO (Either IOException ByteString), IO ()) +mkProcess prog args = do + (Just hin, Just hout, Just herr, ph) <- + P.createProcess (P.proc prog args) + { P.std_in = P.CreatePipe + , P.std_out = P.CreatePipe + , P.std_err = P.CreatePipe + } + + (putOutput, takeOutput) <- bimap writeChan readChan <$> newChan + + let reader h = forever do + eof <- hIsEOF h + unless eof do + BS8.hGetLine h >>= putOutput -- TODO mark as stdout/stderr + + outReader <- async (reader hout) + errReader <- async (reader herr) + + let + -- normal termination path: wait for process, then kill readers + waitProcessAndReaders = do + _ <- P.waitForProcess ph + shutdown + --cancel outReader + --cancel errReader + + -- explicit shutdown: kill everything + shutdown = do + P.terminateProcess ph + cancel outReader + cancel errReader + hClose hin + hClose hout + hClose herr + + -- optionally run waitProcessAndReaders in background: + _ <- async waitProcessAndReaders + + pure (Right <$> takeOutput, shutdown) |
