Skip to content

[RFC] Add option to find best install plan before backjump limit #2917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cabal-install/Distribution/Client/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ instance Semigroup SavedConfig where
installHaddockIndex = combine installHaddockIndex,
installDryRun = combine installDryRun,
installMaxBackjumps = combine installMaxBackjumps,
installMaxScore = combine installMaxScore,
installFindBestSolution = combine installFindBestSolution,
installReorderGoals = combine installReorderGoals,
installCountConflicts = combine installCountConflicts,
installIndependentGoals = combine installIndependentGoals,
Expand Down
41 changes: 32 additions & 9 deletions cabal-install/Distribution/Client/Dependency.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ module Distribution.Client.Dependency (
setSolveExecutables,
setGoalOrder,
setSolverVerbosity,
setMaxScore,
setFindBestSolution,
removeLowerBounds,
removeUpperBounds,
addDefaultSetupDependencies,
Expand Down Expand Up @@ -176,7 +178,9 @@ data DepResolverParams = DepResolverParams {

-- | Function to override the solver's goal-ordering heuristics.
depResolverGoalOrder :: Maybe (Variable QPN -> Variable QPN -> Ordering),
depResolverVerbosity :: Verbosity
depResolverVerbosity :: Verbosity,
depResolverMaxScore :: Maybe InstallPlanScore,
depResolverFindBestSolution :: FindBestSolution
}

showDepResolverParams :: DepResolverParams -> String
Expand Down Expand Up @@ -255,7 +259,9 @@ basicDepResolverParams installedPkgIndex sourcePkgIndex =
depResolverEnableBackjumping = EnableBackjumping True,
depResolverSolveExecutables = SolveExecutables True,
depResolverGoalOrder = Nothing,
depResolverVerbosity = normal
depResolverVerbosity = normal,
depResolverMaxScore = Nothing,
depResolverFindBestSolution = FindBestSolution False
}

addTargets :: [PackageName]
Expand Down Expand Up @@ -362,6 +368,18 @@ setSolverVerbosity verbosity params =
depResolverVerbosity = verbosity
}

setMaxScore :: Maybe InstallPlanScore -> DepResolverParams -> DepResolverParams
setMaxScore n params =
params {
depResolverMaxScore = n
}

setFindBestSolution :: FindBestSolution -> DepResolverParams -> DepResolverParams
setFindBestSolution findBest params =
params {
depResolverFindBestSolution = findBest
}

-- | Some packages are specific to a given compiler version and should never be
-- upgraded.
dontUpgradeNonUpgradeablePackages :: DepResolverParams -> DepResolverParams
Expand Down Expand Up @@ -659,18 +677,19 @@ resolveDependencies :: Platform
--TODO: is this needed here? see dontUpgradeNonUpgradeablePackages
resolveDependencies platform comp _pkgConfigDB _solver params
| Set.null (depResolverTargets params)
= return (validateSolverResult platform comp indGoals [])
= return
(validateSolverResult platform comp indGoals [] defaultInstallPlanScore)
where
indGoals = depResolverIndependentGoals params

resolveDependencies platform comp pkgConfigDB solver params =

Step (showDepResolverParams finalparams)
$ fmap (validateSolverResult platform comp indGoals)
$ fmap (uncurry $ validateSolverResult platform comp indGoals)
$ runSolver solver (SolverConfig reordGoals cntConflicts
indGoals noReinstalls
shadowing strFlags allowBootLibs maxBkjumps enableBj
solveExes order verbosity)
solveExes order verbosity mScore findBest)
platform comp installedPkgIndex sourcePkgIndex
pkgConfigDB preferences constraints targets
where
Expand All @@ -691,7 +710,9 @@ resolveDependencies platform comp pkgConfigDB solver params =
enableBj
solveExes
order
verbosity) =
verbosity
mScore
findBest) =
if asBool (depResolverAllowBootLibInstalls params)
then params
else dontUpgradeNonUpgradeablePackages params
Expand Down Expand Up @@ -749,10 +770,11 @@ validateSolverResult :: Platform
-> CompilerInfo
-> IndependentGoals
-> [ResolverPackage UnresolvedPkgLoc]
-> InstallPlanScore
-> SolverInstallPlan
validateSolverResult platform comp indepGoals pkgs =
validateSolverResult platform comp indepGoals pkgs score =
case planPackagesProblems platform comp pkgs of
[] -> case SolverInstallPlan.new indepGoals graph of
[] -> case SolverInstallPlan.new indepGoals score graph of
Right plan -> plan
Left problems -> error (formatPlanProblems problems)
problems -> error (formatPkgProblems problems)
Expand Down Expand Up @@ -927,7 +949,8 @@ resolveWithoutDependencies (DepResolverParams targets constraints
prefs defpref installedPkgIndex sourcePkgIndex
_reorderGoals _countConflicts _indGoals _avoidReinstalls
_shadowing _strFlags _maxBjumps _enableBj
_solveExes _allowBootLibInstalls _order _verbosity) =
_solveExes _allowBootLibInstalls _order _verbosity
_maxScore _findBest) =
collectEithers $ map selectPackage (Set.toList targets)
where
selectPackage :: PackageName -> Either ResolveNoDepsError UnresolvedSourcePackage
Expand Down
13 changes: 11 additions & 2 deletions cabal-install/Distribution/Client/Install.hs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ planPackages verbosity comp platform mSandboxPkgInfo solver
setMaxBackjumps (if maxBackjumps < 0 then Nothing
else Just maxBackjumps)

