@@ -, +, @@ --- pym/_emerge/depgraph.py | 83 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 13 deletions(-) --- a/pym/_emerge/depgraph.py +++ a/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) @@ -2095,6 +2096,13 @@ class depgraph(object): arg = arg_stack.pop() if arg in traversed_set_args: continue + + # If a node with the same hash already exists in + # the digraph, preserve the existing instance which + # may have a different reset_depth attribute + # (distiguishes user arguments from sets added for + # another reason such as complete mode). + arg = self._dynamic_config.digraph.get(arg, arg) traversed_set_args.add(arg) if add_to_digraph: @@ -2114,8 +2122,16 @@ 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) + + # Preserve instances already in the graph (same + # reason as for the "arg" variable above). + 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 +2180,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 +2459,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 +2767,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 +4001,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 +5890,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 +8544,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 +8626,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) --