coquina-0.1.0.0: src/Coquina/Internal.hs
module Coquina.Internal where
import Control.Concurrent (MVar, newEmptyMVar, forkIO, putMVar, takeMVar, killThread)
import Control.DeepSeq (rnf)
import Control.Exception (SomeException, evaluate, mask, try, throwIO, onException)
import Data.ByteString (hGetContents)
import Data.Text (Text)
import Data.Text.Encoding (decodeUtf8)
import System.Process
import System.Exit
import System.IO (hClose)
-- | The code below is taken from System.Process which unfortunately does not export this function
withForkWait :: IO () -> (IO () -> IO a) -> IO a
withForkWait async body = do
waitVar <- newEmptyMVar :: IO (MVar (Either SomeException ()))
mask $ \restore -> do
tid <- forkIO $ try (restore async) >>= putMVar waitVar
let wait = takeMVar waitVar >>= either throwIO return
restore (body wait) `onException` killThread tid
-- | Like readCreateProcess, but ignores stdin and decodes bytes, assuming utf-8
readAndDecodeCreateProcess :: CreateProcess -> IO (ExitCode, Text, Text)
readAndDecodeCreateProcess cp =
withCreateProcess (cp { std_out = CreatePipe, std_err = CreatePipe }) $ \_ mouth merrh ph -> case (mouth, merrh) of
(Just outh, Just errh) -> do
out <- fmap decodeUtf8 $ hGetContents outh
err <- fmap decodeUtf8 $ hGetContents errh
withForkWait (evaluate $ rnf out) $ \waitOut ->
withForkWait (evaluate $ rnf err) $ \waitErr -> do
waitOut
waitErr
hClose outh
hClose errh
exitCode <- waitForProcess ph
return (exitCode, out, err)
(Nothing, _) -> error "readAndDecodeCreateProcess: Failed to get std_out handle"
(Just _, Nothing) -> error "readAndDecodeCreateProcess: Failed to get std_err handle"