summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apt-pkg/algorithms.cc3
-rw-r--r--apt-pkg/algorithms.h19
-rw-r--r--apt-pkg/upgrade.cc20
-rwxr-xr-xtest/integration/test-ubuntu-bug-2025462-phased-dist-upgrade50
4 files changed, 82 insertions, 10 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..3e1bb292b 100644
--- a/apt-pkg/upgrade.cc
+++ b/apt-pkg/upgrade.cc
@@ -134,8 +134,6 @@ static bool pkgDistUpgrade(pkgDepCache &Cache, OpProgress * const Progress)
pkgDepCache::ActionGroup group(Cache);
- PhasedUpgrader().HoldBackIgnoredPhasedUpdates(Cache, nullptr);
-
/* 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]) */
@@ -216,9 +214,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-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