summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/solver3.cc39
-rw-r--r--apt-pkg/solver3.h15
2 files changed, 35 insertions, 19 deletions
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc
index abc0af314..be1576e98 100644
--- a/apt-pkg/solver3.cc
+++ b/apt-pkg/solver3.cc
@@ -135,7 +135,7 @@ struct APT::Solver::CompareProviders3 /*{{{*/
if ((A->CurrentVer == 0 || B->CurrentVer == 0) && A->CurrentVer != B->CurrentVer)
return A->CurrentVer != 0;
// Prefer packages in the same group as the target; e.g. foo:i386, foo:amd64
- if (A->Group != B->Group)
+ if (A->Group != B->Group && not Pkg.end())
{
if (A->Group == Pkg->Group && B->Group != Pkg->Group)
return true;
@@ -901,13 +901,13 @@ APT::Solver::Clause APT::Solver::TranslateOrGroup(pkgCache::DepIterator start, p
return clause;
}
-void APT::Solver::Push(Work work)
+void APT::Solver::Push(Var var, Work work)
{
if (unlikely(debug >= 2))
std::cerr << "Trying choice for " << work.toString(cache) << std::endl;
choices.push_back(solved.size());
- solved.push_back(Solved{Var(), std::move(work)});
+ solved.push_back(Solved{var, std::move(work)});
}
void APT::Solver::UndoOne()
@@ -947,6 +947,8 @@ bool APT::Solver::Pop()
return false;
time_t now = time(nullptr);
+ if (startTime == 0)
+ startTime = now;
if (now - startTime >= Timeout)
return _error->Error("Solver timed out.");
@@ -956,9 +958,16 @@ bool APT::Solver::Pop()
_error->Discard();
+ // Assume() actually failed to enqueue anything, abort here
+ if (choices.back() == solved.size())
+ {
+ choices.pop_back();
+ return true;
+ }
+
assert(choices.back() < solved.size());
int itemsToUndo = solved.size() - choices.back();
- auto choice = solved[choices.back()].work->choice;
+ auto choice = solved[choices.back()].assigned;
for (; itemsToUndo; --itemsToUndo)
UndoOne();
@@ -976,7 +985,7 @@ bool APT::Solver::Pop()
std::cerr << "Backtracking to choice " << choice.toString(cache) << "\n";
// FIXME: There should be a reason!
- if (not Enqueue(choice, false, {}))
+ if (not choice.empty() && not Enqueue(choice, false, {}))
return false;
if (unlikely(debug >= 2))
@@ -1059,8 +1068,7 @@ bool APT::Solver::Solve()
}
if (item.size > 1 || item.clause->optional)
{
- item.choice = sol;
- Push(item);
+ Push(sol, item);
}
if (unlikely(debug >= 3))
std::cerr << "(try it: " << sol.toString(cache) << ")\n";
@@ -1090,6 +1098,7 @@ bool APT::Solver::Solve()
bool APT::Solver::FromDepCache(pkgDepCache &depcache)
{
DefaultRootSetFunc2 rootSet(&cache);
+ std::vector<Var> manualPackages;
// Enforce strict pinning rules by rejecting all forbidden versions.
if (StrictPinning)
@@ -1167,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
@@ -1201,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
diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h
index 43f6ec3a7..590b187cc 100644
--- a/apt-pkg/solver3.h
+++ b/apt-pkg/solver3.h
@@ -222,7 +222,7 @@ class Solver
std::vector<depth_type> choices{};
// \brief The time we called Solve()
- time_t startTime;
+ time_t startTime{};
EDSP::Request::Flags requestFlags;
/// Various configuration options
@@ -277,7 +277,7 @@ class Solver
public:
// \brief Create a new decision level.
- void Push(Work work);
+ void Push(Var var, Work work);
// \brief Revert to the previous decision level.
[[nodiscard]] bool Pop();
// \brief Undo a single assignment / solved work item
@@ -426,15 +426,8 @@ struct APT::Solver::Work
// \brief The depth at which the item has been added
depth_type depth;
- // This is a union because we only need to store the choice we made when adding
- // to the choice vector, and we don't need the size of valid choices in there.
- union
- {
- // The choice we took
- Var choice;
- // Number of valid choices
- size_t size{0};
- };
+ // Number of valid choices
+ size_t size{0};
// \brief This item should be removed from the queue.
bool erased{false};