summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <julian.klode@canonical.com>2024-08-12 15:27:31 +0200
committerJulian Andres Klode <julian.klode@canonical.com>2024-08-12 16:05:54 +0200
commit5d2c0e600656db690aaeb0768f3df8e71127808a (patch)
tree176549ec830513ef3841b72e0c21f0717934dd54
parent4a65a92f0fe8c57342a21462eda9878c82e7d0bf (diff)
Fix obsoleted-by handling for experimental
Basically this boils down to checking that the priority of the source candidate candidate is higher or equal than the priority of the package's candidate that is being under consideration. It stands to reason if we maybe we should actually calculate a source candidate version; this will look similar but may perhaps perform slightly different.
-rw-r--r--apt-pkg/solver3.cc48
-rw-r--r--apt-pkg/solver3.h5
-rwxr-xr-xtest/integration/test-solver3-obsoleted-by87
3 files changed, 127 insertions, 13 deletions
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc
index 0aec1ecba..2ba6f6065 100644
--- a/apt-pkg/solver3.cc
+++ b/apt-pkg/solver3.cc
@@ -247,8 +247,39 @@ std::string APT::Solver::WhyStr(Reason reason)
return outstr;
}
-bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg)
+// This is essentially asking whether any other binary in the source package has a higher candidate
+// version. This pretends that each package is installed at the same source version as the package
+// under consideration.
+bool APT::Solver::ObsoletedByNewerSourceVersion(pkgCache::VerIterator cand) const
{
+ const auto pkg = cand.ParentPkg();
+ const int candPriority = policy.GetPriority(cand);
+
+ for (auto ver = cand.Cache()->FindGrp(cand.SourcePkgName()).VersionsInSource(); not ver.end(); ver = ver.NextInSource())
+ {
+ // We are only interested in other packages in the same source package; built for the same architecture.
+ if (ver->ParentPkg == cand->ParentPkg || ver.ParentPkg()->Arch != cand.ParentPkg()->Arch || cache.VS->CmpVersion(ver.SourceVerStr(), cand.SourceVerStr()) <= 0)
+ continue;
+
+ // We also take equal priority here, given that we have a higher version
+ const int priority = policy.GetPriority(ver, true);
+ if (priority == 0 || priority < candPriority)
+ continue;
+
+ pkgObsolete[pkg->ID] = 2;
+ if (debug >= 3)
+ std::cerr << "Obsolete: " << cand.ParentPkg().FullName() << "=" << cand.VerStr() << " due to " << ver.ParentPkg().FullName() << "=" << ver.VerStr() << "\n";
+ return true;
+ }
+
+ return false;
+}
+
+bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg) const
+{
+ if (pkgObsolete[pkg->ID] != 0)
+ return pkgObsolete[pkg->ID] == 2;
+
auto ver = policy.GetCandidateVer(pkg);
if (ver.end() && not StrictPinning)
@@ -256,18 +287,13 @@ bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg)
if (ver.end())
{
std::cerr << "Obsolete: " << pkg.FullName() << " - not installable\n";
+ pkgObsolete[pkg->ID] = 2;
return true;
}
- if (pkgObsolete[pkg->ID] != 0)
- return pkgObsolete[pkg->ID] == 2;
- for (auto bin = ver.Cache()->FindGrp(ver.SourcePkgName()).VersionsInSource(); not bin.end(); bin = bin.NextInSource())
- if (bin != ver && bin.ParentPkg()->Arch == ver.ParentPkg()->Arch && bin->ParentPkg != ver->ParentPkg && (not StrictPinning || policy.GetCandidateVer(bin.ParentPkg()) == bin) && _system->VS->CmpVersion(bin.SourceVerStr(), ver.SourceVerStr()) > 0)
- {
- pkgObsolete[pkg->ID] = 2;
- if (debug >= 3)
- std::cerr << "Obsolete: " << ver.ParentPkg().FullName() << "=" << ver.VerStr() << " due to " << bin.ParentPkg().FullName() << "=" << bin.VerStr() << "\n";
- return true;
- }
+
+ if (ObsoletedByNewerSourceVersion(ver))
+ return true;
+
for (auto file = ver.FileList(); !file.end(); file++)
if ((file.File()->Flags & pkgCache::Flag::NotSource) == 0)
{
diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h
index 96faaa605..33067a0ad 100644
--- a/apt-pkg/solver3.h
+++ b/apt-pkg/solver3.h
@@ -104,8 +104,9 @@ class Solver
return verStates[V->ID];
}
- std::vector<char> pkgObsolete;
- bool Obsolete(pkgCache::PkgIterator pkg);
+ mutable std::vector<char> pkgObsolete;
+ bool Obsolete(pkgCache::PkgIterator pkg) const;
+ bool ObsoletedByNewerSourceVersion(pkgCache::VerIterator cand) const;
// \brief Heap of the remaining work.
//
diff --git a/test/integration/test-solver3-obsoleted-by b/test/integration/test-solver3-obsoleted-by
new file mode 100755
index 000000000..031589bb4
--- /dev/null
+++ b/test/integration/test-solver3-obsoleted-by
@@ -0,0 +1,87 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+setupenvironment
+configarchitecture 'amd64'
+allowremovemanual
+
+# We need a canary to make it trigger obsolete detection
+insertpackage 'installed' 'canary' 'amd64' '1' 'Depends: good | not-yet-built | obsolete | obsolete-in-experimental | obsolete-reason | obsolete-in-experimental-reason | local-only | current-version | obsolete-in-downgrade | obsolete-in-downgrade-reason'
+
+# This package is good, it still exists in the candidate
+insertpackage 'installed' 'good' 'amd64' '1' 'Source: good (= 1)'
+insertpackage 'unstable' 'good' 'amd64' '2' 'Source: good (= 2)'
+
+# not-yet-built is not yet obsolete, because it has only been built on i386
+insertpackage 'installed,unstable' 'not-yet-built' 'amd64' '1' 'Source: not-yet-built (= 1)'
+insertpackage 'unstable' 'not-yet-built' 'i386' '2' 'Source: not-yet-built (= 2)'
+
+# obsolete is obsolete because obsolete-reason has been built on the same arch and is the source candidate
+insertpackage 'installed,unstable' 'obsolete' 'amd64' '1' 'Source: obsolete (= 1)'
+insertpackage 'unstable' 'obsolete-reason' 'amd64' '2' 'Source: obsolete (= 2)'
+
+# obsolete-in-experimental is only obsoleted in experimental, so it is not yet considered obsolete
+insertpackage 'installed,unstable' 'obsolete-in-experimental' 'amd64' '1' 'Source: obsolete-in-experimental (= 1)'
+insertpackage 'experimental' 'obsolete-in-experimental-reason' 'amd64' '2' 'Source: obsolete-in-experimental (= 2)'
+
+# local-only only exists in the local install
+insertpackage 'installed' 'local-only' 'amd64' '1' 'Source: local-only (= 1)'
+
+# current-version
+insertpackage 'installed,unstable' 'current-version' 'amd64' '1' 'Source: current-version (= 1)'
+
+# obsolete-in-downgrade is only obsoleted in experimental, so it is not yet considered obsolete
+insertpackage 'installed,experimental' 'obsolete-in-downgrade' 'amd64' '2' 'Source: obsolete-in-downgrade (= 2)'
+insertpackage 'unstable' 'obsolete-in-downgrade-reason' 'amd64' '1' 'Source: obsolete-in-downgrade (= 1)'
+
+setupaptarchive
+
+testobsolete() {
+ out="$1"
+ shift
+ testsuccess $@ -o Debug::APT::Solver=4 -o APT::Solver=3.0 -s
+ cp rootdir/tmp/testsuccess.output upgrade.output
+ testsuccessequal "$out" grep "Obsolete:" upgrade.output
+}
+
+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
+Obsolete: local-only:amd64=1 - not installable" aptget dist-upgrade --no-strict-pinning
+
+msgmsg "Pinning the installed version down to experimental level means experimental wins"
+printf 'Package: obsolete-in-experimental\nPin: release *\nPin-Priority: 1\n' > rootdir/etc/apt/preferences
+testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2
+Obsolete: obsolete-in-experimental:amd64=1 due to obsolete-in-experimental-reason:amd64=2
+Obsolete: local-only:amd64=1 - not installable" aptget dist-upgrade
+testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2
+Obsolete: obsolete-in-experimental:amd64=1 due to obsolete-in-experimental-reason:amd64=2
+Obsolete: local-only:amd64=1 - not installable" aptget dist-upgrade --no-strict-pinning
+
+msgmsg "Testing no-strict-pinning with negative pins on all packages"
+printf 'Package: *\nPin: release *\nPin-Priority: -1\n' > rootdir/etc/apt/preferences
+testobsolete "Obsolete: not-yet-built:amd64 - not installable
+Obsolete: good:amd64 - not installable
+Obsolete: obsolete:amd64 - not installable
+Obsolete: obsolete-in-experimental:amd64 - not installable
+Obsolete: current-version:amd64 - not installable
+Obsolete: local-only:amd64 - not installable
+Obsolete: obsolete-in-downgrade:amd64 - not installable" aptget dist-upgrade
+
+testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2
+Obsolete: obsolete-in-experimental:amd64=1 due to obsolete-in-experimental-reason:amd64=2
+Obsolete: local-only:amd64=1 - not installable
+Obsolete: obsolete-in-downgrade-reason:amd64=1 due to obsolete-in-downgrade:amd64=2" aptget dist-upgrade --no-strict-pinning
+
+
+msgmsg "Testing that pinning a downgrade does not trigger obsoletes handling"
+printf 'Package: downgrade-reason\nPin: release *\nPin-Priority: 1000\n' > rootdir/etc/apt/preferences
+
+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
+Obsolete: local-only:amd64=1 - not installable" aptget dist-upgrade --no-strict-pinning
+
+