From 717ca7922be8a025b8034dc840b2ad9befc3b171 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 26 May 2025 11:19:11 +0200 Subject: solver3: Assume manual packages If we have allowed the removal of manual packages, assume them all before starting the solver. This should ensure that as long as there is a solution that does not remove a manually installed package, it is found. This requires a sweeping set of changes in the test suite, but ensures that we get "safe" behavior from the solver. We have in particular seen that without asserting the installed packages, several people ended up with ubuntu-minimal and perl removed in a situation where that was not warranted, that is, they install winehq, and then pull in some new perl packages in a newer version than the installed one, and the solver chose to create a mismatched version set, which then caused the main perl package to not be installable. Oops: 1b55173a-3526-11f0-b7ac-fa163e171f02 Oops: dbd5149e-36b9-11f0-bb74-fa163ec44ecd --- apt-pkg/solver3.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'apt-pkg/solver3.cc') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index eeac6f177..be1576e98 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -1098,6 +1098,7 @@ bool APT::Solver::Solve() bool APT::Solver::FromDepCache(pkgDepCache &depcache) { DefaultRootSetFunc2 rootSet(&cache); + std::vector manualPackages; // Enforce strict pinning rules by rejecting all forbidden versions. if (StrictPinning) @@ -1175,6 +1176,9 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache) if (not AddWork(Work{insertedW, depth()})) return false; + if (not isAuto) + manualPackages.push_back(Var(P)); + // Given A->A2|A1, B->B1|B2; Bn->An, if we select `not A1`, we // should try to install A2 before trying B so we end up with // A2, B2, instead of removing A1 to keep B1 installed. This @@ -1209,7 +1213,18 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache) } } - return Propagate(); + if (not Propagate()) + return false; + + std::stable_sort(manualPackages.begin(), manualPackages.end(), CompareProviders3{cache, policy, {}, *this}); + for (auto assumption : manualPackages) + { + if (not Assume(assumption, true, {}) || not Propagate()) + if (not Pop()) + abort(); + } + + return true; } bool APT::Solver::ToDepCache(pkgDepCache &depcache) const -- cgit v1.2.3-70-g09d2