module System.Command.QQ.Eval
( Eval(..)
) where
import Control.Applicative
import Control.Concurrent
import Control.Exception (evaluate)
import Control.Monad
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.IO as T
import System.Exit (ExitCode)
import qualified System.Process as P
import System.IO (hFlush, hClose)
class Eval r where
eval :: String -> [String] -> r
instance Eval (IO ()) where
eval command args = () <$ P.rawSystem command args
instance Eval (IO ExitCode) where
eval command args = do
(s, _, _) <- eval command args (T.pack "")
return s
instance Eval (IO Text) where
eval command args = do
(_, o, _) <- eval command args
return o
instance Eval (IO String) where
eval command args = T.unpack <$> eval command args
instance
( s ~ ExitCode
, o ~ Text
, e ~ Text
) => Eval (IO (s, o, e)) where
eval command args = eval command args (T.pack "")
instance
( i ~ Text
, o ~ (ExitCode, Text, Text)
) => Eval (i -> IO o) where
eval = readProcessWithExitCode
readProcessWithExitCode :: String -> [String] -> Text -> IO (ExitCode, Text, Text)
readProcessWithExitCode cmd args input = do
(Just ih, Just oh, Just eh, p) <-
P.createProcess (P.proc cmd args)
{ P.std_in = P.CreatePipe
, P.std_out = P.CreatePipe
, P.std_err = P.CreatePipe
}
m <- newEmptyMVar
o <- T.hGetContents oh
e <- T.hGetContents eh
forkFinally (evaluate (T.length o)) (\_ -> putMVar m ())
forkFinally (evaluate (T.length e)) (\_ -> putMVar m ())
unless (T.null input) $ do
T.hPutStr ih input
hFlush ih
hClose ih
takeMVar m
takeMVar m
hClose oh
hClose eh
s <- P.waitForProcess p
return (s, o, e)