packages feed

interprocess-0.2.1.0: test/Tools/Handle.hs

{-# LANGUAGE LambdaCase #-}
module Tools.Handle (redirectHandle) where

import Control.Exception     (bracket)
import Data.ByteString.Char8 (ByteString, hGetContents)
import GHC.IO.Handle         (hDuplicate, hDuplicateTo, hFlushAll)
import GHC.IO.Handle.Types   (Handle (DuplexHandle, FileHandle))
import System.IO             hiding (hGetContents)
import System.IO.Temp        (withSystemTempFile)

-- | Temporary redirect the output of a handle to an output ByteString (e.g. `stdout` or `stderr`).
redirectHandle :: Handle -> IO a -> IO (ByteString, a)
redirectHandle origHandle action = withSystemTempFile "interprocess.out" $ \_ tempFile -> do
    start <- hGetPosn tempFile
    hGetEncoding origHandle >>= \case
      Just e  -> hSetEncoding tempFile e
      Nothing -> hSetBinaryMode tempFile True
    hSetBuffering tempFile NoBuffering
    hSetNewlineMode tempFile noNewlineTranslation
    r <- bracket (redirect $ hGetWriteEnd tempFile) unredirect (const action)
    r `seq` hFlushAll tempFile
    hSetPosn start
    out <- hGetContents tempFile
    return (out, r)
  where
    redirect tempFile = do
      origDup <- hDuplicate origHandleOut
      hDuplicateTo tempFile origHandleOut
      return origDup

    unredirect origDup = hDuplicateTo origDup origHandleOut >> hClose origDup

    origHandleOut = hGetWriteEnd origHandle

    hGetWriteEnd (DuplexHandle p _ w) = FileHandle p w
    hGetWriteEnd h                    = h