1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE RecordWildCards #-}
7import qualified Control.Concurrent as C
8import Control.Exception (Exception, SomeException, handle, throwIO)
9import Control.Monad (replicateM, unless, when)
10import qualified Data.Map as Map
11import qualified Data.Set as Set
12import Data.Version (parseVersion, Version (Version))
13import Data.Typeable (Typeable)
16import System.Directory (copyFile, createDirectory,
17 createDirectoryIfMissing, removeFile)
18import System.Exit (ExitCode (ExitSuccess))
19import System.FilePath ((<.>), (</>))
20import System.IO (IOMode (WriteMode, AppendMode),
22import System.Process (readProcess, runProcess, waitForProcess)
23import Text.ParserCombinators.ReadP (readP_to_S)
25runTestSuites :: BuildSettings -> BuildPlan -> IO ()
26runTestSuites settings' bp = do
27 settings <- fixBuildSettings settings'
28 let selected = Map.filterWithKey notSkipped $ bpPackages bp
29 putStrLn "Running test suites"
30 let testdir = "runtests"
32 createDirectory testdir
33 cabalVersion <- getCabalVersion
34 allPass <- parFoldM (testWorkerThreads settings) (runTestSuite cabalVersion settings testdir) (&&) True $ Map.toList selected
35 unless allPass $ error $ "There were failures, please see the logs in " ++ testdir
37 notSkipped p _ = p `Set.notMember` bpSkippedTests bp
39getCabalVersion :: IO CabalVersion
41 output <- readProcess "cabal" ["--numeric-version"] ""
42 case filter (null . snd) $ readP_to_S parseVersion $ filter notCRLF output of
43 (Version (x:y:_) _, _):_ -> return $ CabalVersion x y
44 _ -> error $ "Invalid cabal version: " ++ show output
50parFoldM :: Int -- ^ number of threads
56parFoldM threadCount0 f g a0 bs0 = do
59 signal <- C.newEmptyMVar
60 tids <- replicateM threadCount0 $ C.forkIO $ worker ma mbs signal
61 wait threadCount0 signal tids
64 worker ma mbs signal =
66 (C.putMVar signal . Just)
67 (loop >> C.putMVar signal Nothing)
70 mb <- C.modifyMVar mbs $ \bs -> return $
73 b:bs' -> (bs', Just b)
78 C.modifyMVar_ ma $ \a -> return $! g a c
80 wait threadCount signal tids
81 | threadCount == 0 = return ()
83 me <- C.takeMVar signal
85 Nothing -> wait (threadCount - 1) signal tids
87 mapM_ C.killThread tids
88 throwIO (e :: SomeException)
90data TestException = TestException
91 deriving (Show, Typeable)
92instance Exception TestException
94data CabalVersion = CabalVersion Int Int
95 deriving (Eq, Ord, Show)
97runTestSuite :: CabalVersion
100 -> (PackageName, SelectedPackageInfo)
102runTestSuite cabalVersion settings testdir (packageName, SelectedPackageInfo {..}) = do
103 -- Set up a new environment that includes the sandboxed bin folder in PATH.
104 env' <- getModifiedEnv settings
106 = Just $ (if addGPP then (("GHC_PACKAGE_PATH", packageDir settings ++ ":"):) else id)
108 -- FIXME why do these packages require the workaround?
109 bannedSandboxVar = map PackageName $ words "wai-logger warp"
111 | packageName `elem` bannedSandboxVar = id
112 | otherwise = (("HASKELL_PACKAGE_SANDBOX", packageDir settings):)
114 let runGen addGPP cmd args wdir handle' = do
115 ph <- runProcess cmd args (Just wdir) (menv addGPP) Nothing (Just handle') (Just handle')
116 ec <- waitForProcess ph
117 unless (ec == ExitSuccess) $ throwIO TestException
119 let run = runGen False
120 runGhcPackagePath = runGen True
122 passed <- handle (\TestException -> return False) $ do
123 package' <- replaceTarball (tarballDir settings) package
124 getHandle WriteMode $ run "cabal" ["unpack", package'] testdir
125 case cabalFileDir settings of
128 let PackageName name = packageName
129 basename = name ++ ".cabal"
130 src = dir </> basename
131 dst = cfd </> basename
132 createDirectoryIfMissing True cfd
134 getHandle AppendMode $ run "cabal" (addCabalArgs settings BSTest ["configure", "--enable-tests"]) dir
135 when spiHasTests $ do
136 getHandle AppendMode $ run "cabal" ["build"] dir
137 getHandle AppendMode $ runGhcPackagePath "cabal" (concat
139 , if cabalVersion >= CabalVersion 1 20
140 then ["--show-details=streaming"] -- FIXME temporary workaround for https://github.com/haskell/cabal/issues/1810
143 when (buildDocs settings) $
144 getHandle AppendMode $ run "cabal" ["haddock"] dir
146 let expectedFailure = packageName `Set.member` expectedFailuresBuild settings
150 when expectedFailure $ putStrLn $ package ++ " passed, but I didn't think it would."
151 else unless expectedFailure $ putStrLn $ concat
152 [ "Test suite failed: "
155 , unMaintainer spiMaintainer
156 , githubMentions spiGithubUser
160 return $! passed || expectedFailure
162 logfile = testdir </> package <.> "log"
163 dir = testdir </> package
164 getHandle mode = withBinaryFile logfile mode
165 package = packageVersionString (packageName, spiVersion)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list