-- | Running actions with explicit input\/output connected to -- @`stdin`@\/@`stdout`@. -- -- This module is inspired by the package . module System.IO.Fake where import Control.DeepSeq import Control.Exception import GHC.IO.Handle import System.Directory import System.IO -- | Perform an action that with access to a temporary file. The file is removed -- after the action is completed. withTempFile :: FilePath -- ^ Path to directory for temporary file -> String -- ^ Base name for temporary file -> ((FilePath,Handle) -> IO a) -- ^ Action -> IO a withTempFile tmpDir base k = bracket (openTempFile tmpDir base) (\(file,h) -> hClose h >> removeFile file) k -- | Perform an action with a redirected handle withRedirect :: Handle -- ^ Shadowing handle -> Handle -- ^ Shadowed handle -> IO a -- ^ Action in which the redirect takes place -> IO a withRedirect new old act = bracket (do buffering <- hGetBuffering old dupH <- hDuplicate old hDuplicateTo new old return (dupH,buffering) ) (\(dupH,buffering) -> do hDuplicateTo dupH old hSetBuffering old buffering hClose dupH ) (\_ -> act) -- | Perform an action with explicit input\/output connected to -- @`stdin`@\/@`stdout`@ fakeIO :: IO a -- ^ Action -> String -- ^ Input to send to @stdin@ -> IO String -- ^ Result from @stdout@ fakeIO act inp = do tmpDir <- getTemporaryDirectory withTempFile tmpDir "fakeInput" $ \(inpFile,inpH) -> withTempFile tmpDir "fakeOutput" $ \(outFile,outH) -> do withRedirect outH stdout $ withRedirect inpH stdin $ do hPutStr inpH inp hSeek inpH AbsoluteSeek 0 act hFlush stdout hSeek outH AbsoluteSeek 0 str <- hGetContents outH str `deepseq` return str