From 18469291ffc01ed8ca51e3f4d0f8fc8975e411b7 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Mon, 12 Jan 2009 08:21:52 +0000 Subject: [PATCH] When there are unresolved blockers, display the conflicting packages along with the packages that pulled them in (similar to the slot conflict display). This is helpful for troubleshooting cases in which blockers don't solve automatically and the reasons are not apparent from the normal merge list display. (trunk r12408) svn path=/main/branches/2.1.6/; revision=12466 --- pym/_emerge/__init__.py | 82 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 11500213f..ddc33d423 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -4468,6 +4468,12 @@ class depgraph(object): self._irrelevant_blockers = digraph() # Contains only unsolvable Package -> Blocker edges self._unsolvable_blockers = digraph() + # Contains all Blocker -> Blocked Package edges + self._blocked_pkgs = digraph() + # Contains world packages that have been protected from + # uninstallation but may not have been added to the graph + # if the graph is not complete yet. + self._blocked_world_pkgs = {} self._slot_collision_info = {} # Slot collision nodes are not allowed to block other packages since # blocker validation is only able to account for one package per slot. @@ -6428,6 +6434,9 @@ class depgraph(object): # is already done and this would be likely to # confuse users if displayed like a normal blocker. continue + + self._blocked_pkgs.add(pkg, blocker) + if parent.operation == "merge": # Maybe the blocked package can be replaced or simply # unmerged to resolve this block. @@ -6446,6 +6455,8 @@ class depgraph(object): # merge of either package is triggered. continue + self._blocked_pkgs.add(pkg, blocker) + # Maybe the blocking package can be # unmerged to resolve this block. if parent.operation == "merge" and pkg.installed: @@ -6498,7 +6509,7 @@ class depgraph(object): def _accept_blocker_conflicts(self): acceptable = False for x in ("--buildpkgonly", "--fetchonly", - "--fetch-all-uri", "--nodeps", "--pretend"): + "--fetch-all-uri", "--nodeps"): if x in self.myopts: acceptable = True break @@ -6961,6 +6972,7 @@ class depgraph(object): break if not satisfied: skip = True + self._blocked_world_pkgs[inst_pkg] = atom break except portage.exception.InvalidDependString, e: portage.writemsg("!!! Invalid PROVIDE in " + \ @@ -7192,6 +7204,74 @@ class depgraph(object): portage.writemsg("\n", noiselevel=-1) for line in wrap(msg, 70): portage.writemsg(prefix + line + "\n", noiselevel=-1) + + # Display the conflicting packages along with the packages + # that pulled them in. This is helpful for troubleshooting + # cases in which blockers don't solve automatically and + # the reasons are not apparent from the normal merge list + # display. + + conflict_pkgs = {} + for blocker in blockers: + for pkg in chain(self._blocked_pkgs.child_nodes(blocker), \ + self._blocker_parents.parent_nodes(blocker)): + parent_atoms = self._parent_atoms.get(pkg) + if not parent_atoms: + atom = self._blocked_world_pkgs.get(pkg) + if atom is not None: + parent_atoms = set([("@world", atom)]) + if parent_atoms: + conflict_pkgs[pkg] = parent_atoms + + if conflict_pkgs: + msg = [] + msg.append("\n") + indent = " " + # Max number of parents shown, to avoid flooding the display. + max_parents = 3 + for pkg, parent_atoms in conflict_pkgs.iteritems(): + + pruned_list = set() + + # Prefer conflict packages over others. + for parent_atom in parent_atoms: + if len(pruned_list) >= max_parents: + break + parent, atom = parent_atom + if parent in conflict_pkgs: + pruned_list.add(parent_atom) + + for parent_atom in parent_atoms: + if len(pruned_list) >= max_parents: + break + pruned_list.add(parent_atom) + + omitted_parents = len(parent_atoms) - len(pruned_list) + msg.append(indent + "%s pulled in by\n" % pkg) + + for parent_atom in pruned_list: + parent, atom = parent_atom + msg.append(2*indent) + if isinstance(parent, + (PackageArg, AtomArg)): + # For PackageArg and AtomArg types, it's + # redundant to display the atom attribute. + msg.append(str(parent)) + else: + # Display the specific atom from SetArg or + # Package types. + msg.append("%s required by %s" % (atom, parent)) + msg.append("\n") + + if omitted_parents: + msg.append(2*indent) + msg.append("(and %d more)\n" % omitted_parents) + + msg.append("\n") + + sys.stderr.write("".join(msg)) + sys.stderr.flush() + if "--quiet" not in self.myopts: show_blocker_docs_link() -- 2.26.2