PageRenderTime 84ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 1ms

/cabal-install/Distribution/Client/Dependency/TopDown.hs

https://gitlab.com/kranium/cabal
Haskell | 942 lines | 703 code | 115 blank | 124 comment | 14 complexity | 9d27632caeada97685dda3635532f301 MD5 | raw file
  1. -----------------------------------------------------------------------------
  2. -- |
  3. -- Module : Distribution.Client.Dependency.Types
  4. -- Copyright : (c) Duncan Coutts 2008
  5. -- License : BSD-like
  6. --
  7. -- Maintainer : cabal-devel@haskell.org
  8. -- Stability : provisional
  9. -- Portability : portable
  10. --
  11. -- Common types for dependency resolution.
  12. -----------------------------------------------------------------------------
  13. module Distribution.Client.Dependency.TopDown (
  14. topDownResolver
  15. ) where
  16. import Distribution.Client.Dependency.TopDown.Types
  17. import qualified Distribution.Client.Dependency.TopDown.Constraints as Constraints
  18. import Distribution.Client.Dependency.TopDown.Constraints
  19. ( Satisfiable(..) )
  20. import Distribution.Client.IndexUtils
  21. ( convert )
  22. import qualified Distribution.Client.InstallPlan as InstallPlan
  23. import Distribution.Client.InstallPlan
  24. ( PlanPackage(..) )
  25. import Distribution.Client.Types
  26. ( SourcePackage(..), ConfiguredPackage(..), InstalledPackage(..)
  27. , enableStanzas )
  28. import Distribution.Client.Dependency.Types
  29. ( DependencyResolver, PackageConstraint(..)
  30. , PackagePreferences(..), InstalledPreference(..)
  31. , Progress(..), foldProgress )
  32. import qualified Distribution.Client.PackageIndex as PackageIndex
  33. import Distribution.Client.PackageIndex (PackageIndex)
  34. import Distribution.Package
  35. ( PackageName(..), PackageId, Package(..), packageVersion, packageName
  36. , Dependency(Dependency), thisPackageVersion
  37. , simplifyDependency, PackageFixedDeps(depends) )
  38. import Distribution.PackageDescription
  39. ( PackageDescription(buildDepends) )
  40. import Distribution.Client.PackageUtils
  41. ( externalBuildDepends )
  42. import Distribution.PackageDescription.Configuration
  43. ( finalizePackageDescription, flattenPackageDescription )
  44. import Distribution.Version
  45. ( VersionRange, withinRange, simplifyVersionRange
  46. , UpperBound(..), asVersionIntervals )
  47. import Distribution.Compiler
  48. ( CompilerId )
  49. import Distribution.System
  50. ( Platform )
  51. import Distribution.Simple.Utils
  52. ( equating, comparing )
  53. import Distribution.Text
  54. ( display )
  55. import Data.List
  56. ( foldl', maximumBy, minimumBy, nub, sort, sortBy, groupBy )
  57. import Data.Maybe
  58. ( fromJust, fromMaybe, catMaybes )
  59. import Data.Monoid
  60. ( Monoid(mempty) )
  61. import Control.Monad
  62. ( guard )
  63. import qualified Data.Set as Set
  64. import Data.Set (Set)
  65. import qualified Data.Map as Map
  66. import qualified Data.Graph as Graph
  67. import qualified Data.Array as Array
  68. import Control.Exception
  69. ( assert )
  70. -- ------------------------------------------------------------
  71. -- * Search state types
  72. -- ------------------------------------------------------------
  73. type Constraints = Constraints.Constraints
  74. InstalledPackageEx UnconfiguredPackage ExclusionReason
  75. type SelectedPackages = PackageIndex SelectedPackage
  76. -- ------------------------------------------------------------
  77. -- * The search tree type
  78. -- ------------------------------------------------------------
  79. data SearchSpace inherited pkg
  80. = ChoiceNode inherited [[(pkg, SearchSpace inherited pkg)]]
  81. | Failure Failure
  82. -- ------------------------------------------------------------
  83. -- * Traverse a search tree
  84. -- ------------------------------------------------------------
  85. explore :: (PackageName -> PackagePreferences)
  86. -> SearchSpace (SelectedPackages, Constraints, SelectionChanges)
  87. SelectablePackage
  88. -> Progress Log Failure (SelectedPackages, Constraints)
  89. explore _ (Failure failure) = Fail failure
  90. explore _ (ChoiceNode (s,c,_) []) = Done (s,c)
  91. explore pref (ChoiceNode _ choices) =
  92. case [ choice | [choice] <- choices ] of
  93. ((_, node'):_) -> Step (logInfo node') (explore pref node')
  94. [] -> Step (logInfo node') (explore pref node')
  95. where
  96. choice = minimumBy (comparing topSortNumber) choices
  97. pkgname = packageName . fst . head $ choice
  98. (_, node') = maximumBy (bestByPref pkgname) choice
  99. where
  100. topSortNumber choice = case fst (head choice) of
  101. InstalledOnly (InstalledPackageEx _ i _) -> i
  102. SourceOnly (UnconfiguredPackage _ i _ _) -> i
  103. InstalledAndSource _ (UnconfiguredPackage _ i _ _) -> i
  104. bestByPref pkgname = case packageInstalledPreference of
  105. PreferLatest ->
  106. comparing (\(p,_) -> ( isPreferred p, packageId p))
  107. PreferInstalled ->
  108. comparing (\(p,_) -> (isInstalled p, isPreferred p, packageId p))
  109. where
  110. isInstalled (SourceOnly _) = False
  111. isInstalled _ = True
  112. isPreferred p = packageVersion p `withinRange` preferredVersions
  113. (PackagePreferences preferredVersions packageInstalledPreference)
  114. = pref pkgname
  115. logInfo node = Select selected discarded
  116. where (selected, discarded) = case node of
  117. Failure _ -> ([], [])
  118. ChoiceNode (_,_,changes) _ -> changes
  119. -- ------------------------------------------------------------
  120. -- * Generate a search tree
  121. -- ------------------------------------------------------------
  122. type ConfigurePackage = PackageIndex SelectablePackage
  123. -> SelectablePackage
  124. -> Either [Dependency] SelectedPackage
  125. -- | (packages selected, packages discarded)
  126. type SelectionChanges = ([SelectedPackage], [PackageId])
  127. searchSpace :: ConfigurePackage
  128. -> Constraints
  129. -> SelectedPackages
  130. -> SelectionChanges
  131. -> Set PackageName
  132. -> SearchSpace (SelectedPackages, Constraints, SelectionChanges)
  133. SelectablePackage
  134. searchSpace configure constraints selected changes next =
  135. assert (Set.null (selectedSet `Set.intersection` next)) $
  136. assert (selectedSet `Set.isSubsetOf` Constraints.packages constraints) $
  137. assert (next `Set.isSubsetOf` Constraints.packages constraints) $
  138. ChoiceNode (selected, constraints, changes)
  139. [ [ (pkg, select name pkg)
  140. | pkg <- PackageIndex.lookupPackageName available name ]
  141. | name <- Set.elems next ]
  142. where
  143. available = Constraints.choices constraints
  144. selectedSet = Set.fromList (map packageName (PackageIndex.allPackages selected))
  145. select name pkg = case configure available pkg of
  146. Left missing -> Failure $ ConfigureFailed pkg
  147. [ (dep, Constraints.conflicting constraints dep)
  148. | dep <- missing ]
  149. Right pkg' ->
  150. case constrainDeps pkg' newDeps (addDeps constraints newPkgs) [] of
  151. Left failure -> Failure failure
  152. Right (constraints', newDiscarded) ->
  153. searchSpace configure
  154. constraints' selected' (newSelected, newDiscarded) next'
  155. where
  156. selected' = foldl' (flip PackageIndex.insert) selected newSelected
  157. newSelected =
  158. case Constraints.isPaired constraints (packageId pkg) of
  159. Nothing -> [pkg']
  160. Just pkgid' -> [pkg', pkg'']
  161. where
  162. Just pkg'' = fmap (\(InstalledOnly p) -> InstalledOnly p)
  163. (PackageIndex.lookupPackageId available pkgid')
  164. newPkgs = [ name'
  165. | (Dependency name' _, _) <- newDeps
  166. , null (PackageIndex.lookupPackageName selected' name') ]
  167. newDeps = concatMap packageConstraints newSelected
  168. next' = Set.delete name
  169. $ foldl' (flip Set.insert) next newPkgs
  170. packageConstraints :: SelectedPackage -> [(Dependency, Bool)]
  171. packageConstraints = either installedConstraints availableConstraints
  172. . preferSource
  173. where
  174. preferSource (InstalledOnly pkg) = Left pkg
  175. preferSource (SourceOnly pkg) = Right pkg
  176. preferSource (InstalledAndSource _ pkg) = Right pkg
  177. installedConstraints (InstalledPackageEx _ _ deps) =
  178. [ (thisPackageVersion dep, True)
  179. | dep <- deps ]
  180. availableConstraints (SemiConfiguredPackage _ _ _ deps) =
  181. [ (dep, False) | dep <- deps ]
  182. addDeps :: Constraints -> [PackageName] -> Constraints
  183. addDeps =
  184. foldr $ \pkgname cs ->
  185. case Constraints.addTarget pkgname cs of
  186. Satisfiable cs' () -> cs'
  187. _ -> impossible "addDeps unsatisfiable"
  188. constrainDeps :: SelectedPackage -> [(Dependency, Bool)] -> Constraints
  189. -> [PackageId]
  190. -> Either Failure (Constraints, [PackageId])
  191. constrainDeps pkg [] cs discard =
  192. case addPackageSelectConstraint (packageId pkg) cs of
  193. Satisfiable cs' discard' -> Right (cs', discard' ++ discard)
  194. _ -> impossible "constrainDeps unsatisfiable(1)"
  195. constrainDeps pkg ((dep, installedConstraint):deps) cs discard =
  196. case addPackageDependencyConstraint (packageId pkg) dep installedConstraint cs of
  197. Satisfiable cs' discard' -> constrainDeps pkg deps cs' (discard' ++ discard)
  198. Unsatisfiable -> impossible "constrainDeps unsatisfiable(2)"
  199. ConflictsWith conflicts ->
  200. Left (DependencyConflict pkg dep installedConstraint conflicts)
  201. -- ------------------------------------------------------------
  202. -- * The main algorithm
  203. -- ------------------------------------------------------------
  204. search :: ConfigurePackage
  205. -> (PackageName -> PackagePreferences)
  206. -> Constraints
  207. -> Set PackageName
  208. -> Progress Log Failure (SelectedPackages, Constraints)
  209. search configure pref constraints =
  210. explore pref . searchSpace configure constraints mempty ([], [])
  211. -- ------------------------------------------------------------
  212. -- * The top level resolver
  213. -- ------------------------------------------------------------
  214. -- | The main exported resolver, with string logging and failure types to fit
  215. -- the standard 'DependencyResolver' interface.
  216. --
  217. topDownResolver :: DependencyResolver
  218. topDownResolver platform comp installedPkgIndex sourcePkgIndex
  219. preferences constraints targets =
  220. mapMessages (topDownResolver' platform comp
  221. (convert installedPkgIndex) sourcePkgIndex
  222. preferences constraints targets)
  223. where
  224. mapMessages :: Progress Log Failure a -> Progress String String a
  225. mapMessages = foldProgress (Step . showLog) (Fail . showFailure) Done
  226. -- | The native resolver with detailed structured logging and failure types.
  227. --
  228. topDownResolver' :: Platform -> CompilerId
  229. -> PackageIndex InstalledPackage
  230. -> PackageIndex SourcePackage
  231. -> (PackageName -> PackagePreferences)
  232. -> [PackageConstraint]
  233. -> [PackageName]
  234. -> Progress Log Failure [PlanPackage]
  235. topDownResolver' platform comp installedPkgIndex sourcePkgIndex
  236. preferences constraints targets =
  237. fmap (uncurry finalise)
  238. . (\cs -> search configure preferences cs initialPkgNames)
  239. =<< pruneBottomUp platform comp
  240. =<< addTopLevelConstraints constraints
  241. =<< addTopLevelTargets targets emptyConstraintSet
  242. where
  243. configure = configurePackage platform comp
  244. emptyConstraintSet :: Constraints
  245. emptyConstraintSet = Constraints.empty
  246. (annotateInstalledPackages topSortNumber installedPkgIndex')
  247. (annotateSourcePackages constraints topSortNumber sourcePkgIndex')
  248. (installedPkgIndex', sourcePkgIndex') =
  249. selectNeededSubset installedPkgIndex sourcePkgIndex initialPkgNames
  250. topSortNumber = topologicalSortNumbering installedPkgIndex' sourcePkgIndex'
  251. initialPkgNames = Set.fromList targets
  252. finalise selected' constraints' =
  253. PackageIndex.allPackages
  254. . fst . improvePlan installedPkgIndex' constraints'
  255. . PackageIndex.fromList
  256. $ finaliseSelectedPackages preferences selected' constraints'
  257. addTopLevelTargets :: [PackageName]
  258. -> Constraints
  259. -> Progress a Failure Constraints
  260. addTopLevelTargets [] cs = Done cs
  261. addTopLevelTargets (pkg:pkgs) cs =
  262. case Constraints.addTarget pkg cs of
  263. Satisfiable cs' () -> addTopLevelTargets pkgs cs'
  264. Unsatisfiable -> Fail (NoSuchPackage pkg)
  265. ConflictsWith _conflicts -> impossible "addTopLevelTargets conflicts"
  266. addTopLevelConstraints :: [PackageConstraint] -> Constraints
  267. -> Progress Log Failure Constraints
  268. addTopLevelConstraints [] cs = Done cs
  269. addTopLevelConstraints (PackageConstraintFlags _ _ :deps) cs =
  270. addTopLevelConstraints deps cs
  271. addTopLevelConstraints (PackageConstraintVersion pkg ver:deps) cs =
  272. case addTopLevelVersionConstraint pkg ver cs of
  273. Satisfiable cs' pkgids ->
  274. Step (AppliedVersionConstraint pkg ver pkgids)
  275. (addTopLevelConstraints deps cs')
  276. Unsatisfiable ->
  277. Fail (TopLevelVersionConstraintUnsatisfiable pkg ver)
  278. ConflictsWith conflicts ->
  279. Fail (TopLevelVersionConstraintConflict pkg ver conflicts)
  280. addTopLevelConstraints (PackageConstraintInstalled pkg:deps) cs =
  281. case addTopLevelInstalledConstraint pkg cs of
  282. Satisfiable cs' pkgids ->
  283. Step (AppliedInstalledConstraint pkg InstalledConstraint pkgids)
  284. (addTopLevelConstraints deps cs')
  285. Unsatisfiable ->
  286. Fail (TopLevelInstallConstraintUnsatisfiable pkg InstalledConstraint)
  287. ConflictsWith conflicts ->
  288. Fail (TopLevelInstallConstraintConflict pkg InstalledConstraint conflicts)
  289. addTopLevelConstraints (PackageConstraintSource pkg:deps) cs =
  290. case addTopLevelSourceConstraint pkg cs of
  291. Satisfiable cs' pkgids ->
  292. Step (AppliedInstalledConstraint pkg SourceConstraint pkgids)
  293. (addTopLevelConstraints deps cs')
  294. Unsatisfiable ->
  295. Fail (TopLevelInstallConstraintUnsatisfiable pkg SourceConstraint)
  296. ConflictsWith conflicts ->
  297. Fail (TopLevelInstallConstraintConflict pkg SourceConstraint conflicts)
  298. addTopLevelConstraints (PackageConstraintStanzas _ _ : deps) cs =
  299. addTopLevelConstraints deps cs
  300. -- | Add exclusion on available packages that cannot be configured.
  301. --
  302. pruneBottomUp :: Platform -> CompilerId
  303. -> Constraints -> Progress Log Failure Constraints
  304. pruneBottomUp platform comp constraints =
  305. foldr prune Done (initialPackages constraints) constraints
  306. where
  307. prune pkgs rest cs = foldr addExcludeConstraint rest unconfigurable cs
  308. where
  309. unconfigurable =
  310. [ (pkg, missing) -- if necessary we could look up missing reasons
  311. | (Just pkg', pkg) <- zip (map getSourcePkg pkgs) pkgs
  312. , Left missing <- [configure cs pkg'] ]
  313. addExcludeConstraint (pkg, missing) rest cs =
  314. let reason = ExcludedByConfigureFail missing in
  315. case addPackageExcludeConstraint (packageId pkg) reason cs of
  316. Satisfiable cs' [pkgid]| packageId pkg == pkgid
  317. -> Step (ExcludeUnconfigurable pkgid) (rest cs')
  318. Satisfiable _ _ -> impossible "pruneBottomUp satisfiable"
  319. _ -> Fail $ ConfigureFailed pkg
  320. [ (dep, Constraints.conflicting cs dep)
  321. | dep <- missing ]
  322. configure cs (UnconfiguredPackage (SourcePackage _ pkg _) _ flags stanzas) =
  323. finalizePackageDescription flags (dependencySatisfiable cs)
  324. platform comp [] (enableStanzas stanzas pkg)
  325. dependencySatisfiable cs =
  326. not . null . PackageIndex.lookupDependency (Constraints.choices cs)
  327. -- collect each group of packages (by name) in reverse topsort order
  328. initialPackages =
  329. reverse
  330. . sortBy (comparing (topSortNumber . head))
  331. . PackageIndex.allPackagesByName
  332. . Constraints.choices
  333. topSortNumber (InstalledOnly (InstalledPackageEx _ i _)) = i
  334. topSortNumber (SourceOnly (UnconfiguredPackage _ i _ _)) = i
  335. topSortNumber (InstalledAndSource _ (UnconfiguredPackage _ i _ _)) = i
  336. getSourcePkg (InstalledOnly _ ) = Nothing
  337. getSourcePkg (SourceOnly spkg) = Just spkg
  338. getSourcePkg (InstalledAndSource _ spkg) = Just spkg
  339. configurePackage :: Platform -> CompilerId -> ConfigurePackage
  340. configurePackage platform comp available spkg = case spkg of
  341. InstalledOnly ipkg -> Right (InstalledOnly ipkg)
  342. SourceOnly apkg -> fmap SourceOnly (configure apkg)
  343. InstalledAndSource ipkg apkg -> fmap (InstalledAndSource ipkg)
  344. (configure apkg)
  345. where
  346. configure (UnconfiguredPackage apkg@(SourcePackage _ p _) _ flags stanzas) =
  347. case finalizePackageDescription flags dependencySatisfiable
  348. platform comp [] (enableStanzas stanzas p) of
  349. Left missing -> Left missing
  350. Right (pkg, flags') -> Right $
  351. SemiConfiguredPackage apkg flags' stanzas (externalBuildDepends pkg)
  352. dependencySatisfiable = not . null . PackageIndex.lookupDependency available
  353. -- | Annotate each installed packages with its set of transative dependencies
  354. -- and its topological sort number.
  355. --
  356. annotateInstalledPackages :: (PackageName -> TopologicalSortNumber)
  357. -> PackageIndex InstalledPackage
  358. -> PackageIndex InstalledPackageEx
  359. annotateInstalledPackages dfsNumber installed = PackageIndex.fromList
  360. [ InstalledPackageEx pkg (dfsNumber (packageName pkg)) (transitiveDepends pkg)
  361. | pkg <- PackageIndex.allPackages installed ]
  362. where
  363. transitiveDepends :: InstalledPackage -> [PackageId]
  364. transitiveDepends = map (packageId . toPkg) . tail . Graph.reachable graph
  365. . fromJust . toVertex . packageId
  366. (graph, toPkg, toVertex) = PackageIndex.dependencyGraph installed
  367. -- | Annotate each available packages with its topological sort number and any
  368. -- user-supplied partial flag assignment.
  369. --
  370. annotateSourcePackages :: [PackageConstraint]
  371. -> (PackageName -> TopologicalSortNumber)
  372. -> PackageIndex SourcePackage
  373. -> PackageIndex UnconfiguredPackage
  374. annotateSourcePackages constraints dfsNumber sourcePkgIndex =
  375. PackageIndex.fromList
  376. [ UnconfiguredPackage pkg (dfsNumber name) (flagsFor name) (stanzasFor name)
  377. | pkg <- PackageIndex.allPackages sourcePkgIndex
  378. , let name = packageName pkg ]
  379. where
  380. flagsFor = fromMaybe [] . flip Map.lookup flagsMap
  381. flagsMap = Map.fromList
  382. [ (name, flags)
  383. | PackageConstraintFlags name flags <- constraints ]
  384. stanzasFor = fromMaybe [] . flip Map.lookup stanzasMap
  385. stanzasMap = Map.fromListWith (++)
  386. [ (name, stanzas)
  387. | PackageConstraintStanzas name stanzas <- constraints ]
  388. -- | One of the heuristics we use when guessing which path to take in the
  389. -- search space is an ordering on the choices we make. It's generally better
  390. -- to make decisions about packages higer in the dep graph first since they
  391. -- place constraints on packages lower in the dep graph.
  392. --
  393. -- To pick them in that order we annotate each package with its topological
  394. -- sort number. So if package A depends on package B then package A will have
  395. -- a lower topological sort number than B and we'll make a choice about which
  396. -- version of A to pick before we make a choice about B (unless there is only
  397. -- one possible choice for B in which case we pick that immediately).
  398. --
  399. -- To construct these topological sort numbers we combine and flatten the
  400. -- installed and source package sets. We consider only dependencies between
  401. -- named packages, not including versions and for not-yet-configured packages
  402. -- we look at all the possible dependencies, not just those under any single
  403. -- flag assignment. This means we can actually get impossible combinations of
  404. -- edges and even cycles, but that doesn't really matter here, it's only a
  405. -- heuristic.
  406. --
  407. topologicalSortNumbering :: PackageIndex InstalledPackage
  408. -> PackageIndex SourcePackage
  409. -> (PackageName -> TopologicalSortNumber)
  410. topologicalSortNumbering installedPkgIndex sourcePkgIndex =
  411. \pkgname -> let Just vertex = toVertex pkgname
  412. in topologicalSortNumbers Array.! vertex
  413. where
  414. topologicalSortNumbers = Array.array (Array.bounds graph)
  415. (zip (Graph.topSort graph) [0..])
  416. (graph, _, toVertex) = Graph.graphFromEdges $
  417. [ ((), packageName pkg, nub deps)
  418. | pkgs@(pkg:_) <- PackageIndex.allPackagesByName installedPkgIndex
  419. , let deps = [ packageName dep
  420. | pkg' <- pkgs
  421. , dep <- depends pkg' ] ]
  422. ++ [ ((), packageName pkg, nub deps)
  423. | pkgs@(pkg:_) <- PackageIndex.allPackagesByName sourcePkgIndex
  424. , let deps = [ depName
  425. | SourcePackage _ pkg' _ <- pkgs
  426. , Dependency depName _ <-
  427. buildDepends (flattenPackageDescription pkg') ] ]
  428. -- | We don't need the entire index (which is rather large and costly if we
  429. -- force it by examining the whole thing). So trace out the maximul subset of
  430. -- each index that we could possibly ever need. Do this by flattening packages
  431. -- and looking at the names of all possible dependencies.
  432. --
  433. selectNeededSubset :: PackageIndex InstalledPackage
  434. -> PackageIndex SourcePackage
  435. -> Set PackageName
  436. -> (PackageIndex InstalledPackage
  437. ,PackageIndex SourcePackage)
  438. selectNeededSubset installedPkgIndex sourcePkgIndex = select mempty mempty
  439. where
  440. select :: PackageIndex InstalledPackage
  441. -> PackageIndex SourcePackage
  442. -> Set PackageName
  443. -> (PackageIndex InstalledPackage
  444. ,PackageIndex SourcePackage)
  445. select installedPkgIndex' sourcePkgIndex' remaining
  446. | Set.null remaining = (installedPkgIndex', sourcePkgIndex')
  447. | otherwise = select installedPkgIndex'' sourcePkgIndex'' remaining''
  448. where
  449. (next, remaining') = Set.deleteFindMin remaining
  450. moreInstalled = PackageIndex.lookupPackageName installedPkgIndex next
  451. moreSource = PackageIndex.lookupPackageName sourcePkgIndex next
  452. moreRemaining = -- we filter out packages already included in the indexes
  453. -- this avoids an infinite loop if a package depends on itself
  454. -- like base-3.0.3.0 with base-4.0.0.0
  455. filter notAlreadyIncluded
  456. $ [ packageName dep
  457. | pkg <- moreInstalled
  458. , dep <- depends pkg ]
  459. ++ [ name
  460. | SourcePackage _ pkg _ <- moreSource
  461. , Dependency name _ <-
  462. buildDepends (flattenPackageDescription pkg) ]
  463. installedPkgIndex'' = foldl' (flip PackageIndex.insert)
  464. installedPkgIndex' moreInstalled
  465. sourcePkgIndex'' = foldl' (flip PackageIndex.insert)
  466. sourcePkgIndex' moreSource
  467. remaining'' = foldl' (flip Set.insert)
  468. remaining' moreRemaining
  469. notAlreadyIncluded name =
  470. null (PackageIndex.lookupPackageName installedPkgIndex' name)
  471. && null (PackageIndex.lookupPackageName sourcePkgIndex' name)
  472. -- ------------------------------------------------------------
  473. -- * Post processing the solution
  474. -- ------------------------------------------------------------
  475. finaliseSelectedPackages :: (PackageName -> PackagePreferences)
  476. -> SelectedPackages
  477. -> Constraints
  478. -> [PlanPackage]
  479. finaliseSelectedPackages pref selected constraints =
  480. map finaliseSelected (PackageIndex.allPackages selected)
  481. where
  482. remainingChoices = Constraints.choices constraints
  483. finaliseSelected (InstalledOnly ipkg ) = finaliseInstalled ipkg
  484. finaliseSelected (SourceOnly apkg) = finaliseSource Nothing apkg
  485. finaliseSelected (InstalledAndSource ipkg apkg) =
  486. case PackageIndex.lookupPackageId remainingChoices (packageId ipkg) of
  487. --picked package not in constraints
  488. Nothing -> impossible "finaliseSelected no pkg"
  489. -- to constrain to avail only:
  490. Just (SourceOnly _) -> impossible "finaliseSelected src only"
  491. Just (InstalledOnly _) -> finaliseInstalled ipkg
  492. Just (InstalledAndSource _ _) -> finaliseSource (Just ipkg) apkg
  493. finaliseInstalled (InstalledPackageEx pkg _ _) = InstallPlan.PreExisting pkg
  494. finaliseSource mipkg (SemiConfiguredPackage pkg flags stanzas deps) =
  495. InstallPlan.Configured (ConfiguredPackage pkg flags stanzas deps')
  496. where
  497. deps' = map (packageId . pickRemaining mipkg) deps
  498. pickRemaining mipkg dep@(Dependency _name versionRange) =
  499. case PackageIndex.lookupDependency remainingChoices dep of
  500. [] -> impossible "pickRemaining no pkg"
  501. [pkg'] -> pkg'
  502. remaining -> assert (checkIsPaired remaining)
  503. $ maximumBy bestByPref remaining
  504. where
  505. -- We order candidate packages to pick for a dependency by these
  506. -- three factors. The last factor is just highest version wins.
  507. bestByPref =
  508. comparing (\p -> (isCurrent p, isPreferred p, packageVersion p))
  509. -- Is the package already used by the installed version of this
  510. -- package? If so we should pick that first. This stops us from doing
  511. -- silly things like deciding to rebuild haskell98 against base 3.
  512. isCurrent = case mipkg :: Maybe InstalledPackageEx of
  513. Nothing -> \_ -> False
  514. Just ipkg -> \p -> packageId p `elem` depends ipkg
  515. -- If there is no upper bound on the version range then we apply a
  516. -- preferred version according to the hackage or user's suggested
  517. -- version constraints. TODO: distinguish hacks from prefs
  518. bounded = boundedAbove versionRange
  519. isPreferred p
  520. | bounded = True -- any constant will do
  521. | otherwise = packageVersion p `withinRange` preferredVersions
  522. where (PackagePreferences preferredVersions _) = pref (packageName p)
  523. boundedAbove :: VersionRange -> Bool
  524. boundedAbove vr = case asVersionIntervals vr of
  525. [] -> True -- this is the inconsistent version range.
  526. intervals -> case last intervals of
  527. (_, UpperBound _ _) -> True
  528. (_, NoUpperBound ) -> False
  529. -- We really only expect to find more than one choice remaining when
  530. -- we're finalising a dependency on a paired package.
  531. checkIsPaired [p1, p2] =
  532. case Constraints.isPaired constraints (packageId p1) of
  533. Just p2' -> packageId p2' == packageId p2
  534. Nothing -> False
  535. checkIsPaired _ = False
  536. -- | Improve an existing installation plan by, where possible, swapping
  537. -- packages we plan to install with ones that are already installed.
  538. -- This may add additional constraints due to the dependencies of installed
  539. -- packages on other installed packages.
  540. --
  541. improvePlan :: PackageIndex InstalledPackage
  542. -> Constraints
  543. -> PackageIndex PlanPackage
  544. -> (PackageIndex PlanPackage, Constraints)
  545. improvePlan installed constraints0 selected0 =
  546. foldl' improve (selected0, constraints0) (reverseTopologicalOrder selected0)
  547. where
  548. improve (selected, constraints) = fromMaybe (selected, constraints)
  549. . improvePkg selected constraints
  550. -- The idea is to improve the plan by swapping a configured package for
  551. -- an equivalent installed one. For a particular package the condition is
  552. -- that the package be in a configured state, that a the same version be
  553. -- already installed with the exact same dependencies and all the packages
  554. -- in the plan that it depends on are in the installed state
  555. improvePkg selected constraints pkgid = do
  556. Configured pkg <- PackageIndex.lookupPackageId selected pkgid
  557. ipkg <- PackageIndex.lookupPackageId installed pkgid
  558. guard $ all (isInstalled selected) (depends pkg)
  559. tryInstalled selected constraints [ipkg]
  560. isInstalled selected pkgid =
  561. case PackageIndex.lookupPackageId selected pkgid of
  562. Just (PreExisting _) -> True
  563. _ -> False
  564. tryInstalled :: PackageIndex PlanPackage -> Constraints
  565. -> [InstalledPackage]
  566. -> Maybe (PackageIndex PlanPackage, Constraints)
  567. tryInstalled selected constraints [] = Just (selected, constraints)
  568. tryInstalled selected constraints (pkg:pkgs) =
  569. case constraintsOk (packageId pkg) (depends pkg) constraints of
  570. Nothing -> Nothing
  571. Just constraints' -> tryInstalled selected' constraints' pkgs'
  572. where
  573. selected' = PackageIndex.insert (PreExisting pkg) selected
  574. pkgs' = catMaybes (map notSelected (depends pkg)) ++ pkgs
  575. notSelected pkgid =
  576. case (PackageIndex.lookupPackageId installed pkgid
  577. ,PackageIndex.lookupPackageId selected pkgid) of
  578. (Just pkg', Nothing) -> Just pkg'
  579. _ -> Nothing
  580. constraintsOk _ [] constraints = Just constraints
  581. constraintsOk pkgid (pkgid':pkgids) constraints =
  582. case addPackageDependencyConstraint pkgid dep True constraints of
  583. Satisfiable constraints' _ -> constraintsOk pkgid pkgids constraints'
  584. _ -> Nothing
  585. where
  586. dep = thisPackageVersion pkgid'
  587. reverseTopologicalOrder :: PackageFixedDeps pkg
  588. => PackageIndex pkg -> [PackageId]
  589. reverseTopologicalOrder index = map (packageId . toPkg)
  590. . Graph.topSort
  591. . Graph.transposeG
  592. $ graph
  593. where (graph, toPkg, _) = PackageIndex.dependencyGraph index
  594. -- ------------------------------------------------------------
  595. -- * Adding and recording constraints
  596. -- ------------------------------------------------------------
  597. addPackageSelectConstraint :: PackageId -> Constraints
  598. -> Satisfiable Constraints
  599. [PackageId] ExclusionReason
  600. addPackageSelectConstraint pkgid =
  601. Constraints.constrain pkgname constraint reason
  602. where
  603. pkgname = packageName pkgid
  604. constraint ver _ = ver == packageVersion pkgid
  605. reason = SelectedOther pkgid
  606. addPackageExcludeConstraint :: PackageId -> ExclusionReason
  607. -> Constraints
  608. -> Satisfiable Constraints
  609. [PackageId] ExclusionReason
  610. addPackageExcludeConstraint pkgid reason =
  611. Constraints.constrain pkgname constraint reason
  612. where
  613. pkgname = packageName pkgid
  614. constraint ver installed
  615. | ver == packageVersion pkgid = installed
  616. | otherwise = True
  617. addPackageDependencyConstraint :: PackageId -> Dependency -> Bool
  618. -> Constraints
  619. -> Satisfiable Constraints
  620. [PackageId] ExclusionReason
  621. addPackageDependencyConstraint pkgid dep@(Dependency pkgname verrange)
  622. installedConstraint =
  623. Constraints.constrain pkgname constraint reason
  624. where
  625. constraint ver installed = ver `withinRange` verrange
  626. && if installedConstraint then installed else True
  627. reason = ExcludedByPackageDependency pkgid dep installedConstraint
  628. addTopLevelVersionConstraint :: PackageName -> VersionRange
  629. -> Constraints
  630. -> Satisfiable Constraints
  631. [PackageId] ExclusionReason
  632. addTopLevelVersionConstraint pkgname verrange =
  633. Constraints.constrain pkgname constraint reason
  634. where
  635. constraint ver _installed = ver `withinRange` verrange
  636. reason = ExcludedByTopLevelConstraintVersion pkgname verrange
  637. addTopLevelInstalledConstraint,
  638. addTopLevelSourceConstraint :: PackageName
  639. -> Constraints
  640. -> Satisfiable Constraints
  641. [PackageId] ExclusionReason
  642. addTopLevelInstalledConstraint pkgname =
  643. Constraints.constrain pkgname constraint reason
  644. where
  645. constraint _ver installed = installed
  646. reason = ExcludedByTopLevelConstraintInstalled pkgname
  647. addTopLevelSourceConstraint pkgname =
  648. Constraints.constrain pkgname constraint reason
  649. where
  650. constraint _ver installed = not installed
  651. reason = ExcludedByTopLevelConstraintSource pkgname
  652. -- ------------------------------------------------------------
  653. -- * Reasons for constraints
  654. -- ------------------------------------------------------------
  655. -- | For every constraint we record we also record the reason that constraint
  656. -- is needed. So if we end up failing due to conflicting constraints then we
  657. -- can give an explnanation as to what was conflicting and why.
  658. --
  659. data ExclusionReason =
  660. -- | We selected this other version of the package. That means we exclude
  661. -- all the other versions.
  662. SelectedOther PackageId
  663. -- | We excluded this version of the package because it failed to
  664. -- configure probably because of unsatisfiable deps.
  665. | ExcludedByConfigureFail [Dependency]
  666. -- | We excluded this version of the package because another package that
  667. -- we selected imposed a dependency which this package did not satisfy.
  668. | ExcludedByPackageDependency PackageId Dependency Bool
  669. -- | We excluded this version of the package because it did not satisfy
  670. -- a dependency given as an original top level input.
  671. --
  672. | ExcludedByTopLevelConstraintVersion PackageName VersionRange
  673. | ExcludedByTopLevelConstraintInstalled PackageName
  674. | ExcludedByTopLevelConstraintSource PackageName
  675. deriving Eq
  676. -- | Given an excluded package and the reason it was excluded, produce a human
  677. -- readable explanation.
  678. --
  679. showExclusionReason :: PackageId -> ExclusionReason -> String
  680. showExclusionReason pkgid (SelectedOther pkgid') =
  681. display pkgid ++ " was excluded because " ++
  682. display pkgid' ++ " was selected instead"
  683. showExclusionReason pkgid (ExcludedByConfigureFail missingDeps) =
  684. display pkgid ++ " was excluded because it could not be configured. "
  685. ++ "It requires " ++ listOf displayDep missingDeps
  686. showExclusionReason pkgid (ExcludedByPackageDependency pkgid' dep installedConstraint)
  687. = display pkgid ++ " was excluded because " ++ display pkgid' ++ " requires "
  688. ++ (if installedConstraint then "an installed instance of " else "")
  689. ++ displayDep dep
  690. showExclusionReason pkgid (ExcludedByTopLevelConstraintVersion pkgname verRange) =
  691. display pkgid ++ " was excluded because of the top level constraint " ++
  692. displayDep (Dependency pkgname verRange)
  693. showExclusionReason pkgid (ExcludedByTopLevelConstraintInstalled pkgname)
  694. = display pkgid ++ " was excluded because of the top level constraint '"
  695. ++ display pkgname ++ " installed' which means that only installed instances "
  696. ++ "of the package may be selected."
  697. showExclusionReason pkgid (ExcludedByTopLevelConstraintSource pkgname)
  698. = display pkgid ++ " was excluded because of the top level constraint '"
  699. ++ display pkgname ++ " source' which means that only source versions "
  700. ++ "of the package may be selected."
  701. -- ------------------------------------------------------------
  702. -- * Logging progress and failures
  703. -- ------------------------------------------------------------
  704. data Log = Select [SelectedPackage] [PackageId]
  705. | AppliedVersionConstraint PackageName VersionRange [PackageId]
  706. | AppliedInstalledConstraint PackageName InstalledConstraint [PackageId]
  707. | ExcludeUnconfigurable PackageId
  708. data Failure
  709. = NoSuchPackage
  710. PackageName
  711. | ConfigureFailed
  712. SelectablePackage
  713. [(Dependency, [(PackageId, [ExclusionReason])])]
  714. | DependencyConflict
  715. SelectedPackage Dependency Bool
  716. [(PackageId, [ExclusionReason])]
  717. | TopLevelVersionConstraintConflict
  718. PackageName VersionRange
  719. [(PackageId, [ExclusionReason])]
  720. | TopLevelVersionConstraintUnsatisfiable
  721. PackageName VersionRange
  722. | TopLevelInstallConstraintConflict
  723. PackageName InstalledConstraint
  724. [(PackageId, [ExclusionReason])]
  725. | TopLevelInstallConstraintUnsatisfiable
  726. PackageName InstalledConstraint
  727. showLog :: Log -> String
  728. showLog (Select selected discarded) = case (selectedMsg, discardedMsg) of
  729. ("", y) -> y
  730. (x, "") -> x
  731. (x, y) -> x ++ " and " ++ y
  732. where
  733. selectedMsg = "selecting " ++ case selected of
  734. [] -> ""
  735. [s] -> display (packageId s) ++ " " ++ kind s
  736. (s:ss) -> listOf id
  737. $ (display (packageId s) ++ " " ++ kind s)
  738. : [ display (packageVersion s') ++ " " ++ kind s'
  739. | s' <- ss ]
  740. kind (InstalledOnly _) = "(installed)"
  741. kind (SourceOnly _) = "(source)"
  742. kind (InstalledAndSource _ _) = "(installed or source)"
  743. discardedMsg = case discarded of
  744. [] -> ""
  745. _ -> "discarding " ++ listOf id
  746. [ element
  747. | (pkgid:pkgids) <- groupBy (equating packageName) (sort discarded)
  748. , element <- display pkgid : map (display . packageVersion) pkgids ]
  749. showLog (AppliedVersionConstraint pkgname ver pkgids) =
  750. "applying constraint " ++ display (Dependency pkgname ver)
  751. ++ if null pkgids
  752. then ""
  753. else "which excludes " ++ listOf display pkgids
  754. showLog (AppliedInstalledConstraint pkgname inst pkgids) =
  755. "applying constraint " ++ display pkgname ++ " '"
  756. ++ (case inst of InstalledConstraint -> "installed"; _ -> "source") ++ "' "
  757. ++ if null pkgids
  758. then ""
  759. else "which excludes " ++ listOf display pkgids
  760. showLog (ExcludeUnconfigurable pkgid) =
  761. "excluding " ++ display pkgid ++ " (it cannot be configured)"
  762. showFailure :: Failure -> String
  763. showFailure (NoSuchPackage pkgname) =
  764. "The package " ++ display pkgname ++ " is unknown."
  765. showFailure (ConfigureFailed pkg missingDeps) =
  766. "cannot configure " ++ displayPkg pkg ++ ". It requires "
  767. ++ listOf (displayDep . fst) missingDeps
  768. ++ '\n' : unlines (map (uncurry whyNot) missingDeps)
  769. where
  770. whyNot (Dependency name ver) [] =
  771. "There is no available version of " ++ display name
  772. ++ " that satisfies " ++ displayVer ver
  773. whyNot dep conflicts =
  774. "For the dependency on " ++ displayDep dep
  775. ++ " there are these packages: " ++ listOf display pkgs
  776. ++ ". However none of them are available.\n"
  777. ++ unlines [ showExclusionReason (packageId pkg') reason
  778. | (pkg', reasons) <- conflicts, reason <- reasons ]
  779. where pkgs = map fst conflicts
  780. showFailure (DependencyConflict pkg dep installedConstraint conflicts) =
  781. "dependencies conflict: "
  782. ++ displayPkg pkg ++ " requires "
  783. ++ (if installedConstraint then "an installed instance of " else "")
  784. ++ displayDep dep ++ " however:\n"
  785. ++ unlines [ showExclusionReason (packageId pkg') reason
  786. | (pkg', reasons) <- conflicts, reason <- reasons ]
  787. showFailure (TopLevelVersionConstraintConflict name ver conflicts) =
  788. "constraints conflict: we have the top level constraint "
  789. ++ displayDep (Dependency name ver) ++ ", but\n"
  790. ++ unlines [ showExclusionReason (packageId pkg') reason
  791. | (pkg', reasons) <- conflicts, reason <- reasons ]
  792. showFailure (TopLevelVersionConstraintUnsatisfiable name ver) =
  793. "There is no available version of " ++ display name
  794. ++ " that satisfies " ++ displayVer ver
  795. showFailure (TopLevelInstallConstraintConflict name InstalledConstraint conflicts) =
  796. "constraints conflict: "
  797. ++ "top level constraint '" ++ display name ++ " installed' however\n"
  798. ++ unlines [ showExclusionReason (packageId pkg') reason
  799. | (pkg', reasons) <- conflicts, reason <- reasons ]
  800. showFailure (TopLevelInstallConstraintUnsatisfiable name InstalledConstraint) =
  801. "There is no installed version of " ++ display name
  802. showFailure (TopLevelInstallConstraintConflict name SourceConstraint conflicts) =
  803. "constraints conflict: "
  804. ++ "top level constraint '" ++ display name ++ " source' however\n"
  805. ++ unlines [ showExclusionReason (packageId pkg') reason
  806. | (pkg', reasons) <- conflicts, reason <- reasons ]
  807. showFailure (TopLevelInstallConstraintUnsatisfiable name SourceConstraint) =
  808. "There is no available source version of " ++ display name
  809. displayVer :: VersionRange -> String
  810. displayVer = display . simplifyVersionRange
  811. displayDep :: Dependency -> String
  812. displayDep = display . simplifyDependency
  813. -- ------------------------------------------------------------
  814. -- * Utils
  815. -- ------------------------------------------------------------
  816. impossible :: String -> a
  817. impossible msg = internalError $ "assertion failure: " ++ msg
  818. internalError :: String -> a
  819. internalError msg = error $ "internal error: " ++ msg
  820. displayPkg :: Package pkg => pkg -> String
  821. displayPkg = display . packageId
  822. listOf :: (a -> String) -> [a] -> String
  823. listOf _ [] = []
  824. listOf disp [x0] = disp x0
  825. listOf disp (x0:x1:xs) = disp x0 ++ go x1 xs
  826. where go x [] = " and " ++ disp x
  827. go x (x':xs') = ", " ++ disp x ++ go x' xs'