Skip to content

Commit 368a0e7

Browse files
committed
tests: redirect stderr, instead of shuffling bytes one-by-one
1 parent 609205c commit 368a0e7

File tree

1 file changed

+31
-31
lines changed
  • tests/integration/lib/StackTest

1 file changed

+31
-31
lines changed

tests/integration/lib/StackTest/Repl.hs

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,24 @@ module StackTest.Repl
1010
, replGetLine
1111
) where
1212

13-
import Control.Concurrent (forkIO)
14-
import Control.Exception (throw, catch)
15-
import Control.Monad (forever, unless, when)
13+
import Control.Monad (unless, when)
1614
import Control.Monad.IO.Class (liftIO)
1715
import Data.Maybe (fromMaybe)
1816
import GHC.Stack (HasCallStack)
1917
import System.Environment (lookupEnv)
2018
import System.Exit (ExitCode (..))
2119
import System.IO
22-
( BufferMode (NoBuffering, LineBuffering), Handle, IOMode (WriteMode)
23-
, hClose, hGetChar, hGetLine, hPutChar, hPutStrLn, hSetBuffering
24-
, withFile
20+
( BufferMode (NoBuffering, LineBuffering), Handle
21+
, hClose, hGetChar, hGetLine, hPutStrLn, hSetBuffering
22+
, openTempFile
2523
)
26-
import System.IO.Error (isEOFError)
2724

2825
import Control.Monad.Trans (lift)
2926
import Control.Monad.Trans.Reader
3027
import Control.Monad.Trans.State qualified as State
3128
import System.Process
3229
( CreateProcess (std_err, std_in, std_out)
33-
, StdStream (CreatePipe)
30+
, StdStream (CreatePipe, UseHandle)
3431
, createProcess, proc, waitForProcess
3532
)
3633

@@ -43,6 +40,16 @@ data ReplConnection = ReplConnection
4340
, replStdout :: Handle
4441
}
4542

43+
replCommand :: String -> Repl ()
44+
replCommand cmd = do
45+
(ReplConnection replStdinHandle _) <- ask
46+
-- echo what we send to the test's stdout
47+
liftIO . putStrLn $ "____> " <> cmd
48+
liftIO $ hPutStrLn replStdinHandle cmd
49+
50+
replGetLine :: Repl String
51+
replGetLine = ask >>= liftIO . hGetLine . replStdout
52+
4653
nextPrompt :: Repl ()
4754
nextPrompt = State.evalStateT poll "" where
4855
poll = do
@@ -55,42 +62,28 @@ nextPrompt = State.evalStateT poll "" where
5562
unless (buf == "ghci> ")
5663
poll
5764

58-
replCommand :: String -> Repl ()
59-
replCommand cmd = do
60-
(ReplConnection replStdinHandle _) <- ask
61-
liftIO $ hPutStrLn replStdinHandle cmd
62-
63-
replGetLine :: Repl String
64-
replGetLine = ask >>= liftIO . hGetLine . replStdout
65-
6665
runRepl
6766
:: HasCallStack
6867
=> FilePath
6968
-> [String]
7069
-> Repl ()
7170
-> IO ExitCode
7271
runRepl cmd args actions = do
73-
logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args)
74-
(Just rStdin, Just rStdout, Just rStderr, ph) <-
72+
(stderrBufPath, stderrBufHandle) <- openTempStderrBufferFile
73+
hSetBuffering stderrBufHandle NoBuffering
74+
75+
logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args) ++ "\n\
76+
\ with stderr in " ++ stderrBufPath
77+
78+
-- launch the GHCi subprocess, grab its FD handles and process handle
79+
(Just rStdin, Just rStdout, Nothing, ph) <-
7580
createProcess (proc cmd args)
7681
{ std_in = CreatePipe
7782
, std_out = CreatePipe
78-
, std_err = CreatePipe
83+
, std_err = UseHandle stderrBufHandle
7984
}
8085
hSetBuffering rStdin LineBuffering
8186
hSetBuffering rStdout NoBuffering
82-
hSetBuffering rStderr NoBuffering
83-
-- Log stack repl's standard error output
84-
tempDir <- if isWindows
85-
then fromMaybe "" <$> lookupEnv "TEMP"
86-
else pure "/tmp"
87-
let tempLogFile = tempDir ++ "/stderr"
88-
_ <- forkIO $ withFile tempLogFile WriteMode $ \logFileHandle -> do
89-
--hSetBuffering logFileHandle NoBuffering
90-
forever $
91-
catch
92-
(hGetChar rStderr >>= hPutChar logFileHandle)
93-
(\e -> unless (isEOFError e) $ throw e)
9487

9588
-- run the test script which is to talk to the GHCi subprocess.
9689
runReaderT actions (ReplConnection rStdin rStdout)
@@ -100,6 +93,13 @@ runRepl cmd args actions = do
10093
-- read out the exit-code
10194
waitForProcess ph
10295

96+
-- | Roll a bicycle, rather than just `import Path.IO (getTempDir, openTempFile)`,
97+
-- because it's a hassle to use anything beyond base & boot libs here.
98+
openTempStderrBufferFile :: IO (FilePath, Handle)
99+
openTempStderrBufferFile = getTempDir >>= (`openTempFile` "err.log") where
100+
getTempDir | isWindows = fromMaybe "" <$> lookupEnv "TEMP"
101+
| otherwise = pure "/tmp"
102+
103103
repl :: HasCallStack => [String] -> Repl () -> IO ()
104104
repl args action = do
105105
stackExe' <- stackExe

0 commit comments

Comments
 (0)