. setMaxScore maxScore

. setFindBestSolution findBest

. setIndependentGoals independentGoals

. setReorderGoals reorderGoals
Expand Down Expand Up @@ -456,6 +460,8 @@ planPackages verbosity comp platform mSandboxPkgInfo solver
strongFlags = fromFlag (installStrongFlags installFlags)
maxBackjumps = fromFlag (installMaxBackjumps installFlags)
allowBootLibInstalls = fromFlag (installAllowBootLibInstalls installFlags)
maxScore = flagToMaybe (installMaxScore installFlags)
findBest = fromFlag (installFindBestSolution installFlags)
upgradeDeps = fromFlag (installUpgradeDeps installFlags)
onlyDeps = fromFlag (installOnlyDeps installFlags)
allowOlder = fromMaybe (AllowOlder RelaxDepsNone)
Expand Down Expand Up @@ -556,7 +562,7 @@ checkPrintPlan verbosity installed installPlan sourcePkgDb
-- with a dangerous install plan.
when (dryRun || containsReinstalls && not overrideReinstall) $
printPlan (dryRun || breaksPkgs && not overrideReinstall)
adaptedVerbosity lPlan sourcePkgDb
adaptedVerbosity lPlan (InstallPlan.planScore installPlan) sourcePkgDb

-- If the install plan is dangerous, we print various warning messages. In
-- particular, if we can see that packages are likely to be broken, we even
Expand Down Expand Up @@ -647,9 +653,12 @@ packageStatus installedPkgIndex cpkg =
printPlan :: Bool -- is dry run
-> Verbosity
-> [(ReadyPackage, PackageStatus)]
-> InstallPlanScore
-> SourcePackageDb
-> IO ()
printPlan dryRun verbosity plan sourcePkgDb = case plan of
printPlan dryRun verbosity plan score sourcePkgDb = do
notice verbosity $ "Install plan score: " ++ showInstallPlanScore score
case plan of
[] -> return ()
pkgs
| verbosity >= Verbosity.verbose -> putStr $ unlines $
Expand Down
29 changes: 19 additions & 10 deletions cabal-install/Distribution/Client/InstallPlan.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
-----------------------------------------------------------------------------
module Distribution.Client.InstallPlan (
InstallPlan,
GenericInstallPlan,
GenericInstallPlan(planScore),
PlanPackage,
GenericPlanPackage(..),
IsUnit,
Expand Down Expand Up @@ -216,7 +216,10 @@ instance (HasConfiguredId ipkg, HasConfiguredId srcpkg) =>

data GenericInstallPlan ipkg srcpkg = GenericInstallPlan {
planGraph :: !(Graph (GenericPlanPackage ipkg srcpkg)),
planIndepGoals :: !IndependentGoals
planIndepGoals :: !IndependentGoals,

-- TODO: This field can be removed if we don't print the install plan score.
planScore :: !InstallPlanScore
}
deriving (Typeable)

Expand All @@ -230,12 +233,14 @@ mkInstallPlan :: (IsUnit ipkg, IsUnit srcpkg)
=> String
-> Graph (GenericPlanPackage ipkg srcpkg)
-> IndependentGoals
-> InstallPlanScore
-> GenericInstallPlan ipkg srcpkg
mkInstallPlan loc graph indepGoals =
mkInstallPlan loc graph indepGoals score =
assert (valid loc graph)
GenericInstallPlan {
planGraph = graph,
planIndepGoals = indepGoals
planIndepGoals = indepGoals,
planScore = score
}

internalError :: String -> String -> a
Expand All @@ -247,12 +252,13 @@ instance (IsNode ipkg, Key ipkg ~ UnitId, IsNode srcpkg, Key srcpkg ~ UnitId,
=> Binary (GenericInstallPlan ipkg srcpkg) where
put GenericInstallPlan {
planGraph = graph,
planIndepGoals = indepGoals
} = put (graph, indepGoals)
planIndepGoals = indepGoals,
planScore = score
} = put (graph, indepGoals, score)

get = do
(graph, indepGoals) <- get
return $! mkInstallPlan "(instance Binary)" graph indepGoals
(graph, indepGoals, score) <- get
return $! mkInstallPlan "(instance Binary)" graph indepGoals score

showPlanGraph :: (Package ipkg, Package srcpkg,
IsUnit ipkg, IsUnit srcpkg)
Expand All @@ -279,9 +285,10 @@ showPlanPackageTag (Installed _) = "Installed"
--
new :: (IsUnit ipkg, IsUnit srcpkg)
=> IndependentGoals
-> InstallPlanScore
-> Graph (GenericPlanPackage ipkg srcpkg)
-> GenericInstallPlan ipkg srcpkg
new indepGoals graph = mkInstallPlan "new" graph indepGoals
new indepGoals score graph = mkInstallPlan "new" graph indepGoals score

toGraph :: GenericInstallPlan ipkg srcpkg
-> Graph (GenericPlanPackage ipkg srcpkg)
Expand Down Expand Up @@ -312,7 +319,7 @@ remove :: (IsUnit ipkg, IsUnit srcpkg)
-> GenericInstallPlan ipkg srcpkg
-> GenericInstallPlan ipkg srcpkg
remove shouldRemove plan =
mkInstallPlan "remove" newGraph (planIndepGoals plan)
mkInstallPlan "remove" newGraph (planIndepGoals plan) (planScore plan)
where
newGraph = Graph.fromDistinctList $
filter (not . shouldRemove) (toList plan)
Expand Down Expand Up @@ -418,6 +425,7 @@ fromSolverInstallPlan f plan =
mkInstallPlan "fromSolverInstallPlan"
(Graph.fromDistinctList pkgs'')
(SolverInstallPlan.planIndepGoals plan)
(SolverInstallPlan.planScore plan)
where
(_, _, pkgs'') = foldl' f' (Map.empty, Map.empty, [])
(SolverInstallPlan.reverseTopologicalOrder plan)
Expand Down Expand Up @@ -455,6 +463,7 @@ fromSolverInstallPlanWithProgress f plan = do
return $ mkInstallPlan "fromSolverInstallPlanWithProgress"
(Graph.fromDistinctList pkgs'')
(SolverInstallPlan.planIndepGoals plan)
(SolverInstallPlan.planScore plan)
where
f' (pidMap, ipiMap, pkgs) pkg = do
pkgs' <- f (mapDep pidMap ipiMap) pkg
Expand Down
3 changes: 3 additions & 0 deletions cabal-install/Distribution/Client/ProjectConfig/Legacy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ convertLegacyAllPackageFlags globalFlags configFlags
--installOverrideReinstall = projectConfigOverrideReinstall,
installIndexState = projectConfigIndexState,
installMaxBackjumps = projectConfigMaxBackjumps,
--installMaxScore = projectConfigMaxScore,
--installUpgradeDeps = projectConfigUpgradeDeps,
installReorderGoals = projectConfigReorderGoals,
installCountConflicts = projectConfigCountConflicts,
Expand Down Expand Up @@ -497,7 +498,9 @@ convertToLegacySharedConfig
installAvoidReinstalls = mempty, --projectConfigAvoidReinstalls,
installOverrideReinstall = mempty, --projectConfigOverrideReinstall,
installMaxBackjumps = projectConfigMaxBackjumps,
installMaxScore = mempty, --projectConfigMaxScore,
installUpgradeDeps = mempty, --projectConfigUpgradeDeps,
installFindBestSolution = mempty, --projectConfigFindBestSolution,
installReorderGoals = projectConfigReorderGoals,
installCountConflicts = projectConfigCountConflicts,
installIndependentGoals = mempty, --projectConfigIndependentGoals,
Expand Down
6 changes: 3 additions & 3 deletions cabal-install/Distribution/Client/ProjectPlanning.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1839,7 +1839,7 @@ getComponentId (InstallPlan.Installed elab) = elabComponentId elab

instantiateInstallPlan :: ElaboratedInstallPlan -> ElaboratedInstallPlan
instantiateInstallPlan plan =
InstallPlan.new (IndependentGoals False)
InstallPlan.new (IndependentGoals False) (InstallPlan.planScore plan)
(Graph.fromDistinctList (Map.elems ready_map))
where
pkgs = InstallPlan.toList plan
Expand Down Expand Up @@ -2057,7 +2057,7 @@ elabBuildTargetWholeComponents elab =
pruneInstallPlanToTargets :: Map UnitId [PackageTarget]
-> ElaboratedInstallPlan -> ElaboratedInstallPlan
pruneInstallPlanToTargets perPkgTargetsMap elaboratedPlan =
InstallPlan.new (InstallPlan.planIndepGoals elaboratedPlan)
InstallPlan.new (InstallPlan.planIndepGoals elaboratedPlan) (InstallPlan.planScore elaboratedPlan)
. Graph.fromDistinctList
-- We have to do this in two passes
. pruneInstallPlanPass2
Expand Down Expand Up @@ -2357,7 +2357,7 @@ pruneInstallPlanToDependencies pkgTargets installPlan =
assert (all (isJust . InstallPlan.lookup installPlan)
(Set.toList pkgTargets)) $

fmap (InstallPlan.new (InstallPlan.planIndepGoals installPlan))
fmap (InstallPlan.new (InstallPlan.planIndepGoals installPlan) (InstallPlan.planScore installPlan))
. checkBrokenDeps
. Graph.fromDistinctList
. filter (\pkg -> installedUnitId pkg `Set.notMember` pkgTargets)
Expand Down
Loading