@@ -10,27 +10,24 @@ module StackTest.Repl
10
10
, replGetLine
11
11
) where
12
12
13
- import Control.Concurrent (forkIO )
14
- import Control.Exception (throw , catch )
15
- import Control.Monad (forever , unless , when )
13
+ import Control.Monad (unless , when )
16
14
import Control.Monad.IO.Class (liftIO )
17
15
import Data.Maybe (fromMaybe )
18
16
import GHC.Stack (HasCallStack )
19
17
import System.Environment (lookupEnv )
20
18
import System.Exit (ExitCode (.. ))
21
19
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
25
23
)
26
- import System.IO.Error (isEOFError )
27
24
28
25
import Control.Monad.Trans (lift )
29
26
import Control.Monad.Trans.Reader
30
27
import Control.Monad.Trans.State qualified as State
31
28
import System.Process
32
29
( CreateProcess (std_err , std_in , std_out )
33
- , StdStream (CreatePipe )
30
+ , StdStream (CreatePipe , UseHandle )
34
31
, createProcess , proc , waitForProcess
35
32
)
36
33
@@ -43,6 +40,16 @@ data ReplConnection = ReplConnection
43
40
, replStdout :: Handle
44
41
}
45
42
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
+
46
53
nextPrompt :: Repl ()
47
54
nextPrompt = State. evalStateT poll " " where
48
55
poll = do
@@ -55,42 +62,28 @@ nextPrompt = State.evalStateT poll "" where
55
62
unless (buf == " ghci> " )
56
63
poll
57
64
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
-
66
65
runRepl
67
66
:: HasCallStack
68
67
=> FilePath
69
68
-> [String ]
70
69
-> Repl ()
71
70
-> IO ExitCode
72
71
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) <-
75
80
createProcess (proc cmd args)
76
81
{ std_in = CreatePipe
77
82
, std_out = CreatePipe
78
- , std_err = CreatePipe
83
+ , std_err = UseHandle stderrBufHandle
79
84
}
80
85
hSetBuffering rStdin LineBuffering
81
86
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)
94
87
95
88
-- run the test script which is to talk to the GHCi subprocess.
96
89
runReaderT actions (ReplConnection rStdin rStdout)
@@ -100,6 +93,13 @@ runRepl cmd args actions = do
100
93
-- read out the exit-code
101
94
waitForProcess ph
102
95
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
+
103
103
repl :: HasCallStack => [String ] -> Repl () -> IO ()
104
104
repl args action = do
105
105
stackExe' <- stackExe
0 commit comments