From 15f48dcd65fb17a4cb4cd1f93b872b3bb810c3b2 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 10 Jun 2025 11:47:41 +0200 Subject: solver3: Ignore Architecture: all for obsoleted-by In case a new version of the source package is published, we check that if there's a newer binary for the same architecture and then consider the binary obsoleted. This logic did not properly account for Architecture: all packages which are considered as native architecture package with an "All" multi-arch flag set, and hence a native architecture package may inadvertently be considered obsoleted by a package that only built on Architecture: all. --- test/integration/test-solver3-obsoleted-by | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/integration/test-solver3-obsoleted-by b/test/integration/test-solver3-obsoleted-by index e5135340c..dda6b61f0 100755 --- a/test/integration/test-solver3-obsoleted-by +++ b/test/integration/test-solver3-obsoleted-by @@ -8,7 +8,7 @@ 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' +insertpackage 'installed' 'canary' 'amd64' '1' 'Depends: good | not-yet-built | not-yet-built-all | obsolete | obsolete-all | obsolete-in-experimental | obsolete-reason | obsolete-all-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)' @@ -18,10 +18,18 @@ insertpackage 'unstable' 'good' 'amd64' '2' 'Source: good (= 2)' 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)' +# not-yet-built is not yet obsolete, because it has only been built on i386 +insertpackage 'installed,unstable' 'not-yet-built-all' 'amd64' '1' 'Source: not-yet-built-all (= 1)' +insertpackage 'unstable' 'not-yet-built-all' 'all' '2' 'Source: not-yet-built-all (= 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 is obsolete because obsolete-reason has been built on the same arch and is the source candidate +insertpackage 'installed,unstable' 'obsolete-all' 'amd64' '1' 'Source: obsolete-all (= 1)' +insertpackage 'unstable' 'obsolete-all-reason' 'amd64' '2' 'Source: obsolete-all (= 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)' @@ -47,20 +55,25 @@ testobsolete() { } # Test with manually installed local-only first, it cannot be obsolete +# We get one obsolete message from the std::any_of check that ignores manual state 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: obsolete-all:amd64=1 due to obsolete-all-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-all:amd64=1 due to obsolete-all-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-all:amd64=1 due to obsolete-all-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-all:amd64=1 due to obsolete-all-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 @@ -68,16 +81,20 @@ 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: not-yet-built-all:amd64 - not installable Obsolete: obsolete:amd64 - not installable +Obsolete: obsolete-all:amd64 - not installable Obsolete: obsolete-in-experimental:amd64 - not installable Obsolete: obsolete-reason:amd64 - not installable -Obsolete: local-only:amd64 - not installable Obsolete: obsolete-in-experimental-reason:amd64 - not installable +Obsolete: obsolete-all-reason:amd64 - not installable +Obsolete: local-only:amd64 - not installable Obsolete: current-version:amd64 - not installable Obsolete: obsolete-in-downgrade:amd64 - not installable Obsolete: obsolete-in-downgrade-reason:amd64 - not installable" aptget dist-upgrade testobsolete "Obsolete: obsolete:amd64=1 due to obsolete-reason:amd64=2 +Obsolete: obsolete-all:amd64=1 due to obsolete-all-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 @@ -87,8 +104,10 @@ 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: obsolete-all:amd64=1 due to obsolete-all-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-all:amd64=1 due to obsolete-all-reason:amd64=2 Obsolete: local-only:amd64=1 - not installable" aptget dist-upgrade --no-strict-pinning -- cgit v1.2.3-70-g09d2 From b99ec5f1d80962e39e9debb05f1a7c7840e7d97c Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 10 Jun 2025 16:09:19 +0200 Subject: solver3: Filter installed Recommends When inspecting Recommends of installed packages, filter them to the installed packages only, as we want to avoid switching between alternatives of recommended packages. --- apt-pkg/solver3.cc | 10 +++++++++ test/integration/test-solver3-break-recommends | 29 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100755 test/integration/test-solver3-break-recommends (limited to 'test') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index 052142658..c2877946c 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -964,6 +964,16 @@ APT::Solver::Clause APT::Solver::TranslateOrGroup(pkgCache::DepIterator start, p std::cerr << "Promoting new clause to hard dependency: " << clause.toString(cache) << std::endl; clause.optional = false; } + else if (not existing.end() && importantToKeep(start) && satisfied) + { + if (unlikely(debug >= 3)) + std::cerr << "Restricting existing Recommends to installed packages: " << clause.toString(cache, true) << std::endl; + // Erase the non-installed solutions. We will process this last and try to keep the previously installed + // "best" solution installed. + clause.solutions.erase(std::remove_if(clause.solutions.begin(), clause.solutions.end(), [this](auto var) + { return var.CastPkg(cache)->CurrentVer == nullptr; }), + clause.solutions.end()); + } } return clause; diff --git a/test/integration/test-solver3-break-recommends b/test/integration/test-solver3-break-recommends new file mode 100755 index 000000000..88051f5de --- /dev/null +++ b/test/integration/test-solver3-break-recommends @@ -0,0 +1,29 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" +setupenvironment +configarchitecture 'amd64' + +insertpackage 'installed' 'root' 'all' '1' 'Recommends: a | b' +insertpackage 'installed,unstable' 'a' 'all' '1' +insertpackage 'unstable' 'b' 'all' '1' + +setupaptarchive + +msgmsg "b should not be installed" + +testsuccessequal "Reading package lists... +Building dependency tree... +The following packages will be REMOVED: + a +0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded. +Remv a [1]" aptget remove a -s + +testsuccessequal "Reading package lists... +Building dependency tree... +The following packages will be REMOVED: + a +0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded. +Remv a [1]" apt remove a -s -- cgit v1.2.3-70-g09d2