diff options
author | Julian Andres Klode <jak@debian.org> | 2023-07-11 13:47:17 +0000 |
---|---|---|
committer | Julian Andres Klode <jak@debian.org> | 2023-07-11 13:47:17 +0000 |
commit | 7bb2b81090b1a5bd9ebb49a0d9fd5cfd9ddab95f (patch) | |
tree | c7b46bfd6100fd4634fdfa00a39336ad57a10c83 | |
parent | 50efb65f339e715e04af114bca44c9b8c53ad3ad (diff) | |
parent | 68ef41ea912f4879b0ee43419c13a3a8c9bfcd22 (diff) |
Merge branch 'pu/ubuntu-bug-2025462' into 'main'
dist-upgrade: Revert phased updates using keeps only
See merge request apt-team/apt!299
-rw-r--r-- | apt-pkg/algorithms.cc | 3 | ||||
-rw-r--r-- | apt-pkg/algorithms.h | 19 | ||||
-rw-r--r-- | apt-pkg/upgrade.cc | 47 | ||||
-rwxr-xr-x | test/integration/test-phased-updates-new-depends | 96 | ||||
-rwxr-xr-x | test/integration/test-ubuntu-bug-2025462-phased-dist-upgrade | 50 |
5 files changed, 201 insertions, 14 deletions
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 272917b08..3d4096a94 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -1234,7 +1234,8 @@ bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I) } // a newly broken policy (recommends/suggests) is a problem - if (Cache[I].NowPolicyBroken() == false && + if ((Flags[I->ID] & BrokenPolicyAllowed) == 0 && + Cache[I].NowPolicyBroken() == false && Cache[I].InstPolicyBroken() == true) { if (Debug == true) diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h index 12a77d4b8..f06a38c1b 100644 --- a/apt-pkg/algorithms.h +++ b/apt-pkg/algorithms.h @@ -102,10 +102,16 @@ class APT_PUBLIC pkgProblemResolver /*{{{*/ typedef pkgCache::PrvIterator PrvIterator; typedef pkgCache::Version Version; typedef pkgCache::Package Package; - - enum Flags {Protected = (1 << 0), PreInstalled = (1 << 1), - Upgradable = (1 << 2), ReInstateTried = (1 << 3), - ToRemove = (1 << 4)}; + + enum Flags + { + Protected = (1 << 0), + PreInstalled = (1 << 1), + Upgradable = (1 << 2), + ReInstateTried = (1 << 3), + ToRemove = (1 << 4), + BrokenPolicyAllowed = (1 << 5) + }; int *Scores; unsigned char *Flags; bool Debug; @@ -129,7 +135,10 @@ class APT_PUBLIC pkgProblemResolver /*{{{*/ inline void Protect(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= Protected; Cache.MarkProtected(Pkg);}; inline void Remove(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= ToRemove;}; - inline void Clear(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] &= ~(Protected | ToRemove);}; + inline void Clear(pkgCache::PkgIterator Pkg) { Flags[Pkg->ID] &= ~(Protected | ToRemove | BrokenPolicyAllowed); }; +#ifdef APT_COMPILING_APT + inline void AllowBrokenPolicy(pkgCache::PkgIterator Pkg) { Flags[Pkg->ID] |= BrokenPolicyAllowed; }; +#endif // Try to intelligently resolve problems by installing and removing packages bool Resolve(bool BrokenFix = false, OpProgress * const Progress = NULL); diff --git a/apt-pkg/upgrade.cc b/apt-pkg/upgrade.cc index e3e98e5c6..994a05859 100644 --- a/apt-pkg/upgrade.cc +++ b/apt-pkg/upgrade.cc @@ -85,13 +85,13 @@ struct PhasedUpgrader { if (Pkg->CurrentVer == 0) return false; - if (Cache[Pkg].InstallVer == 0) + if (Cache[Pkg].CandidateVer == 0) return false; - if (Cache[Pkg].InstVerIter(Cache).PhasedUpdatePercentage() == 100) + if (Cache[Pkg].CandidateVerIter(Cache).PhasedUpdatePercentage() == 100) return false; - if (IsSecurityUpdate(Cache[Pkg].InstVerIter(Cache))) + if (IsSecurityUpdate(Cache[Pkg].CandidateVerIter(Cache))) return false; - if (!IsIgnoredPhasedUpdate(Cache[Pkg].InstVerIter(Cache))) + if (!IsIgnoredPhasedUpdate(Cache[Pkg].CandidateVerIter(Cache))) return false; return true; @@ -133,15 +133,18 @@ static bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress) Progress->OverallProgress(0, 100, 1, _("Calculating upgrade")); pkgDepCache::ActionGroup group(Cache); - - PhasedUpgrader().HoldBackIgnoredPhasedUpdates(Cache, nullptr); + PhasedUpgrader phasedUpgrader; /* Upgrade all installed packages first without autoinst to help the resolver in versioned or-groups to upgrade the old solver instead of installing a new one (if the old solver is not the first one [anymore]) */ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + { + if (phasedUpgrader.ShouldKeep(Cache, I)) + continue; if (I->CurrentVer != 0) Cache.MarkInstall(I, false, 0, false); + } if (Progress != NULL) Progress->Progress(10); @@ -149,8 +152,12 @@ static bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress) /* Auto upgrade all installed packages, this provides the basis for the installation */ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + { + if (phasedUpgrader.ShouldKeep(Cache, I)) + continue; if (I->CurrentVer != 0) Cache.MarkInstall(I, true, 0, false); + } if (Progress != NULL) Progress->Progress(50); @@ -178,13 +185,19 @@ static bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress) if (isEssential == false || instEssential == true) continue; pkgCache::PkgIterator P = G.FindPreferredPkg(); + if (phasedUpgrader.ShouldKeep(Cache, P)) + continue; Cache.MarkInstall(P, true, 0, false); } } else if (essential != "none") for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + { + if (phasedUpgrader.ShouldKeep(Cache, I)) + continue; if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) Cache.MarkInstall(I, true, 0, false); + } if (Progress != NULL) Progress->Progress(55); @@ -192,8 +205,12 @@ static bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress) /* We do it again over all previously installed packages to force conflict resolution on them all. */ for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + { + if (phasedUpgrader.ShouldKeep(Cache, I)) + continue; if (I->CurrentVer != 0) Cache.MarkInstall(I, false, 0, false); + } if (Progress != NULL) Progress->Progress(65); @@ -216,9 +233,23 @@ static bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress) } } - PhasedUpgrader().HoldBackIgnoredPhasedUpdates(Cache, &Fix); + bool success = Fix.ResolveInternal(false); + if (success) + { + // Revert phased updates using keeps. An issue with ResolveByKeep is + // that it also keeps back packages due to (new) broken Recommends, + // even if Upgrade already decided this is fine, so we will mark all + // packages that dist-upgrade decided may have a broken policy as allowed + // to do so such that we do not keep them back again. + pkgProblemResolver FixPhasing(&Cache); + + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + if (Cache[I].InstPolicyBroken()) + FixPhasing.AllowBrokenPolicy(I); + PhasedUpgrader().HoldBackIgnoredPhasedUpdates(Cache, &FixPhasing); + success = FixPhasing.ResolveByKeepInternal(); + } - bool const success = Fix.ResolveInternal(false); if (Progress != NULL) Progress->Done(); return success; diff --git a/test/integration/test-phased-updates-new-depends b/test/integration/test-phased-updates-new-depends new file mode 100755 index 000000000..8cc9314ad --- /dev/null +++ b/test/integration/test-phased-updates-new-depends @@ -0,0 +1,96 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" + +setupenvironment +echo 'Debug::Phasing "1";' > rootdir/etc/apt/apt.conf.d/debug-phasing +configarchitecture 'i386' + +insertinstalledpackage 'has-new-depends' 'all' '1' '' +insertinstalledpackage 'has-new-recommends' 'all' '1' '' +insertinstalledpackage 'has-new-conflicts' 'all' '1' '' +insertinstalledpackage 'new-conflicts' 'all' '1' '' + +insertpackage 'unstable-updates' 'new-depends' 'all' '2' +insertpackage 'unstable-updates' 'new-recommends' 'all' '2' +insertpackage 'unstable-updates' 'has-new-depends' 'all' '2' 'Phased-Update-Percentage: 0 +Depends: new-depends' +insertpackage 'unstable-updates' 'has-new-recommends' 'all' '2' 'Phased-Update-Percentage: 0 +Recommends: new-recommends' +insertpackage 'unstable-updates' 'has-new-conflicts' 'all' '2' 'Phased-Update-Percentage: 0 +Conflicts: new-conflicts' + +setupaptarchive + + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages have been kept back: + has-new-conflicts has-new-depends has-new-recommends +0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded." aptget upgrade -s -q -o APT::Get::Always-Include-Phased-Updates=1 + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages have been kept back: + has-new-conflicts has-new-depends has-new-recommends +0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded." aptget upgrade -s -q + + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following NEW packages will be installed: + new-depends new-recommends +The following packages have been kept back: + has-new-conflicts +The following packages will be upgraded: + has-new-depends has-new-recommends +2 upgraded, 2 newly installed, 0 to remove and 1 not upgraded. +Inst new-depends (2 unstable-updates [all]) +Inst has-new-depends [1] (2 unstable-updates [all]) +Inst has-new-recommends [1] (2 unstable-updates [all]) +Inst new-recommends (2 unstable-updates [all]) +Conf new-depends (2 unstable-updates [all]) +Conf has-new-depends (2 unstable-updates [all]) +Conf has-new-recommends (2 unstable-updates [all]) +Conf new-recommends (2 unstable-updates [all])" aptget upgrade -s -q --with-new-pkgs -o APT::Get::Always-Include-Phased-Updates=1 + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages have been kept back: + has-new-conflicts has-new-depends has-new-recommends +0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded." aptget upgrade -s -q --with-new-pkgs + +: testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages will be REMOVED: + new-conflicts +The following NEW packages will be installed: + new-depends new-recommends +The following packages will be upgraded: + has-new-conflicts has-new-depends has-new-recommends +3 upgraded, 2 newly installed, 1 to remove and 0 not upgraded. +Remv new-conflicts [1] +Inst has-new-conflicts [1] (2 unstable-updates [all]) +Inst new-depends (2 unstable-updates [all]) +Inst has-new-depends [1] (2 unstable-updates [all]) +Inst has-new-recommends [1] (2 unstable-updates [all]) +Inst new-recommends (2 unstable-updates [all]) +Conf has-new-conflicts (2 unstable-updates [all]) +Conf new-depends (2 unstable-updates [all]) +Conf has-new-depends (2 unstable-updates [all]) +Conf has-new-recommends (2 unstable-updates [all]) +Conf new-recommends (2 unstable-updates [all])" aptget dist-upgrade -s -q -o APT::Get::Always-Include-Phased-Updates=1 + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages have been kept back: + has-new-conflicts has-new-depends has-new-recommends +0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded." aptget dist-upgrade -s -q diff --git a/test/integration/test-ubuntu-bug-2025462-phased-dist-upgrade b/test/integration/test-ubuntu-bug-2025462-phased-dist-upgrade new file mode 100755 index 000000000..eecadcda3 --- /dev/null +++ b/test/integration/test-ubuntu-bug-2025462-phased-dist-upgrade @@ -0,0 +1,50 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" + +setupenvironment +echo 'Debug::Phasing "1";' > rootdir/etc/apt/apt.conf.d/debug-phasing +configarchitecture 'i386' + +insertinstalledpackage 'gnome-shell' 'all' '1' 'Depends: mutter (>= 1), gnome-shell-common (= 1)' +insertinstalledpackage 'gnome-shell-common' 'all' '1' +insertinstalledpackage 'mutter' 'all' '1' + +insertpackage 'unstable-updates' 'gnome-shell-common' 'all' '2' 'Phased-Update-Percentage: 100' +insertpackage 'unstable-updates' 'gnome-shell' 'all' '2' 'Phased-Update-Percentage: 100 +Depends: mutter (>= 2), gnome-shell-common (= 2)' +insertpackage 'unstable-updates' 'mutter' 'all' '2' 'Phased-Update-Percentage: 0' + +setupaptarchive + +# This is the broken test case: +# +# The following packages will be REMOVED: +# gnome-shell +# The following packages have been kept back: +# mutter +# The following packages will be upgraded: +# gnome-shell-common +# 1 upgraded, 0 newly installed, 1 to remove and 1 not upgraded. + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages have been kept back: + gnome-shell gnome-shell-common mutter +0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded." aptget dist-upgrade -s -q + +testsuccessequal "Reading package lists... +Building dependency tree... +Calculating upgrade... +The following packages will be upgraded: + gnome-shell gnome-shell-common mutter +3 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. +Inst mutter [1] (2 unstable-updates [all]) +Inst gnome-shell [1] (2 unstable-updates [all]) [] +Inst gnome-shell-common [1] (2 unstable-updates [all]) +Conf mutter (2 unstable-updates [all]) +Conf gnome-shell (2 unstable-updates [all]) +Conf gnome-shell-common (2 unstable-updates [all])" aptget dist-upgrade -s -q -o APT::Get::Always-Include-Phased-Updates=1 |