I have a program that I want to run and wait for it to initialize before proceeding, but I also want the program to write to the terminal as usual, which it would do if I simply called it with callProcess. To this end, I have devised the following hack:
(In this case I listen to the standard error, but I suppose this is inessential.)
…
withCreateProcess applicationProcessDescription \ _ _ maybeApplicationStdErr _ -> do
case maybeApplicationStdErr of
Nothing -> throwIO $ DeploymentException $ "Unable to grab application's standard error stream!"
Just applicationStdErr -> do
maybeTimeout <- timeout waitingTime (waitForApplication applicationStdErr)
when (isNothing maybeTimeout) $ throwIO $ DeploymentException $ "Application took too long initializing!"
redirectHandle applicationStdErr stderr
…
waitForApplication :: Handle -> IO ( )
waitForApplication stdErr = do
line <- hGetLine stdErr
hPutStrLn stderr line
if line == "Application initialized."
then return ( )
else waitForApplication stdErr
redirectHandle :: Handle -> Handle -> IO ( )
redirectHandle from to = void $ forkFinally
do forever do
line <- hGetLine from
hPutStrLn to line
\ _ -> return ( )
I intercept whatever the subprocess is saying, line by line, analyze the lines in some way and put them to the main process's standard error. When I am done, I still have to keep listening and relaying. This seems like an absurd way of going about it.
What I would like to do is fork the subprocess's standard error stream in some way, so that I may eavesdrop on it passively while I need to, and then simply disconnect. It is important for me that whatever the subprocess is saying was delivered to the human as faithfully as possible — without delay and omission.
Is there a nice way to do it?