diff --git a/cabal-install/Distribution/Client/Dependency.hs b/cabal-install/Distribution/Client/Dependency.hs index ad518f2af12097ada8a277c0935477708edef7c9..0560ff0f89e1bf3a06ec49e3c16e8738a044f4d5 100644 --- a/cabal-install/Distribution/Client/Dependency.hs +++ b/cabal-install/Distribution/Client/Dependency.hs @@ -513,12 +513,12 @@ resolveDependencies :: Platform --TODO: is this needed here? see dontUpgradeNonUpgradeablePackages resolveDependencies platform comp _solver params | null (depResolverTargets params) - = return (mkInstallPlan platform comp []) + = return (mkInstallPlan platform comp (depResolverIndependentGoals params) []) resolveDependencies platform comp solver params = Step (debugDepResolverParams finalparams) - $ fmap (mkInstallPlan platform comp) + $ fmap (mkInstallPlan platform comp indGoals) $ runSolver solver (SolverConfig reorderGoals indGoals noReinstalls shadowing strFlags maxBkjumps) platform comp installedPkgIndex sourcePkgIndex @@ -553,10 +553,11 @@ resolveDependencies platform comp solver params = -- mkInstallPlan :: Platform -> CompilerInfo + -> Bool -> [InstallPlan.PlanPackage] -> InstallPlan -mkInstallPlan platform comp pkgIndex = +mkInstallPlan platform comp indepGoals pkgIndex = let index = InstalledPackageIndex.fromList pkgIndex in - case InstallPlan.new platform comp index of + case InstallPlan.new platform comp indepGoals index of Right plan -> plan Left problems -> error $ unlines $ "internal error: could not construct a valid install plan." diff --git a/cabal-install/Distribution/Client/Dependency/Modular/ConfiguredConversion.hs b/cabal-install/Distribution/Client/Dependency/Modular/ConfiguredConversion.hs index 97d22a52d99385e85c641047fd43fb71830884b3..405c69bcdce4beb0bf344c6b9379d5bd5579fecb 100644 --- a/cabal-install/Distribution/Client/Dependency/Modular/ConfiguredConversion.hs +++ b/cabal-install/Distribution/Client/Dependency/Modular/ConfiguredConversion.hs @@ -13,11 +13,11 @@ import Distribution.System import Distribution.Client.Dependency.Modular.Configured import Distribution.Client.Dependency.Modular.Package -mkPlan :: Platform -> CompilerInfo -> +mkPlan :: Platform -> CompilerInfo -> Bool -> SI.InstalledPackageIndex -> CI.PackageIndex SourcePackage -> [CP QPN] -> Either [PlanProblem] InstallPlan -mkPlan plat comp iidx sidx cps = - new plat comp (SI.fromList (map (convCP iidx sidx) cps)) +mkPlan plat comp indepGoals iidx sidx cps = + new plat comp indepGoals (SI.fromList (map (convCP iidx sidx) cps)) convCP :: SI.InstalledPackageIndex -> CI.PackageIndex SourcePackage -> CP QPN -> PlanPackage diff --git a/cabal-install/Distribution/Client/InstallPlan.hs b/cabal-install/Distribution/Client/InstallPlan.hs index 741d3124702415a7235f084a04eff02c6a8e86e4..431f82635073d2c6a19dfba36d0c93073bec18b3 100644 --- a/cabal-install/Distribution/Client/InstallPlan.hs +++ b/cabal-install/Distribution/Client/InstallPlan.hs @@ -188,19 +188,24 @@ instance HasInstalledPackageId PlanPackage where installedPackageId (Failed pkg _) = installedPackageId pkg data InstallPlan = InstallPlan { - planIndex :: PlanIndex, - planFakeMap :: FakeMap, - planGraph :: Graph, - planGraphRev :: Graph, - planPkgOf :: Graph.Vertex -> PlanPackage, - planVertexOf :: InstalledPackageId -> Graph.Vertex, - planPlatform :: Platform, - planCompiler :: CompilerInfo + planIndex :: PlanIndex, + planFakeMap :: FakeMap, + planGraph :: Graph, + planGraphRev :: Graph, + planPkgOf :: Graph.Vertex -> PlanPackage, + planVertexOf :: InstalledPackageId -> Graph.Vertex, + planPlatform :: Platform, + planCompiler :: CompilerInfo, + planIndepGoals :: Bool } invariant :: InstallPlan -> Bool invariant plan = - valid (planPlatform plan) (planCompiler plan) (planFakeMap plan) (planIndex plan) + valid (planPlatform plan) + (planCompiler plan) + (planFakeMap plan) + (planIndepGoals plan) + (planIndex plan) internalError :: String -> a internalError msg = error $ "InstallPlan: internal error: " ++ msg @@ -228,9 +233,9 @@ showPlanPackageTag (Failed _ _) = "Failed" -- | Build an installation plan from a valid set of resolved packages. -- -new :: Platform -> CompilerInfo -> PlanIndex +new :: Platform -> CompilerInfo -> Bool -> PlanIndex -> Either [PlanProblem] InstallPlan -new platform cinfo index = +new platform cinfo indepGoals index = -- NB: Need to pre-initialize the fake-map with pre-existing -- packages let isPreExisting (PreExisting _) = True @@ -239,16 +244,17 @@ new platform cinfo index = . map (\p -> (fakeInstalledPackageId (packageId p), installedPackageId p)) . filter isPreExisting $ PackageIndex.allPackages index in - case problems platform cinfo fakeMap index of + case problems platform cinfo fakeMap indepGoals index of [] -> Right InstallPlan { - planIndex = index, - planFakeMap = fakeMap, - planGraph = graph, - planGraphRev = Graph.transposeG graph, - planPkgOf = vertexToPkgId, - planVertexOf = fromMaybe noSuchPkgId . pkgIdToVertex, - planPlatform = platform, - planCompiler = cinfo + planIndex = index, + planFakeMap = fakeMap, + planGraph = graph, + planGraphRev = Graph.transposeG graph, + planPkgOf = vertexToPkgId, + planVertexOf = fromMaybe noSuchPkgId . pkgIdToVertex, + planPlatform = platform, + planCompiler = cinfo, + planIndepGoals = indepGoals } where (graph, vertexToPkgId, pkgIdToVertex) = PlanIndex.dependencyGraph fakeMap index @@ -268,7 +274,7 @@ remove :: (PlanPackage -> Bool) -> InstallPlan -> Either [PlanProblem] InstallPlan remove shouldRemove plan = - new (planPlatform plan) (planCompiler plan) newIndex + new (planPlatform plan) (planCompiler plan) (planIndepGoals plan) newIndex where newIndex = PackageIndex.fromList $ filter (not . shouldRemove) (toList plan) @@ -414,8 +420,9 @@ checkConfiguredPackage pkg = -- -- * if the result is @False@ use 'problems' to get a detailed list. -- -valid :: Platform -> CompilerInfo -> FakeMap -> PlanIndex -> Bool -valid platform cinfo fakeMap index = null (problems platform cinfo fakeMap index) +valid :: Platform -> CompilerInfo -> FakeMap -> Bool -> PlanIndex -> Bool +valid platform cinfo fakeMap indepGoals index = + null $ problems platform cinfo fakeMap indepGoals index data PlanProblem = PackageInvalid ConfiguredPackage [PackageProblem] @@ -465,9 +472,9 @@ showPlanProblem (PackageStateInvalid pkg pkg') = -- error messages. This is mainly intended for debugging purposes. -- Use 'showPlanProblem' for a human readable explanation. -- -problems :: Platform -> CompilerInfo -> FakeMap +problems :: Platform -> CompilerInfo -> FakeMap -> Bool -> PlanIndex -> [PlanProblem] -problems platform cinfo fakeMap index = +problems platform cinfo fakeMap indepGoals index = [ PackageInvalid pkg packageProblems | Configured pkg <- PackageIndex.allPackages index , let packageProblems = configuredPackageProblems platform cinfo pkg @@ -480,7 +487,7 @@ problems platform cinfo fakeMap index = | cycleGroup <- PlanIndex.dependencyCycles fakeMap index ] ++ [ PackageInconsistency name inconsistencies - | (name, inconsistencies) <- PlanIndex.dependencyInconsistencies fakeMap index ] + | (name, inconsistencies) <- PlanIndex.dependencyInconsistencies fakeMap indepGoals index ] ++ [ PackageStateInvalid pkg pkg' | pkg <- PackageIndex.allPackages index @@ -522,7 +529,7 @@ closed fakeMap = null . PlanIndex.brokenPackages fakeMap -- find out which packages are. -- consistent :: FakeMap -> PlanIndex -> Bool -consistent fakeMap = null . PlanIndex.dependencyInconsistencies fakeMap +consistent fakeMap = null . PlanIndex.dependencyInconsistencies fakeMap False -- | The states of packages have that depend on each other must respect -- this relation. That is for very case where package @a@ depends on diff --git a/cabal-install/Distribution/Client/PlanIndex.hs b/cabal-install/Distribution/Client/PlanIndex.hs index b4f96e305079c3f13ba33d0c262293f2c2fa6174..4668d92033053ccf97c329966bdeabee4d33eb87 100644 --- a/cabal-install/Distribution/Client/PlanIndex.hs +++ b/cabal-install/Distribution/Client/PlanIndex.hs @@ -29,6 +29,7 @@ import Data.Array ((!)) import Data.List (sortBy) import Data.Map (Map) import Data.Maybe (isNothing, fromMaybe) +import Data.Either (lefts) #if !MIN_VERSION_base(4,8,0) import Data.Monoid (Monoid(..)) @@ -116,6 +117,47 @@ brokenPackages fakeMap index = , isNothing (fakeLookupInstalledPackageId fakeMap index pkg') ] , not (null missing) ] + +dependencyInconsistencies :: forall pkg. (PackageFixedDeps pkg, HasInstalledPackageId pkg) + => FakeMap + -> Bool + -> PackageIndex pkg + -> [(PackageName, [(PackageIdentifier, Version)])] +dependencyInconsistencies fakeMap indepGoals index = + concatMap (dependencyInconsistencies' fakeMap) subplans + where + subplans :: [PackageIndex pkg] + subplans = lefts $ + map (dependencyClosure fakeMap index) + (rootSets fakeMap indepGoals index) + +-- | Compute the root sets of a plan +-- +-- A root set is a set of packages whose dependency closure must be consistent. +-- This is the set of all top-level library roots (taken together normally, or +-- as singletons sets if we are considering them as independent goals), along +-- with all setup dependencies of all packages. +rootSets :: (PackageFixedDeps pkg, HasInstalledPackageId pkg) + => FakeMap -> Bool -> PackageIndex pkg -> [[InstalledPackageId]] +rootSets fakeMap indepGoals index = + if indepGoals then map (:[]) libRoots else [libRoots] + where + libRoots = libraryRoots fakeMap index + +-- | Compute the library roots of a plan +-- +-- The library roots are the set of packages with no reverse dependencies +-- (no reverse library dependencies but also no reverse setup dependencies). +libraryRoots :: (PackageFixedDeps pkg, HasInstalledPackageId pkg) + => FakeMap -> PackageIndex pkg -> [InstalledPackageId] +libraryRoots fakeMap index = + map (installedPackageId . toPkgId) roots + where + (graph, toPkgId, _) = dependencyGraph fakeMap index + indegree = Graph.indegree graph + roots = filter isRoot (Graph.vertices graph) + isRoot v = indegree ! v == 0 + -- | Given a package index where we assume we want to use all the packages -- (use 'dependencyClosure' if you need to get such a index subset) find out -- if the dependencies within it use consistent versions of each package. @@ -126,12 +168,12 @@ brokenPackages fakeMap index = -- depend on it and the versions they require. These are guaranteed to be -- distinct. -- -dependencyInconsistencies :: forall pkg. - (PackageFixedDeps pkg, HasInstalledPackageId pkg) - => FakeMap - -> PackageIndex pkg - -> [(PackageName, [(PackageIdentifier, Version)])] -dependencyInconsistencies fakeMap index = +dependencyInconsistencies' :: forall pkg. + (PackageFixedDeps pkg, HasInstalledPackageId pkg) + => FakeMap + -> PackageIndex pkg + -> [(PackageName, [(PackageIdentifier, Version)])] +dependencyInconsistencies' fakeMap index = [ (name, [ (pid,packageVersion dep) | (dep,pids) <- uses, pid <- pids]) | (name, ipid_map) <- Map.toList inverseIndex , let uses = Map.elems ipid_map @@ -196,7 +238,6 @@ dependencyCycles fakeMap index = -- -- * Note that if the result is @Right []@ it is because at least one of -- the original given 'PackageIdentifier's do not occur in the index. --- dependencyClosure :: (PackageFixedDeps pkg, HasInstalledPackageId pkg) => FakeMap -> PackageIndex pkg