1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveFoldable #-}
3{-# LANGUAGE DeriveFunctor #-}
4{-# LANGUAGE DeriveTraversable #-}
5{-# LANGUAGE NoImplicitPrelude #-}
6{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE RecordWildCards #-}
8{-# LANGUAGE TupleSections #-}
9{-# LANGUAGE TypeFamilies #-}
10-- | Representation of a concrete build plan, and how to generate a new one
11-- based on constraints.
12module Stackage2.BuildPlan
19import Control.Monad.State.Strict (execState, get, put)
21import qualified Data.Map as Map
22import qualified Data.Set as Set
23import qualified Distribution.Compiler
24import Distribution.PackageDescription
25import Stackage2.BuildConstraints
26import Stackage2.GithubPings
27import Stackage2.PackageDescription
28import Stackage2.PackageIndex
29import Stackage2.Prelude
31data BuildPlan = BuildPlan
32 { bpSystemInfo :: SystemInfo
33 , bpTools :: Vector (PackageName, Version)
34 , bpPackages :: Map PackageName PackagePlan
38instance ToJSON BuildPlan where
39 toJSON BuildPlan {..} = object
40 [ "system-info" .= bpSystemInfo
41 , "tools" .= map goTool bpTools
42 , "packages" .= Map.mapKeysWith const unPackageName bpPackages
45 goTool (k, v) = object
47 , "version" .= display v
49instance FromJSON BuildPlan where
50 parseJSON = withObject "BuildPlan" $ \o -> do
51 bpSystemInfo <- o .: "system-info"
52 bpTools <- (o .: "tools") >>= mapM goTool
53 bpPackages <- Map.mapKeysWith const mkPackageName <$> (o .: "packages")
56 goTool = withObject "Tool" $ \o -> (,)
57 <$> ((o .: "name") >>=
58 either (fail . show) return . simpleParse . asText)
59 <*> ((o .: "version") >>=
60 either (fail . show) return . simpleParse . asText)
62data PackagePlan = PackagePlan
63 { ppVersion :: Version
64 , ppGithubPings :: Set Text
65 , ppUsers :: Set PackageName
66 , ppConstraints :: PackageConstraints
67 , ppDesc :: SimpleDesc
71instance ToJSON PackagePlan where
72 toJSON PackagePlan {..} = object
73 [ "version" .= asText (display ppVersion)
74 , "github-pings" .= ppGithubPings
75 , "users" .= map unPackageName (unpack ppUsers)
76 , "constraints" .= ppConstraints
77 , "description" .= ppDesc
79instance FromJSON PackagePlan where
80 parseJSON = withObject "PackageBuild" $ \o -> do
81 ppVersion <- o .: "version"
82 >>= either (fail . show) return
83 . simpleParse . asText
84 ppGithubPings <- o .:? "github-pings" .!= mempty
85 ppUsers <- Set.map PackageName <$> (o .:? "users" .!= mempty)
86 ppConstraints <- o .: "constraints"
87 ppDesc <- o .: "description"
88 return PackagePlan {..}
90newBuildPlan :: MonadIO m => BuildConstraints -> m BuildPlan
91newBuildPlan bc@BuildConstraints {..} = liftIO $ do
92 packagesOrig <- getLatestDescriptions (isAllowed bc) (mkPackagePlan bc)
93 let toolMap = makeToolMap packagesOrig
94 packages = populateUsers $ removeUnincluded bc toolMap packagesOrig
95 toolNames :: [ExeName]
96 toolNames = concatMap (Map.keys . sdTools . ppDesc) packages
97 tools <- topologicalSortTools toolMap $ mapFromList $ do
99 guard $ exeName `notMember` siCoreExecutables
100 packageName <- maybe mempty setToList $ lookup exeName toolMap
101 packagePlan <- maybeToList $ lookup packageName packagesOrig
102 return (packageName, packagePlan)
103 -- FIXME topologically sort packages? maybe just leave that to the build phase
105 { bpSystemInfo = bcSystemInfo
107 , bpPackages = packages
110 SystemInfo {..} = bcSystemInfo
112makeToolMap :: Map PackageName PackagePlan
113 -> Map ExeName (Set PackageName)
115 unionsWith (++) . map go . mapToList
117 go (packageName, pp) =
118 foldMap go' $ sdProvidedExes $ ppDesc pp
120 go' exeName = singletonMap exeName (singletonSet packageName)
122topologicalSortTools :: MonadThrow m
123 => Map ExeName (Set PackageName)
124 -> Map PackageName PackagePlan
125 -> m (Vector (PackageName, Version))
126topologicalSortTools toolMap = topologicalSort
128 (concatMap (fromMaybe mempty . flip lookup toolMap) . Map.keys . sdTools . ppDesc)
130-- | Include only packages which are dependencies of the required packages and
132removeUnincluded :: BuildConstraints
133 -> Map ExeName (Set PackageName)
134 -> Map PackageName PackagePlan
135 -> Map PackageName PackagePlan
136removeUnincluded BuildConstraints {..} toolMap orig =
137 mapFromList $ filter (\(x, _) -> x `member` included) $ mapToList orig
139 SystemInfo {..} = bcSystemInfo
141 included :: Set PackageName
142 included = flip execState mempty $ mapM_ add bcPackages
146 when (name `notMember` inc) $ do
147 put $ insertSet name inc
148 case lookup name orig of
151 mapM_ add $ Map.keys $ sdPackages $ ppDesc pb
152 forM_ (Map.keys $ sdTools $ ppDesc pb) $
153 \exeName -> when (exeName `notMember` siCoreExecutables)
154 $ mapM_ add $ fromMaybe mempty $ lookup exeName toolMap
156populateUsers :: Map PackageName PackagePlan
157 -> Map PackageName PackagePlan
161 go name pb = pb { ppUsers = foldMap (go2 name) (mapToList orig) }
164 | dep `member` sdPackages (ppDesc pb) = singletonSet user
167-- | Check whether the given package/version combo meets the constraints
168-- currently in place.
169isAllowed :: BuildConstraints
170 -> PackageName -> Version -> Bool
171isAllowed bc = \name version ->
172 case lookup name $ siCorePackages $ bcSystemInfo bc of
173 Just _ -> False -- never reinstall a core package
174 Nothing -> withinRange version $ pcVersionRange $ bcPackageConstraints bc name
176mkPackagePlan :: MonadThrow m
178 -> GenericPackageDescription
180mkPackagePlan bc gpd = do
181 ppDesc <- toSimpleDesc CheckCond {..} gpd
182 return PackagePlan {..}
184 PackageIdentifier name ppVersion = package $ packageDescription gpd
185 ppGithubPings = getGithubPings gpd
186 ppConstraints = bcPackageConstraints bc name
187 ppUsers = mempty -- must be filled in later
192 ccCompilerFlavor = Distribution.Compiler.GHC
193 ccCompilerVersion = siGhcVersion
195 ccIncludeTests = pcTests ppConstraints /= Don'tBuild
196 ccIncludeBenchmarks = pcBuildBenchmarks ppConstraints
198 SystemInfo {..} = bcSystemInfo bc
200 overrides = pcFlagOverrides ppConstraints
201 getFlag MkFlag {..} =
202 (flagName, fromMaybe flagDefault $ lookup flagName overrides)
203 flags = mapFromList $ map getFlag $ genPackageFlags gpd
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