Skip to content

Commit 7a20ce7

Browse files
committed
Refactor build code to use process utilities
Initially, this was in preparation for a resolution to #1635. However, I I don't think I'll be using the approach of sending stderr / stdout via logging. Some tests could emit tons of output, and I'd rather avoid the overhead.
1 parent c8f6ce0 commit 7a20ce7

File tree

2 files changed

+62
-93
lines changed

2 files changed

+62
-93
lines changed

src/Stack/Build/Execute.hs

Lines changed: 32 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -842,63 +842,39 @@ withSingleContext runInBase ActionContext {..} ExecuteEnv {..} task@Task {..} md
842842
++ ["-package-db=" ++ toFilePathNoTrailingSep (bcoSnapDB eeBaseConfigOpts)]
843843

844844
setupArgs = ("--builddir=" ++ toFilePathNoTrailingSep distRelativeDir') : args
845-
runExe exeName fullArgs = do
846-
$logProcessRun (toFilePath exeName) fullArgs
847-
848-
-- Use createProcess_ to avoid the log file being closed afterwards
849-
(Nothing, moutH, merrH, ph) <- liftIO $ createProcess_ "singleBuild" cp
850-
851-
let makeAbsolute = stripTHLoading -- If users want control, we should add a config option for this
852-
853-
ec <-
854-
liftIO $
855-
withAsync (runInBase $ maybePrintBuildOutput stripTHLoading makeAbsolute pkgDir LevelInfo mlogFile moutH) $ \outThreadID ->
856-
withAsync (runInBase $ maybePrintBuildOutput False makeAbsolute pkgDir LevelWarn mlogFile merrH) $ \errThreadID -> do
857-
ec <- waitForProcess ph
858-
wait errThreadID
859-
wait outThreadID
860-
return ec
861-
case ec of
862-
ExitSuccess -> return ()
863-
_ -> do
864-
bss <-
865-
case mlogFile of
866-
Nothing -> return []
867-
Just (logFile, h) -> do
868-
liftIO $ hClose h
869-
runResourceT
870-
$ CB.sourceFile (toFilePath logFile)
871-
=$= CT.decodeUtf8
872-
$$ mungeBuildOutput stripTHLoading makeAbsolute pkgDir
873-
=$ CL.consume
874-
throwM $ CabalExitedUnsuccessfully
875-
ec
876-
taskProvides
877-
exeName
878-
fullArgs
879-
(fmap fst mlogFile)
880-
bss
881-
where
882-
cp0 = proc (toFilePath exeName) fullArgs
883-
cp = cp0
884-
{ cwd = Just $ toFilePath pkgDir
885-
, Process.env = envHelper menv
886-
-- Ideally we'd create a new pipe here and then close it
887-
-- below to avoid the child process from taking from our
888-
-- stdin. However, if we do this, the child process won't
889-
-- be able to get the codepage on Windows that we want.
890-
-- See:
891-
-- https://github.com/commercialhaskell/stack/issues/738
892-
-- , std_in = CreatePipe
893-
, std_out =
894-
case mlogFile of
895-
Nothing -> CreatePipe
896-
Just (_, h) -> UseHandle h
897-
, std_err =
845+
runExe exeName fullArgs =
846+
runAndOutput `catch` \(ProcessExitedUnsuccessfully _ ec) -> do
847+
bss <-
898848
case mlogFile of
899-
Nothing -> CreatePipe
900-
Just (_, h) -> UseHandle h
901-
}
849+
Nothing -> return []
850+
Just (logFile, h) -> do
851+
liftIO $ hClose h
852+
runResourceT
853+
$ CB.sourceFile (toFilePath logFile)
854+
=$= CT.decodeUtf8
855+
$$ mungeBuildOutput stripTHLoading makeAbsolute pkgDir
856+
=$ CL.consume
857+
throwM $ CabalExitedUnsuccessfully
858+
ec
859+
taskProvides
860+
exeName
861+
fullArgs
862+
(fmap fst mlogFile)
863+
bss
864+
where
865+
runAndOutput = case mlogFile of
866+
Just (_, h) ->
867+
sinkProcessStderrStdoutHandle (Just pkgDir) menv (toFilePath exeName) fullArgs h h
868+
Nothing ->
869+
void $ sinkProcessStderrStdout (Just pkgDir) menv (toFilePath exeName) fullArgs
870+
(outputSink False LevelWarn)
871+
(outputSink stripTHLoading LevelInfo)
872+
outputSink excludeTH level =
873+
CT.decodeUtf8
874+
=$ mungeBuildOutput excludeTH makeAbsolute pkgDir
875+
=$ CL.mapM_ (runInBase . monadLoggerLog $(TH.location >>= liftLoc) "" level)
876+
-- If users want control, we should add a config option for this
877+
makeAbsolute = stripTHLoading
902878

903879
wc <- getWhichCompiler
904880
(exeName, fullArgs) <- case (esetupexehs, wc) of
@@ -927,14 +903,6 @@ withSingleContext runInBase ActionContext {..} ExecuteEnv {..} task@Task {..} md
927903
return (outputFile, setupArgs)
928904
runExe exeName $ (if boptsCabalVerbose eeBuildOpts then ("--verbose":) else id) fullArgs
929905

930-
maybePrintBuildOutput stripTHLoading makeAbsolute pkgDir level mlogFile mh =
931-
case mh of
932-
Just h ->
933-
case mlogFile of
934-
Just{} -> return ()
935-
Nothing -> printBuildOutput stripTHLoading makeAbsolute pkgDir level h
936-
Nothing -> return ()
937-
938906
singleBuild :: M env m
939907
=> (m () -> IO ())
940908
-> ActionContext
@@ -1356,23 +1324,6 @@ singleBench runInBase beopts benchesToRun ac ee task installedMap = do
13561324
announce "benchmarks"
13571325
cabal False ("bench" : args)
13581326

1359-
-- | Grab all output from the given @Handle@ and log it, stripping
1360-
-- Template Haskell "Loading package" lines and making paths absolute.
1361-
-- thread.
1362-
printBuildOutput :: (MonadIO m, MonadBaseControl IO m, MonadLogger m,
1363-
MonadThrow m)
1364-
=> Bool -- ^ exclude TH loading?
1365-
-> Bool -- ^ convert paths to absolute?
1366-
-> Path Abs Dir -- ^ package's root directory
1367-
-> LogLevel
1368-
-> Handle
1369-
-> m ()
1370-
printBuildOutput excludeTHLoading makeAbsolute pkgDir level outH = void $
1371-
CB.sourceHandle outH
1372-
$$ CT.decodeUtf8
1373-
=$ mungeBuildOutput excludeTHLoading makeAbsolute pkgDir
1374-
=$ CL.mapM_ (monadLoggerLog $(TH.location >>= liftLoc) "" level)
1375-
13761327
-- | Strip Template Haskell "Loading package" lines and making paths absolute.
13771328
mungeBuildOutput :: (MonadIO m, MonadThrow m)
13781329
=> Bool -- ^ exclude TH loading?

src/System/Process/Read.hs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module System.Process.Read
1414
,tryProcessStdout
1515
,sinkProcessStdout
1616
,sinkProcessStderrStdout
17+
,sinkProcessStderrStdoutHandle
1718
,readProcess
1819
,EnvOverride(..)
1920
,unEnvOverride
@@ -34,9 +35,8 @@ module System.Process.Read
3435
)
3536
where
3637

