aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2020-02-14 11:21:28 -0800
committerZac Medico <zmedico@gentoo.org>2020-02-14 15:10:37 -0800
commit079f8c4a36ccc2ef5e25e7a57cd0707640f82592 (patch)
tree78f0885fa2ad19d11838df2436b48e9dd23b7ab0 /lib/_emerge/depgraph.py
parentdepgraph: sort nested package set names for consistent results (diff)
downloadportage-079f8c4a36ccc2ef5e25e7a57cd0707640f82592.tar.gz
portage-079f8c4a36ccc2ef5e25e7a57cd0707640f82592.tar.bz2
portage-079f8c4a36ccc2ef5e25e7a57cd0707640f82592.zip
depclean: ensure consistency with update actions (bug 649622)
Make depclean traverse dependencies in the same order as update actions, in order to ensure consistency in decisions which are dependent on the order of dependency evaluation due to inconsistent use of || preferences in different packages. In unit tests, update test_virtual_w3m_realistic to assert that the order of graph traversal is deterministic and consistent between update and removal (depclean) actions. Bug: https://bugs.gentoo.org/649622 Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib/_emerge/depgraph.py')
-rw-r--r--lib/_emerge/depgraph.py21
1 files changed, 15 insertions, 6 deletions
diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 8e0d79e29..27696ad40 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -6955,9 +6955,18 @@ class depgraph(object):
# Removal actions may override sets with temporary
# replacements that have had atoms removed in order
# to implement --deselect behavior.
- required_set_names = set(required_sets[root])
depgraph_sets.sets.clear()
depgraph_sets.sets.update(required_sets[root])
+ if 'world' in depgraph_sets.sets:
+ # For consistent order of traversal for both update
+ # and removal (depclean) actions, sets other that
+ # world are always nested under the world set.
+ world_atoms = list(depgraph_sets.sets['world'])
+ world_atoms.extend(SETPREFIX + s for s in required_sets[root] if s != 'world')
+ depgraph_sets.sets['world'] = InternalPackageSet(initial_atoms=world_atoms)
+ required_set_names = {'world'}
+ else:
+ required_set_names = set(required_sets[root])
if "remove" not in self._dynamic_config.myparams and \
root == self._frozen_config.target_root and \
already_deep:
@@ -6967,7 +6976,7 @@ class depgraph(object):
not self._dynamic_config._dep_stack:
continue
root_config = self._frozen_config.roots[root]
- for s in required_set_names:
+ for s in sorted(required_set_names):
pset = depgraph_sets.sets.get(s)
if pset is None:
pset = root_config.sets[s]
@@ -6977,10 +6986,10 @@ class depgraph(object):
self._set_args(args)
for arg in self._expand_set_args(args, add_to_digraph=True):
- for atom in sorted(arg.pset.getAtoms(), reverse=True):
- self._dynamic_config._dep_stack.append(
- Dependency(atom=atom, root=arg.root_config.root,
- parent=arg, depth=self._UNREACHABLE_DEPTH))
+ for atom in sorted(arg.pset.getAtoms()):
+ if not self._add_dep(Dependency(atom=atom, root=arg.root_config.root,
+ parent=arg, depth=self._UNREACHABLE_DEPTH), allow_unsatisfied=True):
+ return 0
if True:
if self._dynamic_config._ignored_deps: