From df395decc4981d267ac8bcdcb7e4bebd205ce81d Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Wed, 3 Sep 2014 15:39:10 -0700 Subject: [PATCH] depgraph._add_dep: fix bug #520950 This handles a case which occurs when _solve_non_slot_operator_slot_conflicts calls _create_graph. In this case, ignore unsatisfied deps for installed packages only if their depth is beyond the depth requested by the user and the dep was initially unsatisfied (not broken by a slot conflict in the current graph). Since depth is meaningless for packages that are not reachable as deep dependencies of arguments, the True constant is used as the depth value for any packages added via _complete_graph. Also, any sets added via _complete_graph have their reset_depth attribute set to False. --- pym/_emerge/depgraph.py | 77 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index d6cd24d..a7870bb 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -107,7 +107,7 @@ def _wildcard_set(atoms): class _frozen_depgraph_config(object): - def __init__(self, settings, trees, myopts, spinner): + def __init__(self, settings, trees, myopts, params, spinner): self.settings = settings self.target_root = settings["EROOT"] self.myopts = myopts @@ -115,6 +115,7 @@ class _frozen_depgraph_config(object): if settings.get("PORTAGE_DEBUG", "") == "1": self.edebug = 1 self.spinner = spinner + self.requested_depth = params.get("deep", 0) self._running_root = trees[trees._running_eroot]["root_config"] self.pkgsettings = {} self.trees = {} @@ -508,7 +509,7 @@ class depgraph(object): frozen_config=None, backtrack_parameters=BacktrackParameter(), allow_backtracking=False): if frozen_config is None: frozen_config = _frozen_depgraph_config(settings, trees, - myopts, spinner) + myopts, myparams, spinner) self._frozen_config = frozen_config self._dynamic_config = _dynamic_depgraph_config(self, myparams, allow_backtracking, backtrack_parameters) @@ -2114,8 +2115,17 @@ class depgraph(object): if nested_set is None: nested_set = root_config.sets.get(s) if nested_set is not None: + # Propagate the reset_depth attribute from + # parent set to nested set. nested_arg = SetArg(arg=token, pset=nested_set, + reset_depth=arg.reset_depth, root_config=root_config) + # If a node with the same hash already exists in + # the digraph, keep the existing instance which + # may have a different reset_depth attribute + # (meaning that it corresponds to a user + # argument). + nested_arg = self._dynamic_config.digraph.get(nested_arg, nested_arg) arg_stack.append(nested_arg) if add_to_digraph: self._dynamic_config.digraph.add(nested_arg, arg, @@ -2164,9 +2174,41 @@ class depgraph(object): dep.collapsed_priority.ignored): # This is an unnecessary build-time dep. return 1 + + # NOTE: For removal actions, allow_unsatisfied is always + # True since all existing removal actions traverse all + # installed deps deeply via the _complete_graph method, + # which calls _create_graph with allow_unsatisfied = True. if allow_unsatisfied: self._dynamic_config._unsatisfied_deps.append(dep) return 1 + + # The following case occurs when + # _solve_non_slot_operator_slot_conflicts calls + # _create_graph. In this case, ignore unsatisfied deps for + # installed packages only if their depth is beyond the depth + # requested by the user and the dep was initially + # unsatisfied (not broken by a slot conflict in the current + # graph). See bug #520950. + # NOTE: The value of dep.parent.depth is guaranteed to be + # either an integer or True, with the value True indicating + # that the parent has been pulled in by the _complete_graph + # method (rather than by explicit arguments or their deep + # dependencies). These cases must be distinguished because + # depth is meaningless for packages that are not reachable + # as deep dependencies of arguments. + if (self._dynamic_config._complete_mode and + isinstance(dep.parent, Package) and + dep.parent.installed and + (dep.parent.depth is True or + (self._frozen_config.requested_depth is not True and ++ dep.parent.depth >= self._frozen_config.requested_depth))): + inst_pkg, in_graph = \ + self._select_pkg_from_installed(dep.root, dep.atom) + if inst_pkg is None: + self._dynamic_config._initially_unsatisfied_deps.append(dep) + return 1 + self._dynamic_config._unsatisfied_deps_for_display.append( ((dep.root, dep.atom), {"myparent":dep.parent})) @@ -2411,14 +2453,17 @@ class depgraph(object): # Installing package A, we need to make sure package A's deps are met. # emerge --deep ; we need to recursively check dependencies of pkgspec # If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies. - if arg_atoms and depth > 0: + if arg_atoms and (depth is True or depth > 0): for parent, atom in arg_atoms: if parent.reset_depth: depth = 0 break - if previously_added and pkg.depth is not None: - depth = min(pkg.depth, depth) + if previously_added and isinstance(pkg.depth, int): + if depth is True: + depth = pkg.depth + else: + depth = min(pkg.depth, depth) pkg.depth = depth deep = self._dynamic_config.myparams.get("deep", 0) update = "--update" in self._frozen_config.myopts @@ -2716,7 +2761,10 @@ class depgraph(object): def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string, allow_unsatisfied): - depth = pkg.depth + 1 + if pkg.depth is True: + depth = True + else: + depth = pkg.depth + 1 deep = self._dynamic_config.myparams.get("deep", 0) recurse_satisfied = deep is True or depth <= deep debug = "--debug" in self._frozen_config.myopts @@ -3947,10 +3995,13 @@ class depgraph(object): # Recursively traversed virtual dependencies, and their # direct dependencies, are considered to have the same # depth as direct dependencies. - if parent.depth is None: - virt_depth = None - else: + if isinstance(parent.depth, int): virt_depth = parent.depth + 1 + else: + # The depth may be None when called via + # _select_atoms_probe, or it may be True + # for complete mode. + virt_depth = parent.depth chosen_atom_ids = frozenset(id(atom) for atom in mycheck[1]) selected_atoms = OrderedDict() node_stack = [(parent, None, None)] @@ -5833,14 +5884,14 @@ class depgraph(object): pset = root_config.sets[s] atom = SETPREFIX + s args.append(SetArg(arg=atom, pset=pset, - root_config=root_config)) + reset_depth=False, root_config=root_config)) self._set_args(args) for arg in self._expand_set_args(args, add_to_digraph=True): for atom in arg.pset.getAtoms(): self._dynamic_config._dep_stack.append( Dependency(atom=atom, root=arg.root_config.root, - parent=arg)) + parent=arg, depth=True)) if True: if self._dynamic_config._ignored_deps: @@ -8487,7 +8538,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp backtracked = 0 frozen_config = _frozen_depgraph_config(settings, trees, - myopts, spinner) + myopts, myparams, spinner) while backtracker: @@ -8569,7 +8620,7 @@ def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner): mergelist = mtimedb["resume"]["mergelist"] dropped_tasks = {} frozen_config = _frozen_depgraph_config(settings, trees, - myopts, spinner) + myopts, myparams, spinner) while True: mydepgraph = depgraph(settings, trees, myopts, myparams, spinner, frozen_config=frozen_config) -- 1.8.1.5