37-
import Control.Applicative
3838
import Control.Arrow ((***), first)
39-
import Control.Concurrent.Async (Concurrently (..))
39+
import Control.Concurrent.Async (concurrently)
4040
import Control.Exception hiding (try, catch)
4141
import Control.Monad (join, liftM, unless)
4242
import Control.Monad.Catch (MonadThrow, MonadCatch, throwM, try, catch)
@@ -69,6 +69,7 @@ import System.Directory (doesFileExist, getCurrentDirectory)
6969
import System.Environment (getEnvironment)
7070
import System.Exit
7171
import qualified System.FilePath as FP
72+
import System.IO (Handle)
7273
import System.Process.Log
7374

7475
-- | Override the environment received by a child process.
@@ -256,7 +257,7 @@ sinkProcessStdout wd menv name args sinkStdout = do
256257
return sinkRet
257258

258259
-- | Consume the stdout and stderr of a process feeding strict 'S.ByteString's to the consumers.
259-
sinkProcessStderrStdout :: (MonadIO m, MonadLogger m)
260+
sinkProcessStderrStdout :: forall m e o. (MonadIO m, MonadLogger m)
260261
=> Maybe (Path Abs Dir) -- ^ Optional directory to run in
261262
-> EnvOverride
262263
-> String -- ^ Command
@@ -267,15 +268,32 @@ sinkProcessStderrStdout :: (MonadIO m, MonadLogger m)
267268
sinkProcessStderrStdout wd menv name args sinkStderr sinkStdout = do
268269
$logProcessRun name args
269270
name' <- preProcess wd menv name
270-
liftIO (withCheckedProcess
271-
(proc name' args) { env = envHelper menv, cwd = fmap toFilePath wd }
272-
(\ClosedStream out err ->
273-
runConcurrently $
274-
(,) <$>
275-
Concurrently (asBSSource err $$ sinkStderr) <*>
276-
Concurrently (asBSSource out $$ sinkStdout)))
277-
where asBSSource :: Source m S.ByteString -> Source m S.ByteString
278-
asBSSource = id
271+
liftIO $ withCheckedProcess
272+
(proc name' args) { env = envHelper menv, cwd = fmap toFilePath wd }
273+
(\ClosedStream out err -> f err out)
274+
where
275+
f :: Source IO S.ByteString -> Source IO S.ByteString -> IO (e, o)
276+
f err out = (err $$ sinkStderr) `concurrently` (out $$ sinkStdout)
277+
278+
sinkProcessStderrStdoutHandle :: (MonadIO m, MonadLogger m)
279+
=> Maybe (Path Abs Dir) -- ^ Optional directory to run in
280+
-> EnvOverride
281+
-> String -- ^ Command
282+
-> [String] -- ^ Command line arguments
283+
-> Handle
284+
-> Handle
285+
-> m ()
286+
sinkProcessStderrStdoutHandle wd menv name args err out = do
287+
$logProcessRun name args
288+
name' <- preProcess wd menv name
289+
liftIO $ withCheckedProcess
290+
(proc name' args)
291+
{ env = envHelper menv
292+
, cwd = fmap toFilePath wd
293+
, std_err = UseHandle err
294+
, std_out = UseHandle out
295+
}
296+
(\ClosedStream UseProvidedHandle UseProvidedHandle -> return ())
279297

280298
-- | Perform pre-call-process tasks. Ensure the working directory exists and find the
281299
-- executable path.

0 commit comments

Comments
 (0)