summaryrefslogtreecommitdiffstats
path: root/Process.hs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-02-09 03:48:15 +0100
committertv <tv@krebsco.de>2026-02-09 03:48:15 +0100
commit6edeb752c80bb4a9cd7e27672f773fe3d66b2039 (patch)
tree0032daadc3986873e756bcb2be3dd21c7aa3e600 /Process.hs
initial commit
Diffstat (limited to 'Process.hs')
-rw-r--r--Process.hs52
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)