on master help sign in
Build plan created separately (partway to #25)
commitfb2385dd9c5132e2c34973ef823acc741d70f86e authorMichael Snoyman <michael@snoyman.com> dateThu 24 Jan 2013, 17:35 (14 years ago) parent2ba0b0e
13 files changed+378−84
Stackage/Build.hs+22−39 Stackage/BuildPlan.hs+139 Stackage/CheckCabalVersion.hs+45 Stackage/CheckPlan.hs+5−5 Stackage/InstallInfo.hs+20−8 Stackage/NarrowDatabase.hs+2 Stackage/Select.hs+74 Stackage/Tarballs.hs+6−6 Stackage/Test.hs+18−13 Stackage/Types.hs+20−3 Stackage/Util.hs+21−3 app/stackage.hs+3−7 stackage.cabal+3
Stackage/Build.hs+22−39
@@ -28,6 +28,8 @@ import System.IO (IOMode (WriteMode), hPutStrLn,
2828 withBinaryFile)
2929import System.Process (rawSystem, readProcess, runProcess,
3030 waitForProcess)
31+import Stackage.Select (select)
32+import Stackage.CheckCabalVersion (checkCabalVersion)
3133
3234defaultBuildSettings :: BuildSettings
3335defaultBuildSettings = BuildSettings
@@ -39,7 +41,6 @@ defaultBuildSettings = BuildSettings
3941 , extraArgs = ["-fnetwork23"]
4042 , haskellPlatformCabal = "haskell-platform/haskell-platform.cabal"
4143 , requireHaskellPlatform = True
42− , cleanBeforeBuild = True
4344 , excludedPackages = empty
4445 , testWorkerThreads = 4
4546 , flags = Set.fromList $ words "blaze_html_0_5"
@@ -48,49 +49,31 @@ defaultBuildSettings = BuildSettings
4849
4950build :: BuildSettings -> IO ()
5051build settings' = do
51− ii <- getInstallInfo settings'
52+ putStrLn "Checking Cabal version"
53+ libVersion <- checkCabalVersion
5254
53− let root' = sandboxRoot settings'
54− initPkgDb <- if cleanBeforeBuild settings'
55− then do
56− putStrLn "Wiping out old sandbox folder"
57− rm_r root'
58− rm_r "logs"
59− return True
60− else do
61− b <- doesDirectoryExist root'
62− when b (putStrLn "Re-using existing sandbox")
63− return (not b)
64− createDirectoryIfMissing True root'
65− root <- canonicalizePath root'
66− let settings = settings' { sandboxRoot = root }
55+ bp <- select settings'
6756
68− when initPkgDb $ do
69− ec1 <- rawSystem "ghc-pkg" ["init", packageDir settings]
70− unless (ec1 == ExitSuccess) $ do
71− putStrLn "Unable to create package database via ghc-pkg init"
72− exitWith ec1
73− checkPlan settings ii
74− putStrLn "No mismatches, starting the sandboxed build."
57+ putStrLn "Checking build plan"
58+ checkPlan bp
59+ putStrLn "No mismatches, starting the sandboxed build."
7560
76− versionString <- readProcess "cabal" ["--version"] ""
77− libVersion <-
78− case map words $ lines versionString of
79− [_,["using","version",libVersion,"of","the","Cabal","library"]] -> return libVersion
80− _ -> error "Did not understand cabal --version output"
61+ putStrLn "Wiping out old sandbox folder"
62+ rm_r $ sandboxRoot settings'
63+ rm_r "logs"
64+ settings <- fixBuildSettings settings'
8165
82− case (simpleParse libVersion, simpleParse ">= 1.16") of
83− (Nothing, _) -> error $ "Invalid Cabal library version: " ++ libVersion
84− (_, Nothing) -> assert False $ return ()
85− (Just v, Just vr)
86− | v `withinRange` vr -> return ()
87− | otherwise -> error $ "Unsupported Cabal version: " ++ libVersion
66+ putStrLn "Creating new package database"
67+ ec1 <- rawSystem "ghc-pkg" ["init", packageDir settings]
68+ unless (ec1 == ExitSuccess) $ do
69+ putStrLn "Unable to create package database via ghc-pkg init"
70+ exitWith ec1
8871
8972 menv <- fmap Just $ getModifiedEnv settings
9073 let runCabal args handle = runProcess "cabal" args Nothing menv Nothing (Just handle) (Just handle)
9174
9275 -- First install build tools so they can be used below.
93− case iiBuildTools ii of
76+ case bpTools bp of
9477 [] -> putStrLn "No build tools required"
9578 tools -> do
9679 putStrLn $ "Installing the following build tools: " ++ unwords tools
@@ -103,7 +86,7 @@ build settings' = do
10386 : concat
10487 [ extraBuildArgs settings
10588 , extraArgs settings
106− , iiBuildTools ii
89+ , tools
10790 ]
10891 hPutStrLn handle ("cabal " ++ unwords (map (\s -> "'" ++ s ++ "'") args))
10992 runCabal args handle
@@ -122,7 +105,7 @@ build settings' = do
122105 : concat
123106 [ extraBuildArgs settings
124107 , extraArgs settings
125− , iiPackageList ii
108+ , bpPackageList bp
126109 ]
127110 hPutStrLn handle ("cabal " ++ unwords (map (\s -> "'" ++ s ++ "'") args))
128111 runCabal args handle
@@ -132,10 +115,10 @@ build settings' = do
132115 exitWith ec
133116
134117 putStrLn "Sandbox built, beginning individual test suites"
135− runTestSuites settings ii
118+ runTestSuites settings $ bpPackages bp
136119
137120 putStrLn "All test suites that were expected to pass did pass, building tarballs."
138− makeTarballs ii
121+ makeTarballs bp
139122
140123-- | Get all of the build tools required.
141124iiBuildTools :: InstallInfo -> [String]
Stackage/BuildPlan.hsnew file+139
@@ -0,0 +1,139 @@
1+{-# LANGUAGE RecordWildCards #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+module Stackage.BuildPlan
4+ ( readBuildPlan
5+ , writeBuildPlan
6+ ) where
7+
8+import Stackage.Types
9+import qualified Data.Map as Map
10+import qualified Data.Set as Set
11+import Distribution.Text (simpleParse, display)
12+import Distribution.Package (PackageName (..))
13+import Control.Applicative ((<$>), (<*>))
14+
15+readBuildPlan :: FilePath -> IO BuildPlan
16+readBuildPlan fp = do
17+ str <- readFile fp
18+ case fromString str of
19+ Left s -> error $ "Could not read build plan: " ++ s
20+ Right (x, "") -> return x
21+ Right (_, _:_) -> error "Trailing content when reading build plan"
22+
23+writeBuildPlan :: FilePath -> BuildPlan -> IO ()
24+writeBuildPlan fp bp = writeFile fp $ toString bp
25+
26+class AsString a where
27+ toString :: a -> String
28+ fromString :: String -> Either String (a, String)
29+
30+instance AsString BuildPlan where
31+ toString BuildPlan {..} = concat
32+ [ makeSection "tools" bpTools
33+ , makeSection "packages" $ Map.toList bpPackages
34+ , makeSection "core" $ Set.toList bpCore
35+ , makeSection "optional-core" $ Map.toList bpOptionalCore
36+ ]
37+ fromString s1 = do
38+ (tools, s2) <- getSection "tools" s1
39+ (packages, s3) <- getSection "packages" s2
40+ (core, s4) <- getSection "core" s3
41+ (optionalCore, s5) <- getSection "optional-core" s4
42+ let bp = BuildPlan
43+ { bpTools = tools
44+ , bpPackages = Map.fromList packages
45+ , bpCore = Set.fromList core
46+ , bpOptionalCore = Map.fromList optionalCore
47+ }
48+ return (bp, s5)
49+
50+makeSection :: AsString a => String -> [a] -> String
51+makeSection title contents = unlines
52+ $ ("-- BEGIN " ++ title)
53+ : map toString contents
54+ ++ ["-- END " ++ title, ""]
55+
56+instance AsString String where
57+ toString = id
58+ fromString s = Right (s, "")
59+
60+instance AsString PackageName where
61+ toString (PackageName pn) = pn
62+ fromString s = Right (PackageName s, "")
63+
64+instance AsString a => AsString (PackageName, a) where
65+ toString (PackageName pn, s) = concat [pn, " ", toString s]
66+ fromString s = do
67+ (pn, rest) <- takeWord s
68+ (rest', s') <- fromString rest
69+ return ((PackageName pn, rest'), s')
70+
71+takeWord :: AsString a => String -> Either String (a, String)
72+takeWord s =
73+ case break (== ' ') s of
74+ (x, _:y) -> do
75+ (x', s') <- fromString x
76+ if null s'
77+ then Right (x', y)
78+ else Left $ "Unconsumed input in takeWord call"
79+
80+instance AsString SelectedPackageInfo where
81+ toString SelectedPackageInfo {..} = unwords
82+ [ display spiVersion
83+ , toString spiHasTests
84+ , maybe "@" ("@" ++) spiGithubUser
85+ , unMaintainer spiMaintainer
86+ ]
87+ fromString s1 = do
88+ (version, s2) <- takeWord s1
89+ (hasTests, s3) <- takeWord s2
90+ (gu, m) <- takeWord s3
91+ Right (SelectedPackageInfo
92+ { spiVersion = version
93+ , spiHasTests = hasTests
94+ , spiGithubUser = gu
95+ , spiMaintainer = Maintainer m
96+ }, "")
97+
98+instance AsString (Maybe String) where
99+ toString Nothing = "@"
100+ toString (Just x) = "@" ++ x
101+ fromString "@" = Right (Nothing, "")
102+ fromString ('@':rest) = Right (Just rest, "")
103+ fromString x = Left $ "Invalid Github user: " ++ x
104+
105+instance AsString Bool where
106+ toString True = "test"
107+ toString False = "notest"
108+ fromString "test" = Right (True, "")
109+ fromString "notest" = Right (False, "")
110+ fromString x = Left $ "Invalid test value: " ++ x
111+
112+instance AsString Version where
113+ toString = display
114+ fromString s =
115+ case simpleParse s of
116+ Nothing -> Left $ "Invalid version: " ++ s
117+ Just v -> Right (v, "")
118+
119+getSection :: AsString a => String -> String -> Either String ([a], String)
120+getSection title orig =
121+ case lines orig of
122+ [] -> Left "Unexpected EOF when looking for a section"
123+ l1:ls1
124+ | l1 == begin ->
125+ case break (== end) ls1 of
126+ (here, _:"":rest) -> do
127+ here' <- mapM fromString' here
128+ Right (here', unlines rest)
129+ (_, _) -> Left $ "Could not find section end: " ++ title
130+ | otherwise -> Left $ "Could not find section start: " ++ title
131+ where
132+ begin = "-- BEGIN " ++ title
133+ end = "-- END " ++ title
134+
135+ fromString' x = do
136+ (y, z) <- fromString x
137+ if null z
138+ then return y
139+ else Left $ "Unconsumed input on line: " ++ x
Stackage/CheckCabalVersion.hsnew file+45
@@ -0,0 +1,45 @@
1+module Stackage.CheckCabalVersion
2+ ( checkCabalVersion
3+ ) where
4+
5+import Control.Exception (assert)
6+import Control.Monad (unless, when)
7+import qualified Data.Map as Map
8+import Data.Maybe (mapMaybe)
9+import Data.Set (empty)
10+import qualified Data.Set as Set
11+import Distribution.Text (simpleParse)
12+import Distribution.Version (withinRange)
13+import Prelude hiding (pi)
14+import Stackage.CheckPlan
15+import Stackage.Config
16+import Stackage.InstallInfo
17+import Stackage.Tarballs
18+import Stackage.Test
19+import Stackage.Types
20+import Stackage.Util
21+import System.Directory (canonicalizePath,
22+ createDirectoryIfMissing,
23+ doesDirectoryExist)
24+import System.Exit (ExitCode (ExitSuccess), exitWith)
25+import System.IO (IOMode (WriteMode), hPutStrLn,
26+ withBinaryFile)
27+import System.Process (rawSystem, readProcess, runProcess,
28+ waitForProcess)
29+
30+checkCabalVersion :: IO String
31+checkCabalVersion = do
32+ versionString <- readProcess "cabal" ["--version"] ""
33+ libVersion <-
34+ case map words $ lines versionString of
35+ [_,["using","version",libVersion,"of","the","Cabal","library"]] -> return libVersion
36+ _ -> error "Did not understand cabal --version output"
37+
38+ case (simpleParse libVersion, simpleParse ">= 1.16") of
39+ (Nothing, _) -> error $ "Invalid Cabal library version: " ++ libVersion
40+ (_, Nothing) -> assert False $ return ()
41+ (Just v, Just vr)
42+ | v `withinRange` vr -> return ()
43+ | otherwise -> error $ "Unsupported Cabal version: " ++ libVersion
44+
45+ return libVersion
Stackage/CheckPlan.hs+5−5
@@ -16,22 +16,22 @@ import System.Process (readProcessWithExitCode)
1616data Mismatch = OnlyDryRun String | OnlySimpleList String
1717 deriving Show
1818
19−checkPlan :: BuildSettings -> InstallInfo -> IO ()
20−checkPlan settings ii = do
21− (ec, dryRun', stderr) <- readProcessWithExitCode "cabal" (addCabalArgs settings $ "install":"--dry-run":iiPackageList ii) ""
19+checkPlan :: BuildPlan -> IO ()
20+checkPlan bp = do
21+ (ec, dryRun', stderr) <- readProcessWithExitCode "cabal" (addCabalArgsOnlyGlobal $ "install":"--dry-run":bpPackageList bp) ""
2222 when (ec /= ExitSuccess || "Warning:" `isPrefixOf` stderr) $ do
2323 putStr stderr
2424 putStr dryRun'
2525 putStrLn "cabal returned a bad result, exiting"
2626 exitWith ec
2727 let dryRun = sort $ filter notOptionalCore $ map (takeWhile (/= ' ')) $ drop 2 $ lines dryRun'
28− let mismatches = getMismatches dryRun (filter notOptionalCore $ iiPackageList ii)
28+ let mismatches = getMismatches dryRun (filter notOptionalCore $ bpPackageList bp)
2929 unless (null mismatches) $ do
3030 putStrLn "Found the following mismatches"
3131 mapM_ print mismatches
3232 exitWith $ ExitFailure 1
3333 where
34− optionalCore = Set.fromList $ map packageVersionString $ Map.toList $ iiOptionalCore ii
34+ optionalCore = Set.fromList $ map packageVersionString $ Map.toList $ bpOptionalCore bp
3535 notOptionalCore s = not $ s `Set.member` optionalCore
3636
3737getMismatches :: [String] -> [String] -> [Mismatch]
Stackage/InstallInfo.hs+20−8
@@ -1,6 +1,7 @@
1+{-# LANGUAGE RecordWildCards #-}
12module Stackage.InstallInfo
23 ( getInstallInfo
3− , iiPackageList
4+ , bpPackageList
45 ) where
56
67import Control.Arrow ((&&&))
@@ -60,28 +61,39 @@ getInstallInfo settings = do
6061
6162 return InstallInfo
6263 { iiCore = totalCore
63− , iiPackages = Map.map (biVersion &&& biMaintainer) final
64+ , iiPackages = Map.map biToSPI final
6465 , iiOptionalCore = Map.fromList $ map (\(PackageIdentifier p v) -> (p, v)) $ Set.toList $ hplibs hp
6566 , iiPackageDB = pdb
6667 }
6768
69+biToSPI :: BuildInfo -> SelectedPackageInfo
70+biToSPI BuildInfo {..} = SelectedPackageInfo
71+ { spiVersion = biVersion
72+ , spiMaintainer = biMaintainer
73+ , spiGithubUser = biGithubUser
74+ , spiHasTests = biHasTests
75+ }
76+
6877showDep :: (PackageName, BuildInfo) -> String
69−showDep (PackageName name, (BuildInfo version deps (Maintainer m) _)) =
78+showDep (PackageName name, BuildInfo {..}) =
7079 concat
7180 [ name
7281 , "-"
73− , showVersion version
82+ , showVersion biVersion
7483 , " ("
75− , m
84+ , unMaintainer biMaintainer
85+ , case biGithubUser of
86+ Nothing -> ""
87+ Just x -> " @" ++ x
7688 , ")"
7789 , ": "
78− , unwords $ map unP deps
90+ , unwords $ map unP biUsers
7991 ]
8092 where
8193 unP (PackageName p) = p
8294
83−iiPackageList :: InstallInfo -> [String]
84−iiPackageList = map packageVersionString . Map.toList . Map.map fst . iiPackages
95+bpPackageList :: BuildPlan -> [String]
96+bpPackageList = map packageVersionString . Map.toList . Map.map spiVersion . bpPackages
8597
8698-- | Check for internal mismatches in required and actual package versions.
8799checkBadVersions :: BuildSettings
Stackage/NarrowDatabase.hs+2
@@ -38,6 +38,8 @@ narrowPackageDB settings (PackageDB pdb) packageSet = do
3838 , biUsers = users
3939 , biMaintainer = maintainer
4040 , biDeps = piDeps pi
41+ , biGithubUser = piGithubUser pi
42+ , biHasTests = piHasTests pi
4143 } result
4244 case piGPD pi of
4345 Nothing -> return ()
Stackage/Select.hsnew file+74
@@ -0,0 +1,74 @@
1+module Stackage.Select
2+ ( select
3+ ) where
4+
5+import Control.Exception (assert)
6+import Control.Monad (unless, when)
7+import qualified Data.Map as Map
8+import Data.Maybe (mapMaybe)
9+import Data.Set (empty)
10+import qualified Data.Set as Set
11+import Distribution.Text (simpleParse)
12+import Distribution.Version (withinRange)
13+import Prelude hiding (pi)
14+import Stackage.CheckPlan
15+import Stackage.Config
16+import Stackage.InstallInfo
17+import Stackage.Tarballs
18+import Stackage.Test
19+import Stackage.Types
20+import Stackage.Util
21+import System.Directory (canonicalizePath,
22+ createDirectoryIfMissing,
23+ doesDirectoryExist)
24+import System.Exit (ExitCode (ExitSuccess), exitWith)
25+import System.IO (IOMode (WriteMode), hPutStrLn,
26+ withBinaryFile)
27+import System.Process (rawSystem, readProcess, runProcess,
28+ waitForProcess)
29+import Stackage.BuildPlan
30+
31+select :: BuildSettings -> IO BuildPlan
32+select settings' = do
33+ ii <- getInstallInfo settings'
34+
35+ let bp = BuildPlan
36+ { bpTools = iiBuildTools ii
37+ , bpPackages = iiPackages ii
38+ , bpOptionalCore = iiOptionalCore ii
39+ , bpCore = iiCore ii
40+ }
41+
42+ writeBuildPlan "build-plan.txt" bp -- FIXME
43+ readBuildPlan "build-plan.txt"
44+ --return bp
45+
46+-- | Get all of the build tools required.
47+iiBuildTools :: InstallInfo -> [String]
48+iiBuildTools InstallInfo { iiPackageDB = PackageDB m, iiPackages = packages } =
49+ -- FIXME possible improvement: track the dependencies between the build
50+ -- tools themselves, and install them in the correct order.
51+ map packageVersionString
52+ $ filter (flip Set.notMember coreTools . fst)
53+ $ mapMaybe (flip Map.lookup buildToolMap)
54+ $ Set.toList
55+ $ Set.unions
56+ $ map piBuildTools
57+ $ Map.elems
58+ $ Map.filterWithKey isSelected m
59+ where
60+ unPackageName (PackageName pn) = pn
61+ isSelected name _ = name `Set.member` selected
62+ selected = Set.fromList $ Map.keys packages
63+
64+ -- Build tools shipped with GHC which we should not attempt to build
65+ -- ourselves.
66+ coreTools = Set.fromList $ map PackageName $ words "hsc2hs"
67+
68+ -- The map from build tool name to the package it comes from.
69+ buildToolMap = Map.unions $ map toBuildToolMap $ Map.toList m
70+ toBuildToolMap :: (PackageName, PackageInfo) -> Map Executable (PackageName, Version)
71+ toBuildToolMap (pn, pi) = Map.unions
72+ $ map (flip Map.singleton (pn, piVersion pi))
73+ $ Set.toList
74+ $ piExecs pi
Stackage/Tarballs.hs+6−6
@@ -11,8 +11,8 @@ import Stackage.Util
1111import System.Directory (createDirectoryIfMissing)
1212import System.FilePath (takeDirectory)
1313
14−makeTarballs :: InstallInfo -> IO ()
15−makeTarballs ii = do
14+makeTarballs :: BuildPlan -> IO ()
15+makeTarballs bp = do
1616 tarName <- getTarballName
1717 origEntries <- fmap Tar.read $ L.readFile tarName
1818 (stableEntries, extraEntries) <- loop id id origEntries
@@ -35,10 +35,10 @@ makeTarballs ii = do
3535 case getPackageVersion e of
3636 Nothing -> (stable, extra)
3737 Just (package, version) ->
38− case Map.lookup package $ iiPackages ii of
39− Just (version', _maintainer)
40− | version == version' -> (stable . (e:), extra)
38+ case Map.lookup package $ bpPackages bp of
39+ Just spi
40+ | version == spiVersion spi -> (stable . (e:), extra)
4141 | otherwise -> (stable, extra)
4242 Nothing
43− | package `Set.member` iiCore ii -> (stable, extra)
43+ | package `Set.member` bpCore bp -> (stable, extra)
4444 | otherwise -> (stable, extra . (e:))
Stackage/Test.hs+18−13
@@ -1,4 +1,5 @@
11{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE RecordWildCards #-}
23module Stackage.Test
34 ( runTestSuites
45 ) where
@@ -18,17 +19,13 @@ import System.IO (IOMode (WriteMode, AppendMode),
1819 withBinaryFile)
1920import System.Process (runProcess, waitForProcess)
2021
21−runTestSuites :: BuildSettings -> InstallInfo -> IO ()
22−runTestSuites settings ii = do
22+runTestSuites :: BuildSettings -> Map PackageName SelectedPackageInfo -> IO ()
23+runTestSuites settings selected = do
2324 let testdir = "runtests"
2425 rm_r testdir
2526 createDirectory testdir
26− allPass <- parFoldM (testWorkerThreads settings) (runTestSuite settings testdir hasTestSuites) (&&) True $ Map.toList $ iiPackages ii
27+ allPass <- parFoldM (testWorkerThreads settings) (runTestSuite settings testdir) (&&) True $ Map.toList selected
2728 unless allPass $ error $ "There were failures, please see the logs in " ++ testdir
28− where
29− PackageDB pdb = iiPackageDB ii
30−
31− hasTestSuites name = maybe defaultHasTestSuites piHasTests $ Map.lookup name pdb
3229
3330parFoldM :: Int -- ^ number of threads
3431 -> (b -> IO c)
@@ -76,10 +73,9 @@ instance Exception TestException
7673
7774runTestSuite :: BuildSettings
7875 -> FilePath
79− -> (PackageName -> Bool) -- ^ do we have any test suites?
80− -> (PackageName, (Version, Maintainer))
76+ -> (PackageName, SelectedPackageInfo)
8177 -> IO Bool
82−runTestSuite settings testdir hasTestSuites (packageName, (version, Maintainer maintainer)) = do
78+runTestSuite settings testdir (packageName, SelectedPackageInfo {..}) = do
8379 -- Set up a new environment that includes the sandboxed bin folder in PATH.
8480 env' <- getModifiedEnv settings
8581 let menv addGPP
@@ -98,7 +94,7 @@ runTestSuite settings testdir hasTestSuites (packageName, (version, Maintainer m
9894 passed <- handle (\TestException -> return False) $ do
9995 getHandle WriteMode $ run "cabal" ["unpack", package] testdir
10096 getHandle AppendMode $ run "cabal" (addCabalArgs settings ["configure", "--enable-tests"]) dir
101− when (hasTestSuites packageName) $ do
97+ when spiHasTests $ do
10298 getHandle AppendMode $ run "cabal" ["build"] dir
10399 getHandle AppendMode $ runGhcPackagePath "cabal" ["test"] dir
104100 getHandle AppendMode $ run "cabal" ["haddock"] dir
@@ -108,11 +104,20 @@ runTestSuite settings testdir hasTestSuites (packageName, (version, Maintainer m
108104 then do
109105 removeFile logfile
110106 when expectedFailure $ putStrLn $ package ++ " passed, but I didn't think it would."
111− else unless expectedFailure $ putStrLn $ "Test suite failed: " ++ package ++ "(" ++ maintainer ++ ")"
107+ else unless expectedFailure $ putStrLn $ concat
108+ [ "Test suite failed: "
109+ , package
110+ , "("
111+ , unMaintainer spiMaintainer
112+ , case spiGithubUser of
113+ Nothing -> ""
114+ Just x -> " @" ++ x
115+ , ")"
116+ ]
112117 rm_r dir
113118 return $! passed || expectedFailure
114119 where
115120 logfile = testdir </> package <.> "log"
116121 dir = testdir </> package
117122 getHandle mode = withBinaryFile logfile mode
118− package = packageVersionString (packageName, version)
123+ package = packageVersionString (packageName, spiVersion)
Stackage/Types.hs+20−3
@@ -46,6 +46,8 @@ data BuildInfo = BuildInfo
4646 , biUsers :: [PackageName]
4747 , biMaintainer :: Maintainer
4848 , biDeps :: Map PackageName VersionRange
49+ , biGithubUser :: Maybe String
50+ , biHasTests :: Bool
4951 }
5052
5153data HaskellPlatform = HaskellPlatform
@@ -59,7 +61,7 @@ instance Monoid HaskellPlatform where
5961
6062data InstallInfo = InstallInfo
6163 { iiCore :: Set PackageName
62− , iiPackages :: Map PackageName (Version, Maintainer)
64+ , iiPackages :: Map PackageName SelectedPackageInfo
6365 , iiOptionalCore :: Map PackageName Version
6466 -- ^ This is intended to hold onto packages which might be automatically
6567 -- provided in the global package database. In practice, this would be
@@ -67,9 +69,25 @@ data InstallInfo = InstallInfo
6769 , iiPackageDB :: PackageDB
6870 }
6971
72+data SelectedPackageInfo = SelectedPackageInfo
73+ { spiVersion :: Version
74+ , spiMaintainer :: Maintainer
75+ , spiGithubUser :: Maybe String
76+ , spiHasTests :: Bool
77+ }
78+ deriving (Show, Read)
79+
80+data BuildPlan = BuildPlan
81+ { bpTools :: [String]
82+ , bpPackages :: Map PackageName SelectedPackageInfo
83+ , bpCore :: Set PackageName
84+ , bpOptionalCore :: Map PackageName Version
85+ -- ^ See 'iiOptionalCore'
86+ }
87+
7088-- | Email address of a Stackage maintainer.
7189newtype Maintainer = Maintainer { unMaintainer :: String }
72− deriving (Show, Eq, Ord)
90+ deriving (Show, Eq, Ord, Read)
7391
7492data BuildSettings = BuildSettings
7593 { sandboxRoot :: FilePath
@@ -80,7 +98,6 @@ data BuildSettings = BuildSettings
8098 , extraArgs :: [String]
8199 , haskellPlatformCabal :: FilePath
82100 , requireHaskellPlatform :: Bool
83− , cleanBeforeBuild :: Bool
84101 , excludedPackages :: Set PackageName
85102 -- ^ Packages which should be dropped from the list of stable packages,
86103 -- even if present via the Haskell Platform or @stablePackages@. If these
Stackage/Util.hs+21−3
@@ -19,6 +19,9 @@ import System.FilePath ((</>))
1919import qualified Distribution.Package as P
2020import qualified Distribution.PackageDescription as PD
2121import Distribution.License (License (..))
22+import System.Directory (canonicalizePath,
23+ createDirectoryIfMissing,
24+ doesDirectoryExist)
2225
2326-- | Allow only packages with permissive licenses.
2427allowPermissive :: [String] -- ^ list of explicitly allowed packages
@@ -94,11 +97,16 @@ binDir = (</> "bin") . sandboxRoot
9497dataDir = (</> "share") . sandboxRoot
9598docDir x = sandboxRoot x </> "share" </> "doc" </> "$pkgid"
9699
97−addCabalArgs :: BuildSettings -> [String] -> [String]
98−addCabalArgs settings rest
100+addCabalArgsOnlyGlobal :: [String] -> [String]
101+addCabalArgsOnlyGlobal rest
99102 = "--package-db=clear"
100103 : "--package-db=global"
101− : ("--package-db=" ++ packageDir settings)
104+ : rest
105+
106+addCabalArgs :: BuildSettings -> [String] -> [String]
107+addCabalArgs settings rest
108+ = addCabalArgsOnlyGlobal
109+ $ ("--package-db=" ++ packageDir settings)
102110 : ("--libdir=" ++ libDir settings)
103111 : ("--bindir=" ++ binDir settings)
104112 : ("--datadir=" ++ dataDir settings)
@@ -121,3 +129,13 @@ getModifiedEnv settings = do
121129#else
122130 pathSep = ':'
123131#endif
132+
133+-- | Minor fixes, such as making paths absolute.
134+--
135+-- Note: creates the sandbox root in the process.
136+fixBuildSettings :: BuildSettings -> IO BuildSettings
137+fixBuildSettings settings' = do
138+ let root' = sandboxRoot settings'
139+ createDirectoryIfMissing True root'
140+ root <- canonicalizePath root'
141+ return settings' { sandboxRoot = root }
app/stackage.hs+3−7
@@ -8,8 +8,7 @@ import Data.Set (fromList)
88import System.IO (hFlush, stdout)
99
1010data BuildArgs = BuildArgs
11− { noClean :: Bool
12− , excluded :: [String]
11+ { excluded :: [String]
1312 , noPlatform :: Bool
1413 , onlyPermissive :: Bool
1514 , allowed :: [String]
@@ -18,15 +17,13 @@ data BuildArgs = BuildArgs
1817parseBuildArgs :: [String] -> IO BuildArgs
1918parseBuildArgs =
2019 loop BuildArgs
21− { noClean = False
22− , excluded = []
20+ { excluded = []
2321 , noPlatform = False
2422 , onlyPermissive = False
2523 , allowed = []
2624 }
2725 where
2826 loop x [] = return x
29− loop x ("--no-clean":rest) = loop x { noClean = True } rest
3027 loop x ("--exclude":y:rest) = loop x { excluded = y : excluded x } rest
3128 loop x ("--no-platform":rest) = loop x { noPlatform = True } rest
3229 loop x ("--only-permissive":rest) = loop x { onlyPermissive = True } rest
@@ -40,8 +37,7 @@ main = do
4037 "build":rest -> do
4138 BuildArgs {..} <- parseBuildArgs rest
4239 build defaultBuildSettings
43− { cleanBeforeBuild = not noClean
44− , excludedPackages = fromList $ map PackageName excluded
40+ { excludedPackages = fromList $ map PackageName excluded
4541 , requireHaskellPlatform = not noPlatform
4642 , allowedPackage =
4743 if onlyPermissive
stackage.cabal+3
@@ -24,6 +24,9 @@ library
2424 Stackage.Test
2525 Stackage.Build
2626 Stackage.Init
27+ Stackage.BuildPlan
28+ Stackage.CheckCabalVersion
29+ Stackage.Select
2730 build-depends: base >= 4 && < 5
2831 , containers
2932 , Cabal