--- pym/portage/dep/__init__.py (revision 15839) +++ pym/portage/dep/__init__.py (working copy) @@ -213,7 +213,7 @@ # behavior will be explicitly enabled as necessary. _dep_check_strict = False -def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]): +def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[], metadata_store = None, inducing_use = set()): """ Takes a paren_reduce'd array and reduces the use? conditionals out leaving an array with subarrays @@ -245,7 +245,8 @@ head = mydeparray.pop(0) if not isinstance(head, basestring): - additions = use_reduce(head, uselist, masklist, matchall, excludeall) + additions = use_reduce(head, uselist, masklist, matchall, excludeall, \ + metadata_store=metadata_store, inducing_use=inducing_use) if additions: rlist.append(additions) elif rlist and rlist[-1] == "||": @@ -257,9 +258,12 @@ if head[-1:] == "?": # Use reduce next group on fail. # Pull any other use conditions and the following atom or list into a separate array newdeparray = [head] + new_inducing_use = inducing_use.copy() + while isinstance(newdeparray[-1], basestring) and \ newdeparray[-1][-1:] == "?": if mydeparray: + new_inducing_use.add(newdeparray[-1][:-1]) newdeparray.append(mydeparray.pop(0)) else: raise ValueError(_("Conditional with no target.")) @@ -307,7 +311,8 @@ if ismatch: target = newdeparray[-1] if isinstance(target, list): - additions = use_reduce(target, uselist, masklist, matchall, excludeall) + additions = use_reduce(target, uselist, masklist, matchall, excludeall, \ + metadata_store=metadata_store, inducing_use=new_inducing_use) if additions: rlist.append(additions) elif not _dep_check_strict: @@ -319,6 +324,11 @@ else: rlist += [head] + if inducing_use and metadata_store is not None: + if not head in metadata_store: + metadata_store[head] = inducing_use + else: + metadata_store[head].union(inducing_use) return rlist --- pym/portage/util/digraph.py (revision 15839) +++ pym/portage/util/digraph.py (working copy) @@ -17,12 +17,16 @@ # { node : ( { child : priority } , { parent : priority } ) } self.nodes = {} self.order = [] + self.metadata = {} - def add(self, node, parent, priority=0): + def add(self, node, parent, priority=0, metadata = set()): """Adds the specified node with the specified parent. If the dep is a soft-dep and the node already has a hard relationship to the parent, the relationship is left as hard.""" + + if metadata: + self.metadata[(node, parent)] = metadata if node not in self.nodes: self.nodes[node] = ({}, {}, node) @@ -86,6 +90,9 @@ Any endpoint vertices that become isolated will remain in the graph. """ + if (child, parent) in self.metadata: + del self.metadata[(child, parent)] + # Nothing should be modified when a KeyError is raised. for k in parent, child: if k not in self.nodes: @@ -245,6 +252,9 @@ parents_clone[parent] = priorities_clone clone.nodes[node] = (children_clone, parents_clone, node) clone.order = self.order[:] + clone.metadata = {} + for (a,b) in self.metadata: + clone.metadata[(a,b)] = self.metadata[(a,b)] return clone def delnode(self, node): @@ -273,7 +283,12 @@ else: output("(no children)\n") for child, priorities in self.nodes[node][0].items(): - output(" %s (%s)\n" % (child, priorities[-1],)) + msg = " %s (%s)" % (child, priorities[-1], ) + if (child, node) in self.metadata: + msg += " induced by USE=\"" + msg += " ".join(self.metadata[(child, node)]) + "\"" + msg += "\n" + output(msg) # Backward compatibility addnode = add --- pym/_emerge/depgraph.py (revision 15839) +++ pym/_emerge/depgraph.py (working copy) @@ -725,7 +725,7 @@ return 0 return 1 - def _add_dep(self, dep, allow_unsatisfied=False): + def _add_dep(self, dep, allow_unsatisfied=False, inducing_use = ""): debug = "--debug" in self._frozen_config.myopts buildpkgonly = "--buildpkgonly" in self._frozen_config.myopts nodeps = "--nodeps" in self._frozen_config.myopts @@ -834,11 +834,11 @@ self._dynamic_config._ignored_deps.append(dep) return 1 - if not self._add_pkg(dep_pkg, dep): + if not self._add_pkg(dep_pkg, dep, inducing_use): return 0 return 1 - def _add_pkg(self, pkg, dep): + def _add_pkg(self, pkg, dep, inducing_use = ""): myparent = None priority = None depth = 0 @@ -912,7 +912,7 @@ for parent_atom in arg_atoms: parent, atom = parent_atom self._dynamic_config.digraph.add(existing_node, parent, - priority=priority) + priority=priority, metadata=inducing_use) self._add_parent_atom(existing_node, parent_atom) # If a direct circular dependency is not an unsatisfied # buildtime dependency then drop it here since otherwise @@ -921,7 +921,7 @@ if existing_node != myparent or \ (priority.buildtime and not priority.satisfied): self._dynamic_config.digraph.addnode(existing_node, myparent, - priority=priority) + priority=priority, metadata=inducing_use) if dep.atom is not None and dep.parent is not None: self._add_parent_atom(existing_node, (dep.parent, dep.atom)) @@ -1028,7 +1028,7 @@ # Do this even when addme is False (--onlydeps) so that the # parent/child relationship is always known in case # self._show_slot_collision_notice() needs to be called later. - self._dynamic_config.digraph.add(pkg, myparent, priority=priority) + self._dynamic_config.digraph.add(pkg, myparent, priority=priority, metadata=inducing_use) if dep.atom is not None and dep.parent is not None: self._add_parent_atom(pkg, (dep.parent, dep.atom)) @@ -1173,11 +1173,11 @@ noiselevel=-1, level=logging.DEBUG) try: - + metadata_store = {} dep_string = portage.dep.paren_normalize( portage.dep.use_reduce( portage.dep.paren_reduce(dep_string), - uselist=pkg.use.enabled)) + uselist=pkg.use.enabled, metadata_store=metadata_store)) dep_string = list(self._queue_disjunctive_deps( pkg, dep_root, dep_priority, dep_string)) @@ -1196,7 +1196,7 @@ if not self._add_pkg_dep_string( pkg, dep_root, dep_priority, dep_string, - allow_unsatisfied, ignore_blockers=ignore_blockers): + allow_unsatisfied, ignore_blockers=ignore_blockers, metadata_store=metadata_store): return 0 except portage.exception.AmbiguousPackageName as e: @@ -1224,7 +1224,7 @@ return 1 def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string, - allow_unsatisfied, ignore_blockers=False): + allow_unsatisfied, ignore_blockers=False, metadata_store=None): depth = pkg.depth + 1 debug = "--debug" in self._frozen_config.myopts strict = pkg.type_name != "installed" @@ -1268,11 +1268,18 @@ if not atom.blocker and vardb.match(atom): mypriority.satisfied = True - if not self._add_dep(Dependency(atom=atom, - blocker=atom.blocker, child=child, depth=depth, parent=pkg, - priority=mypriority, root=dep_root), - allow_unsatisfied=allow_unsatisfied): - return 0 + if metadata_store is not None and atom in metadata_store: + if not self._add_dep(Dependency(atom=atom, + blocker=atom.blocker, child=child, depth=depth, parent=pkg, + priority=mypriority, root=dep_root), + allow_unsatisfied=allow_unsatisfied, inducing_use=metadata_store[atom]): + return 0 + else: + if not self._add_dep(Dependency(atom=atom, + blocker=atom.blocker, child=child, depth=depth, parent=pkg, + priority=mypriority, root=dep_root), + allow_unsatisfied=allow_unsatisfied): + return 0 selected_atoms.pop(pkg)