summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2009-01-10 06:24:52 +0000
committerZac Medico <zmedico@gentoo.org>2009-01-10 06:24:52 +0000
commitfd5258a4cc3f7bfa4a29b0f05b9872b99654bebb (patch)
treeba55481a32ed2c6d8df558defd175c98ac6d63d5
parentRevert r12405 since it will be more convenient to use a separate graph to (diff)
downloadportage-multirepo-fd5258a4cc3f7bfa4a29b0f05b9872b99654bebb.tar.gz
portage-multirepo-fd5258a4cc3f7bfa4a29b0f05b9872b99654bebb.tar.bz2
portage-multirepo-fd5258a4cc3f7bfa4a29b0f05b9872b99654bebb.zip
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. svn path=/main/trunk/; revision=12408
-rw-r--r--pym/_emerge/__init__.py82
1 files changed, 81 insertions, 1 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index fb4937bf..5059ee77 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -4484,6 +4484,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.
@@ -6444,6 +6450,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.
@@ -6462,6 +6471,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:
@@ -6514,7 +6525,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
@@ -6977,6 +6988,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 " + \
@@ -7208,6 +7220,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()