1 |
Author: zmedico |
2 |
Date: 2009-01-10 06:24:52 +0000 (Sat, 10 Jan 2009) |
3 |
New Revision: 12408 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/_emerge/__init__.py |
7 |
Log: |
8 |
When there are unresolved blockers, display the conflicting packages along |
9 |
with the packages that pulled them in (similar to the slot conflict display). |
10 |
This is helpful for troubleshooting cases in which blockers don't solve |
11 |
automatically and the reasons are not apparent from the normal merge list |
12 |
display. |
13 |
|
14 |
|
15 |
Modified: main/trunk/pym/_emerge/__init__.py |
16 |
=================================================================== |
17 |
--- main/trunk/pym/_emerge/__init__.py 2009-01-10 04:03:19 UTC (rev 12407) |
18 |
+++ main/trunk/pym/_emerge/__init__.py 2009-01-10 06:24:52 UTC (rev 12408) |
19 |
@@ -4484,6 +4484,12 @@ |
20 |
self._irrelevant_blockers = digraph() |
21 |
# Contains only unsolvable Package -> Blocker edges |
22 |
self._unsolvable_blockers = digraph() |
23 |
+ # Contains all Blocker -> Blocked Package edges |
24 |
+ self._blocked_pkgs = digraph() |
25 |
+ # Contains world packages that have been protected from |
26 |
+ # uninstallation but may not have been added to the graph |
27 |
+ # if the graph is not complete yet. |
28 |
+ self._blocked_world_pkgs = {} |
29 |
self._slot_collision_info = {} |
30 |
# Slot collision nodes are not allowed to block other packages since |
31 |
# blocker validation is only able to account for one package per slot. |
32 |
@@ -6444,6 +6450,9 @@ |
33 |
# is already done and this would be likely to |
34 |
# confuse users if displayed like a normal blocker. |
35 |
continue |
36 |
+ |
37 |
+ self._blocked_pkgs.add(pkg, blocker) |
38 |
+ |
39 |
if parent.operation == "merge": |
40 |
# Maybe the blocked package can be replaced or simply |
41 |
# unmerged to resolve this block. |
42 |
@@ -6462,6 +6471,8 @@ |
43 |
# merge of either package is triggered. |
44 |
continue |
45 |
|
46 |
+ self._blocked_pkgs.add(pkg, blocker) |
47 |
+ |
48 |
# Maybe the blocking package can be |
49 |
# unmerged to resolve this block. |
50 |
if parent.operation == "merge" and pkg.installed: |
51 |
@@ -6514,7 +6525,7 @@ |
52 |
def _accept_blocker_conflicts(self): |
53 |
acceptable = False |
54 |
for x in ("--buildpkgonly", "--fetchonly", |
55 |
- "--fetch-all-uri", "--nodeps", "--pretend"): |
56 |
+ "--fetch-all-uri", "--nodeps"): |
57 |
if x in self.myopts: |
58 |
acceptable = True |
59 |
break |
60 |
@@ -6977,6 +6988,7 @@ |
61 |
break |
62 |
if not satisfied: |
63 |
skip = True |
64 |
+ self._blocked_world_pkgs[inst_pkg] = atom |
65 |
break |
66 |
except portage.exception.InvalidDependString, e: |
67 |
portage.writemsg("!!! Invalid PROVIDE in " + \ |
68 |
@@ -7208,6 +7220,74 @@ |
69 |
portage.writemsg("\n", noiselevel=-1) |
70 |
for line in wrap(msg, 70): |
71 |
portage.writemsg(prefix + line + "\n", noiselevel=-1) |
72 |
+ |
73 |
+ # Display the conflicting packages along with the packages |
74 |
+ # that pulled them in. This is helpful for troubleshooting |
75 |
+ # cases in which blockers don't solve automatically and |
76 |
+ # the reasons are not apparent from the normal merge list |
77 |
+ # display. |
78 |
+ |
79 |
+ conflict_pkgs = {} |
80 |
+ for blocker in blockers: |
81 |
+ for pkg in chain(self._blocked_pkgs.child_nodes(blocker), \ |
82 |
+ self._blocker_parents.parent_nodes(blocker)): |
83 |
+ parent_atoms = self._parent_atoms.get(pkg) |
84 |
+ if not parent_atoms: |
85 |
+ atom = self._blocked_world_pkgs.get(pkg) |
86 |
+ if atom is not None: |
87 |
+ parent_atoms = set([("@world", atom)]) |
88 |
+ if parent_atoms: |
89 |
+ conflict_pkgs[pkg] = parent_atoms |
90 |
+ |
91 |
+ if conflict_pkgs: |
92 |
+ msg = [] |
93 |
+ msg.append("\n") |
94 |
+ indent = " " |
95 |
+ # Max number of parents shown, to avoid flooding the display. |
96 |
+ max_parents = 3 |
97 |
+ for pkg, parent_atoms in conflict_pkgs.iteritems(): |
98 |
+ |
99 |
+ pruned_list = set() |
100 |
+ |
101 |
+ # Prefer conflict packages over others. |
102 |
+ for parent_atom in parent_atoms: |
103 |
+ if len(pruned_list) >= max_parents: |
104 |
+ break |
105 |
+ parent, atom = parent_atom |
106 |
+ if parent in conflict_pkgs: |
107 |
+ pruned_list.add(parent_atom) |
108 |
+ |
109 |
+ for parent_atom in parent_atoms: |
110 |
+ if len(pruned_list) >= max_parents: |
111 |
+ break |
112 |
+ pruned_list.add(parent_atom) |
113 |
+ |
114 |
+ omitted_parents = len(parent_atoms) - len(pruned_list) |
115 |
+ msg.append(indent + "%s pulled in by\n" % pkg) |
116 |
+ |
117 |
+ for parent_atom in pruned_list: |
118 |
+ parent, atom = parent_atom |
119 |
+ msg.append(2*indent) |
120 |
+ if isinstance(parent, |
121 |
+ (PackageArg, AtomArg)): |
122 |
+ # For PackageArg and AtomArg types, it's |
123 |
+ # redundant to display the atom attribute. |
124 |
+ msg.append(str(parent)) |
125 |
+ else: |
126 |
+ # Display the specific atom from SetArg or |
127 |
+ # Package types. |
128 |
+ msg.append("%s required by %s" % (atom, parent)) |
129 |
+ msg.append("\n") |
130 |
+ |
131 |
+ if omitted_parents: |
132 |
+ msg.append(2*indent) |
133 |
+ msg.append("(and %d more)\n" % omitted_parents) |
134 |
+ |
135 |
+ msg.append("\n") |
136 |
+ |
137 |
+ sys.stderr.write("".join(msg)) |
138 |
+ sys.stderr.flush() |
139 |
+ |
140 |
if "--quiet" not in self.myopts: |
141 |
show_blocker_docs_link() |