summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2024-03-14 20:59:10 +0000
committerDavid Kalnischkies <david@kalnischkies.de>2024-04-24 13:16:21 +0000
commitd030a1041b243c45dcd41e34d3c2b21cf1a533ba (patch)
treeb249f3de9c5a2e463c90757f9def3fc7052fdba8
parente099ee946000797f4c03b8c5075ce7ebba193337 (diff)
Do not upgrade rev-deps ear-marked for removal
We schedule reverse dependencies for an upgrade, but we shouldn't do it if we have ear-marked this package for removal later on. Usually the solver will end up doing the right thing like it already did in the included testcase in the end, but given that before it reaches the right end it explored a bad path which can lead to more installs and removals influencing later decisions or are just too hard for the resolver to undo later on, we can just not explore this path to begin with. References: e077370ffcb3669a50a600e80356c2002e6b176d
-rw-r--r--apt-pkg/depcache.cc7
-rwxr-xr-xtest/integration/test-not-upgrading-removed-depends50
2 files changed, 55 insertions, 2 deletions
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 76a5c09ba..72cbf8dcc 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -1463,7 +1463,7 @@ static bool MarkInstall_RemoveConflictsIfNotUpgradeable(pkgDepCache &Cache, bool
return not failedToRemoveSomething;
}
/*}}}*/
-static bool MarkInstall_CollectReverseDepends(pkgDepCache &Cache, bool const DebugAutoInstall, pkgCache::VerIterator const &PV, unsigned long Depth, APT::PackageVector &toUpgrade) /*{{{*/
+static bool MarkInstall_CollectReverseDepends(pkgDepCache &Cache, bool const DebugAutoInstall, pkgCache::VerIterator const &PV, unsigned long Depth, APT::PackageVector &toUpgrade, APT::PackageVector const &delayedRemove) /*{{{*/
{
auto CurrentVer = PV.ParentPkg().CurrentVer();
if (CurrentVer.end())
@@ -1474,6 +1474,9 @@ static bool MarkInstall_CollectReverseDepends(pkgDepCache &Cache, bool const Deb
// Skip non-installed versions and packages already marked for upgrade
if (ParentPkg.CurrentVer() != D.ParentVer() || Cache[ParentPkg].Install())
continue;
+ // Skip rev-depends we already tagged for removal
+ if (Cache[ParentPkg].Delete() || std::find(delayedRemove.begin(), delayedRemove.end(), ParentPkg) != delayedRemove.end())
+ continue;
// We only handle important positive dependencies, RemoveConflictsIfNotUpgradeable handles negative
if (not Cache.IsImportantDep(D) || D.IsNegative())
continue;
@@ -1722,7 +1725,7 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg, bool AutoInst,
return false;
hasFailed = true;
}
- if (not MarkInstall_CollectReverseDepends(*this, DebugAutoInstall, PV, Depth, toUpgrade))
+ if (not MarkInstall_CollectReverseDepends(*this, DebugAutoInstall, PV, Depth, toUpgrade, delayedRemove))
{
if (failEarly)
return false;
diff --git a/test/integration/test-not-upgrading-removed-depends b/test/integration/test-not-upgrading-removed-depends
new file mode 100755
index 000000000..54b20422c
--- /dev/null
+++ b/test/integration/test-not-upgrading-removed-depends
@@ -0,0 +1,50 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+setupenvironment
+configarchitecture 'amd64'
+
+insertpackage 'unstable' 'untouchable-for-solving' 'all' '1' 'Conflicts: main'
+insertpackage 'installed' 'bad' 'all' '1' 'Depends: main (= 1)'
+insertpackage 'unstable' 'bad' 'all' '2' 'Depends: main (= 2), untouchable-for-solving'
+
+insertpackage 'installed' 'main' 'all' '1'
+insertpackage 'unstable' 'main' 'all' '2' 'Breaks: bad'
+
+insertpackage 'unstable' 'else' 'all' '1'
+insertpackage 'unstable' 'meta' 'all' '1' 'Depends: main (= 2) | else'
+
+setupaptarchive
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following packages will be REMOVED:
+ bad
+The following packages will be upgraded:
+ main
+1 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
+Remv bad [1]
+Inst main [1] (2 unstable [all])
+Conf main (2 unstable [all])' apt install -s main
+testsuccess apt install -s main -o Debug::pkgProblemResolver=1 -o Debug::pkgDepCache::Marker=1 -o Debug::pkgDepCache::AutoInstall=1
+testfailure grep 'untouchable-for-solving' rootdir/tmp/testsuccess.output
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following additional packages will be installed:
+ main
+The following packages will be REMOVED:
+ bad
+The following NEW packages will be installed:
+ meta
+The following packages will be upgraded:
+ main
+1 upgraded, 1 newly installed, 1 to remove and 0 not upgraded.
+Remv bad [1]
+Inst main [1] (2 unstable [all])
+Inst meta (1 unstable [all])
+Conf main (2 unstable [all])
+Conf meta (1 unstable [all])' apt install -s meta
+testsuccess apt install -s meta -o Debug::pkgProblemResolver=1 -o Debug::pkgDepCache::Marker=1 -o Debug::pkgDepCache::AutoInstall=1
+testfailure grep 'untouchable-for-solving' rootdir/tmp/testsuccess.output