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 Stackage.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 Stackage.BuildConstraints
26import Stackage.GithubPings
27import Stackage.PackageDescription
28import Stackage.PackageIndex
29import Stackage.Prelude
31data BuildPlan = BuildPlan
32 { bpSystemInfo :: SystemInfo
33 , bpTools :: Vector (PackageName, Version)
34 , bpPackages :: Map PackageName PackagePlan
35 , bpGithubUsers :: Map Text (Set Text)
39instance ToJSON BuildPlan where
40 toJSON BuildPlan {..} = object
41 [ "system-info" .= bpSystemInfo
42 , "tools" .= map goTool bpTools
43 , "packages" .= Map.mapKeysWith const unPackageName bpPackages
44 , "github-users" .= bpGithubUsers
47 goTool (k, v) = object
49 , "version" .= display v
51instance FromJSON BuildPlan where
52 parseJSON = withObject "BuildPlan" $ \o -> do
53 bpSystemInfo <- o .: "system-info"
54 bpTools <- (o .: "tools") >>= mapM goTool
55 bpPackages <- Map.mapKeysWith const mkPackageName <$> (o .: "packages")
56 bpGithubUsers <- o .:? "github-users" .!= mempty
59 goTool = withObject "Tool" $ \o -> (,)
60 <$> ((o .: "name") >>=
61 either (fail . show) return . simpleParse . asText)
62 <*> ((o .: "version") >>=
63 either (fail . show) return . simpleParse . asText)
65data PackagePlan = PackagePlan
66 { ppVersion :: Version
67 , ppGithubPings :: Set Text
68 , ppUsers :: Set PackageName
69 , ppConstraints :: PackageConstraints
70 , ppDesc :: SimpleDesc
74instance ToJSON PackagePlan where
75 toJSON PackagePlan {..} = object
76 [ "version" .= asText (display ppVersion)
77 , "github-pings" .= ppGithubPings
78 , "users" .= map unPackageName (unpack ppUsers)
79 , "constraints" .= ppConstraints
80 , "description" .= ppDesc
82instance FromJSON PackagePlan where
83 parseJSON = withObject "PackageBuild" $ \o -> do
84 ppVersion <- o .: "version"
85 >>= either (fail . show) return
86 . simpleParse . asText
87 ppGithubPings <- o .:? "github-pings" .!= mempty
88 ppUsers <- Set.map PackageName <$> (o .:? "users" .!= mempty)
89 ppConstraints <- o .: "constraints"
90 ppDesc <- o .: "description"
91 return PackagePlan {..}
93newBuildPlan :: MonadIO m => BuildConstraints -> m BuildPlan
94newBuildPlan bc@BuildConstraints {..} = liftIO $ do
95 packagesOrig <- getLatestDescriptions (isAllowed bc) (mkPackagePlan bc)
96 let toolMap = makeToolMap packagesOrig
97 packages = populateUsers $ removeUnincluded bc toolMap packagesOrig
98 toolNames :: [ExeName]
99 toolNames = concatMap (Map.keys . sdTools . ppDesc) packages
100 tools <- topologicalSortTools toolMap $ mapFromList $ do
102 guard $ exeName `notMember` siCoreExecutables
103 packageName <- maybe mempty setToList $ lookup exeName toolMap
104 packagePlan <- maybeToList $ lookup packageName packagesOrig
105 return (packageName, packagePlan)
106 -- FIXME topologically sort packages? maybe just leave that to the build phase
108 { bpSystemInfo = bcSystemInfo
110 , bpPackages = packages
111 , bpGithubUsers = bcGithubUsers
114 SystemInfo {..} = bcSystemInfo
116makeToolMap :: Map PackageName PackagePlan
117 -> Map ExeName (Set PackageName)
119 unionsWith (++) . map go . mapToList
121 go (packageName, pp) =
122 foldMap go' $ sdProvidedExes $ ppDesc pp
124 go' exeName = singletonMap exeName (singletonSet packageName)
126topologicalSortTools :: MonadThrow m
127 => Map ExeName (Set PackageName)
128 -> Map PackageName PackagePlan
129 -> m (Vector (PackageName, Version))
130topologicalSortTools toolMap = topologicalSort
132 (concatMap (fromMaybe mempty . flip lookup toolMap) . Map.keys . sdTools . ppDesc)
134-- | Include only packages which are dependencies of the required packages and
136removeUnincluded :: BuildConstraints
137 -> Map ExeName (Set PackageName)
138 -> Map PackageName PackagePlan
139 -> Map PackageName PackagePlan
140removeUnincluded BuildConstraints {..} toolMap orig =
141 mapFromList $ filter (\(x, _) -> x `member` included) $ mapToList orig
143 SystemInfo {..} = bcSystemInfo
145 included :: Set PackageName
146 included = flip execState mempty $ mapM_ add bcPackages
150 when (name `notMember` inc) $ do
151 put $ insertSet name inc
152 case lookup name orig of
155 mapM_ add $ Map.keys $ sdPackages $ ppDesc pb
156 forM_ (Map.keys $ sdTools $ ppDesc pb) $
157 \exeName -> when (exeName `notMember` siCoreExecutables)
158 $ mapM_ add $ fromMaybe mempty $ lookup exeName toolMap
160populateUsers :: Map PackageName PackagePlan
161 -> Map PackageName PackagePlan
165 go name pb = pb { ppUsers = foldMap (go2 name) (mapToList orig) }
168 | dep `member` sdPackages (ppDesc pb) = singletonSet user
171-- | Check whether the given package/version combo meets the constraints
172-- currently in place.
173isAllowed :: BuildConstraints
174 -> PackageName -> Version -> Bool
175isAllowed bc = \name version ->
176 case lookup name $ siCorePackages $ bcSystemInfo bc of
177 Just _ -> False -- never reinstall a core package
178 Nothing -> withinRange version $ pcVersionRange $ bcPackageConstraints bc name
180mkPackagePlan :: MonadThrow m
182 -> GenericPackageDescription
184mkPackagePlan bc gpd = do
185 ppDesc <- toSimpleDesc CheckCond {..} gpd
186 return PackagePlan {..}
188 PackageIdentifier name ppVersion = package $ packageDescription gpd
189 ppGithubPings = getGithubPings bc gpd
190 ppConstraints = bcPackageConstraints bc name
191 ppUsers = mempty -- must be filled in later
196 ccCompilerFlavor = Distribution.Compiler.GHC
197 ccCompilerVersion = siGhcVersion
199 ccIncludeTests = pcTests ppConstraints /= Don'tBuild
200 ccIncludeBenchmarks = pcBuildBenchmarks ppConstraints
202 SystemInfo {..} = bcSystemInfo bc
204 overrides = pcFlagOverrides ppConstraints
205 getFlag MkFlag {..} =
206 (flagName, fromMaybe flagDefault $ lookup flagName overrides)
207 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