[Merge] ~juliank/ubuntu-release-upgrader:ubuntu/noble into ubuntu-release-upgrader:ubuntu/noble
Julian Andres Klode
mp+472686 at code.launchpad.net
Thu Sep 5 18:22:46 UTC 2024
Detailed explanation as why it is the same: git diff -w 68638f7c342f0157c356cbeba403abdc1f37ceb1^ DistUpgrade/DistUpgradeController.py
So first we add all our new bits for the new Algorithm, which is essentially split up into two loops to handle the special case of forced obsolete packages allowing removal of reverse dependencies (see it's handling in tryMarkObsoleteForRemoval). We also enable the log redirector (this is important later).
diff --git a/DistUpgrade/DistUpgradeController.py b/DistUpgrade/DistUpgradeController.py
index 338274e52..0eb8b6340 100644
--- a/DistUpgrade/DistUpgradeController.py
+++ b/DistUpgrade/DistUpgradeController.py
@@ -1998,13 +1998,62 @@ class DistUpgradeController(object):
logging.debug("remove_candidates: '%s'" % remove_candidates)
logging.debug("Start checking for obsolete pkgs")
progress = self._view.getOpCacheProgress()
+ scheduled_remove = set()
+
+ with self.cache.actiongroup():
+ # Forced obsoletes we remove, removing any of their dependencies, hence do a first loop with auto_fix=True
+ for (i, pkgname) in enumerate(remove_candidates):
+ progress.update((i/float(len(remove_candidates)))*100.0 / 2)
+ if pkgname in self.foreign_pkgs and pkgname in self.forced_obsoletes:
+ self._view.processEvents()
+ if not self.cache.tryMarkObsoleteForRemoval(pkgname, remove_candidates, self.forced_obsoletes, self.foreign_pkgs, auto_fix=True):
+ logging.debug("'%s' scheduled for remove but not safe to remove, skipping", pkgname)
+ else:
+ scheduled_remove.add(pkgname)
+
+ # Now let's try to remove other packages
+ for (i, pkgname) in enumerate(remove_candidates):
+ progress.update((i/float(len(remove_candidates)))*100.0 / 2 + 50)
+ if pkgname not in self.foreign_pkgs:
+ self._view.processEvents()
+ if not self.cache.tryMarkObsoleteForRemoval(pkgname, remove_candidates, self.forced_obsoletes, self.foreign_pkgs, auto_fix=False):
+ logging.debug("'%s' scheduled for remove but not safe to remove, skipping", pkgname)
+ else:
+ scheduled_remove.add(pkgname)
+
+ # We have scheduled their removals, but not any reverse-dependencies. If anything is broken now,
+ # resolve them by keeping back the obsolete packages.
+ self.cache._startAptResolverLog()
+ pr = apt.ProblemResolver(self.cache)
+ try:
+ pr.resolve_by_keep()
+ except Exception:
+ pass
+
If this code failed, we enter the fallback branch which will restore the old behavior:
+ if self.cache.broken_count > 0:
+ logging.debug("resolve_by_keep() failed to resolve conflicts from removing obsolete packages, falling back to slower implementation.")
To do that, it first reverts the changes it made in the previous two loops (note we keep the new scheduled_remove set, it is only used for logging later on):
+ self.cache.clear()
+ scheduled_remove = set()
So now we enter the exact same loop as before except that we explicitly pass `auto_fix=True` and add all succesfully removed packages to scheduled_remove still:
with self.cache.actiongroup():
for (i, pkgname) in enumerate(remove_candidates):
progress.update((i/float(len(remove_candidates)))*100.0)
if pkgname not in self.foreign_pkgs:
self._view.processEvents()
- if not self.cache.tryMarkObsoleteForRemoval(pkgname, remove_candidates, self.forced_obsoletes, self.foreign_pkgs):
+ if not self.cache.tryMarkObsoleteForRemoval(pkgname, remove_candidates, self.forced_obsoletes, self.foreign_pkgs, auto_fix=True):
logging.debug("'%s' scheduled for remove but not safe to remove, skipping", pkgname)
+ else:
+ scheduled_remove.add(pkgname)
The final new bit stops the apt resolver log we started at the top and prints any removals that were scheduled but have disappeared (this should not be any for the legacy algorithm, but we do add them to the set now - so we can keep the changes):
+
+ self.cache._stopAptResolverLog()
+
+ # resolve_by_keep() will revert any unsafe removals, so we need to list them here again.
+ for pkgname in scheduled_remove:
+ if (
+ pkgname in self.cache and
+ not self.cache[pkgname].marked_delete
+ ):
+ logging.debug("obsolete package '%s' could not be removed", pkgname)
+
If you do the same for tryMarkObsoleteForRemoval you see it is exactly the same code, just a bunch of blocks are wrapped in `if auto_fix` (and we forward the `auto_fix=` to mark_delete(); the default there is `True` [which is what we pass in this commit in the fallback case])
- def tryMarkObsoleteForRemoval(self, pkgname, remove_candidates, forced_obsoletes, foreign_pkgs):
+ def tryMarkObsoleteForRemoval(self, pkgname, remove_candidates, forced_obsoletes, foreign_pkgs, auto_fix):
#logging.debug("tryMarkObsoleteForRemoval(): %s" % pkgname)
# coherence check, first see if it looks like a running kernel pkg
if pkgname.endswith(self.uname):
@@ -972,10 +993,12 @@ class MyCache(apt.Cache):
# if this package has not been forced obsolete, only
# delete it if it doesn't remove other dependents
# that are not obsolete as well
+ if auto_fix:
self.create_snapshot()
try:
- self[pkgname].mark_delete(purge=purge)
+ self[pkgname].mark_delete(purge=purge, auto_fix=auto_fix)
self.view.processEvents()
+ if auto_fix:
if pkgname in forced_obsoletes:
return True
#logging.debug("marking '%s' for removal" % pkgname)
@@ -989,6 +1012,7 @@ class MyCache(apt.Cache):
return False
except (SystemError, KeyError) as e:
logging.warning("_tryMarkObsoleteForRemoval failed for '%s' (%s: %s)" % (pkgname, repr(e), e))
+ if auto_fix:
self.restore_snapshot()
return False
return True
--
https://code.launchpad.net/~juliank/ubuntu-release-upgrader/+git/ubuntu-release-upgrader/+merge/472686
Your team Ubuntu Core Development Team is subscribed to branch ubuntu-release-upgrader:ubuntu/noble.
More information about the Ubuntu-reviews
mailing list