--- /dev/null
+module IOStuff (interactWithCommand) where
+import System.IO
+import System.Process
+import System.Exit
+import Control.Concurrent
+import Control.Concurrent.MVar
+
+-- Like hGetContents but reads all the input before returning, resulting in
+-- more predictable behavior.
+hStrictGetContents :: Handle -> IO String
+hStrictGetContents h = do
+ c <- hGetContents h
+ -- Note to self: The seq has to be *outside* the return. Otherwise the
+ -- seqified thunk will just be returned to the caller, defeating the
+ -- purpose.
+ seq (length c) $ return c
+
+interactWithCommand :: String -> String -> IO String
+interactWithCommand cmd inData = do
+ (inH, outH, errH, pid) <- runInteractiveCommand cmd
+ forkIO (do
+ hPutStr inH inData
+ hClose inH)
+ outDataMV <- newEmptyMVar
+ forkIO (do
+ outData <- hStrictGetContents outH
+ putMVar outDataMV outData)
+ errDataMV <- newEmptyMVar
+ forkIO (do
+ errData <- hStrictGetContents errH
+ putMVar errDataMV errData)
+ outData <- takeMVar outDataMV
+ errData <- takeMVar errDataMV
+ ex <- waitForProcess pid
+ if ex == ExitSuccess && length errData == 0
+ then return outData
+ else error $ "Command " ++ show cmd ++ " failed: "
+ ++ "stderr " ++ show errData ++ ", exit " ++ show ex