summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
+
+