From ccdbea353a30de597a00a88cf4c7216370a21882 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 2 Nov 2024 13:54:04 +0100 Subject: solver3: Replace Install() with Enqueue(), and PropagateInstall() Do not enqueue common dependencies if a version is selected already, this avoids test suites changing now in behavior as the ordering is different. --- apt-pkg/solver3.cc | 74 ++++++++++++++++++++++++------------------------------ apt-pkg/solver3.h | 6 ++--- 2 files changed, 36 insertions(+), 44 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index ce38d75d8..a00da5716 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -357,52 +357,44 @@ bool APT::Solver::Enqueue(Var var, bool decision, Var reason) return true; } -bool APT::Solver::Install(pkgCache::PkgIterator Pkg, Var reason, Group group) +bool APT::Solver::PropagateInstall(Var var) { - if ((*this)[Pkg].decision == Decision::MUST) - return true; - - // Note decision - if (not Enqueue(Var(Pkg), true, reason)) - return false; - - bool anyInstallable = false; - // Insert the work item. - Work workItem{Var(Pkg), depth(), group}; - for (auto ver = Pkg.VersionList(); not ver.end(); ver++) - { - workItem.solutions.push_back(ver); - if ((*this)[ver].decision != Decision::MUSTNOT) - anyInstallable = true; - } - - if (not anyInstallable) + if (auto Pkg = var.Pkg(cache); not Pkg.end()) { - _error->Error("Conflict: %s -> %s but no versions are installable", - WhyStr(reason).c_str(), Pkg.FullName().c_str()); + bool anyInstallable = false; + bool anyMust = false; + // Insert the work item. + Work workItem{Var(Pkg), depth(), Group::SelectVersion}; for (auto ver = Pkg.VersionList(); not ver.end(); ver++) - _error->Error("Uninstallable version: %s", WhyStr(Var(ver)).c_str()); - return false; - } - - std::stable_sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, policy, Pkg, *this}); - assert(workItem.solutions.size() > 0); + { + workItem.solutions.push_back(ver); + if ((*this)[ver].decision != Decision::MUSTNOT) + anyInstallable = true; + if ((*this)[ver].decision == Decision::MUST) + anyMust = true; + } - if (workItem.solutions.size() > 1 || workItem.optional) - AddWork(std::move(workItem)); - else if (not Enqueue(Var(pkgCache::VerIterator(cache, workItem.solutions[0])), true, workItem.reason)) - return false; + if (not anyInstallable) + { + _error->Error("Conflict: %s -> %s but no versions are installable", + WhyStr((*this)[Pkg].reason).c_str(), Pkg.FullName().c_str()); + for (auto ver = Pkg.VersionList(); not ver.end(); ver++) + _error->Error("Uninstallable version: %s", WhyStr(Var(ver)).c_str()); + return false; + } - if (not EnqueueCommonDependencies(Pkg)) - return false; + std::stable_sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, policy, Pkg, *this}); + assert(workItem.solutions.size() > 0); - return true; -} + if (workItem.solutions.size() > 1 || workItem.optional) + AddWork(std::move(workItem)); + else if (not Enqueue(Var(pkgCache::VerIterator(cache, workItem.solutions[0])), true, workItem.reason)) + return false; -bool APT::Solver::PropagateInstall(Var var) -{ - if (auto Pkg = var.Pkg(cache); not Pkg.end()) - { + // FIXME: We skip enqueuing duplicate common dependencies if we already selected a version, but + // we should not have common dependencies duplicated in the version objects anyway. + if (not anyMust && not EnqueueCommonDependencies(Pkg)) + return false; } else if (auto Ver = var.Ver(cache); not Ver.end()) { @@ -897,7 +889,7 @@ bool APT::Solver::Solve() } if (unlikely(debug >= 3)) std::cerr << "(try it: " << ver.ParentPkg().FullName() << "=" << ver.VerStr() << ")\n"; - if (not Enqueue(Var(pkgCache::VerIterator(cache, ver)), true, item.reason) && not Pop()) + if (not Enqueue(Var(ver), true, item.reason) && not Pop()) return false; foundSolution = true; break; @@ -987,7 +979,7 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache) if (not isOptional) { // Pre-empt the non-optional requests, as we don't want to queue them, we can just "unit propagate" here. - if (depcache[P].Keep() ? not Install(P, {}, Group) : not Enqueue(Var(depcache.GetCandidateVersion(P)), true, {})) + if (depcache[P].Keep() ? not Enqueue(Var(P), true, {}) : not Enqueue(Var(depcache.GetCandidateVersion(P)), true, {})) return false; } else diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h index c7437f8fb..5c67faff2 100644 --- a/apt-pkg/solver3.h +++ b/apt-pkg/solver3.h @@ -56,6 +56,9 @@ class Solver // try it last. SatisfyObsolete, + // Select a version of a package chosen for install. + SelectVersion, + // My intuition tells me that we should try to schedule upgrades first, then // any non-obsolete installed packages, and only finally obsolete ones, such // that newer packages guide resolution of dependencies for older ones, they @@ -183,9 +186,6 @@ class Solver // Enqueue a decision fact bool Enqueue(Var var, bool decision, Var reason); - // \brief Mark the package for install. This is annoying as it incurs a decision - bool Install(pkgCache::PkgIterator Pkg, Var reason, Group group); - // \brief Apply the selections from the dep cache to the solver bool FromDepCache(pkgDepCache &depcache); // \brief Apply the solver result to the depCache -- cgit v1.2.3-70-g09d2