summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <julian.klode@canonical.com>2025-03-09 14:52:53 +0100
committerJulian Andres Klode <julian.klode@canonical.com>2025-03-09 14:53:53 +0100
commit5daf6dbfd272be2f8e3c59d4bab4be8c119b7aa1 (patch)
tree1032f7f4727c45306c1de38faa24c9e5bbc34c9e
parent153bbf448f91eb347574624890c36f97cd168b53 (diff)
solver3: Do not prefer new installs over manually installed obsoletes
Only move obsolete packages last that are automatically installed, as we don't want to remove manually installed obsolete packages. Add some missing const annotations to the operator[] arguments as well that were needed. LP: #2100247
-rw-r--r--apt-pkg/solver3.cc7
-rw-r--r--apt-pkg/solver3.h13
-rwxr-xr-xtest/integration/test-solver3-obsoleted-by4
3 files changed, 17 insertions, 7 deletions
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc
index 9f27951e8..c993c1096 100644
--- a/apt-pkg/solver3.cc
+++ b/apt-pkg/solver3.cc
@@ -497,8 +497,10 @@ bool APT::Solver::ObsoletedByNewerSourceVersion(pkgCache::VerIterator cand) cons
return false;
}
-bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg) const
+bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg, bool AllowManual) const
{
+ if ((*this)[pkg].flags.manual && not AllowManual)
+ return false;
if (pkgObsolete[pkg] != 0)
return pkgObsolete[pkg] == 2;
@@ -804,7 +806,7 @@ APT::Solver::Clause APT::Solver::TranslateOrGroup(pkgCache::DepIterator start, p
{ return var.CastPkg(cache)->CurrentVer == 0; }))
clause.group = Group::SatisfyNew;
if (std::any_of(clause.solutions.begin(), clause.solutions.end(), [this](auto var) -> auto
- { return Obsolete(var.CastPkg(cache)); }))
+ { return Obsolete(var.CastPkg(cache), true); }))
clause.group = Group::SatisfyObsolete;
// Try to perserve satisfied Recommends. FIXME: We should check if the Recommends was there in the installed version?
if (clause.optional && start.ParentPkg()->CurrentVer)
@@ -1102,6 +1104,7 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache)
std::cerr << "Install " << P.FullName() << " (" << (isEssential ? "E" : "") << (isAuto ? "M" : "") << (Root ? "R" : "") << ")"
<< "\n";
+ (*this)[P].flags.manual = not isAuto;
if (not isOptional)
{
// Pre-empt the non-optional requests, as we don't want to queue them, we can just "unit propagate" here.
diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h
index 9d4a195ec..b7000c52e 100644
--- a/apt-pkg/solver3.h
+++ b/apt-pkg/solver3.h
@@ -146,21 +146,21 @@ class Solver
ContiguousCacheMap<pkgCache::Version, State> verStates;
// \brief Helper function for safe access to package state.
- inline State &operator[](pkgCache::Package *P)
+ inline State &operator[](const pkgCache::Package *P)
{
return pkgStates[P];
}
- inline const State &operator[](pkgCache::Package *P) const
+ inline const State &operator[](const pkgCache::Package *P) const
{
return pkgStates[P];
}
// \brief Helper function for safe access to version state.
- inline State &operator[](pkgCache::Version *V)
+ inline State &operator[](const pkgCache::Version *V)
{
return verStates[V];
}
- inline const State &operator[](pkgCache::Version *V) const
+ inline const State &operator[](const pkgCache::Version *V) const
{
return verStates[V];
}
@@ -169,7 +169,9 @@ class Solver
inline const State &operator[](Var r) const;
mutable FastContiguousCacheMap<pkgCache::Package, char> pkgObsolete;
- bool Obsolete(pkgCache::PkgIterator pkg) const;
+ // \brief Check if package is obsolete.
+ // \param AllowManual controls whether manual packages can be obsolete
+ bool Obsolete(pkgCache::PkgIterator pkg, bool AllowManual=false) const;
bool ObsoletedByNewerSourceVersion(pkgCache::VerIterator cand) const;
mutable FastContiguousCacheMap<pkgCache::Version, short> priorities;
@@ -471,6 +473,7 @@ struct APT::Solver::State
struct
{
bool discovered{};
+ bool manual{};
} flags;
static_assert(sizeof(flags) <= sizeof(int));
diff --git a/test/integration/test-solver3-obsoleted-by b/test/integration/test-solver3-obsoleted-by
index 486c55c58..e5135340c 100755
--- a/test/integration/test-solver3-obsoleted-by
+++ b/test/integration/test-solver3-obsoleted-by
@@ -46,6 +46,10 @@ testobsolete() {
testsuccessequal "$out" grep "Obsolete:" upgrade.output
}
+# Test with manually installed local-only first, it cannot be obsolete
+testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2" aptget dist-upgrade
+
+testsuccess aptmark auto '*'
testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2
Obsolete: local-only:amd64=1 - not installable" aptget dist-upgrade
testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2