1 |
Author: zmedico |
2 |
Date: 2008-12-04 05:38:09 +0000 (Thu, 04 Dec 2008) |
3 |
New Revision: 12148 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/_emerge/__init__.py |
7 |
Log: |
8 |
Bug #249185 - For common cases in which USE deps trigger SLOT conflicts, give |
9 |
a short explanation and suggest a course of action to solve the problem. |
10 |
|
11 |
|
12 |
Modified: main/trunk/pym/_emerge/__init__.py |
13 |
=================================================================== |
14 |
--- main/trunk/pym/_emerge/__init__.py 2008-12-03 20:47:05 UTC (rev 12147) |
15 |
+++ main/trunk/pym/_emerge/__init__.py 2008-12-04 05:38:09 UTC (rev 12148) |
16 |
@@ -4349,23 +4349,6 @@ |
17 |
automatically, but support for backtracking (removal nodes that have |
18 |
already been selected) will be required in order to handle all possible |
19 |
cases. |
20 |
- |
21 |
- When a slot conflict occurs due to USE deps, there are a few |
22 |
- different cases to consider: |
23 |
- |
24 |
- 1) New USE are correctly set but --newuse wasn't requested so an |
25 |
- installed package with incorrect USE happened to get pulled |
26 |
- into graph before the new one. |
27 |
- |
28 |
- 2) New USE are incorrectly set but an installed package has correct |
29 |
- USE so it got pulled into the graph, and a new instance also got |
30 |
- pulled in due to --newuse or an upgrade. |
31 |
- |
32 |
- 3) Multiple USE deps exist that can't be satisfied simultaneously, |
33 |
- and multiple package instances got pulled into the same slot to |
34 |
- satisfy the conflicting deps. |
35 |
- |
36 |
- TODO: Distinguish the above cases and tailor messages to suit them. |
37 |
""" |
38 |
|
39 |
if not self._slot_collision_info: |
40 |
@@ -4381,6 +4364,8 @@ |
41 |
indent = " " |
42 |
# Max number of parents shown, to avoid flooding the display. |
43 |
max_parents = 3 |
44 |
+ explanation_columns = 70 |
45 |
+ explanations = 0 |
46 |
for (slot_atom, root), slot_nodes \ |
47 |
in self._slot_collision_info.iteritems(): |
48 |
msg.append(str(slot_atom)) |
49 |
@@ -4446,11 +4431,20 @@ |
50 |
else: |
51 |
msg.append(" (no parents)\n") |
52 |
msg.append("\n") |
53 |
+ explanation = self._slot_conflict_explanation(slot_nodes) |
54 |
+ if explanation: |
55 |
+ explanations += 1 |
56 |
+ msg.append(indent + "Explanation:\n\n") |
57 |
+ for line in textwrap.wrap(explanation, explanation_columns): |
58 |
+ msg.append(2*indent + line + "\n") |
59 |
+ msg.append("\n") |
60 |
msg.append("\n") |
61 |
sys.stderr.write("".join(msg)) |
62 |
sys.stderr.flush() |
63 |
|
64 |
- if "--quiet" in self.myopts: |
65 |
+ explanations_for_all = explanations == len(self._slot_collision_info) |
66 |
+ |
67 |
+ if explanations_for_all or "--quiet" in self.myopts: |
68 |
return |
69 |
|
70 |
msg = [] |
71 |
@@ -4478,6 +4472,92 @@ |
72 |
f.end_paragraph(1) |
73 |
f.writer.flush() |
74 |
|
75 |
+ def _slot_conflict_explanation(self, slot_nodes): |
76 |
+ """ |
77 |
+ When a slot conflict occurs due to USE deps, there are a few |
78 |
+ different cases to consider: |
79 |
+ |
80 |
+ 1) New USE are correctly set but --newuse wasn't requested so an |
81 |
+ installed package with incorrect USE happened to get pulled |
82 |
+ into graph before the new one. |
83 |
+ |
84 |
+ 2) New USE are incorrectly set but an installed package has correct |
85 |
+ USE so it got pulled into the graph, and a new instance also got |
86 |
+ pulled in due to --newuse or an upgrade. |
87 |
+ |
88 |
+ 3) Multiple USE deps exist that can't be satisfied simultaneously, |
89 |
+ and multiple package instances got pulled into the same slot to |
90 |
+ satisfy the conflicting deps. |
91 |
+ |
92 |
+ Currently, explanations and suggested courses of action are generated |
93 |
+ for cases 1 and 2. Case 3 is too complex to give a useful suggestion. |
94 |
+ """ |
95 |
+ |
96 |
+ if len(slot_nodes) != 2: |
97 |
+ # Suggestions are only implemented for |
98 |
+ # conflicts between two packages. |
99 |
+ return None |
100 |
+ |
101 |
+ all_conflict_atoms = self._slot_conflict_parent_atoms |
102 |
+ matched_node = None |
103 |
+ matched_atoms = None |
104 |
+ unmatched_node = None |
105 |
+ for node in slot_nodes: |
106 |
+ parent_atoms = self._parent_atoms.get(node) |
107 |
+ if not parent_atoms: |
108 |
+ # Normally, there are always parent atoms. If there are |
109 |
+ # none then something unexpected is happening and there's |
110 |
+ # currently no suggestion for this case. |
111 |
+ return None |
112 |
+ conflict_atoms = all_conflict_atoms.intersection(parent_atoms) |
113 |
+ for parent_atom in conflict_atoms: |
114 |
+ parent, atom = parent_atom |
115 |
+ if not atom.use: |
116 |
+ # Suggestions are currently only implemented for cases |
117 |
+ # in which all conflict atoms have USE deps. |
118 |
+ return None |
119 |
+ if conflict_atoms: |
120 |
+ if matched_node is not None: |
121 |
+ # If conflict atoms match multiple nodes |
122 |
+ # then there's no suggestion. |
123 |
+ return None |
124 |
+ matched_node = node |
125 |
+ matched_atoms = conflict_atoms |
126 |
+ else: |
127 |
+ if unmatched_node is not None: |
128 |
+ # Neither node is matched by conflict atoms, and |
129 |
+ # there is no suggestion for this case. |
130 |
+ return None |
131 |
+ unmatched_node = node |
132 |
+ |
133 |
+ if matched_node is None or unmatched_node is None: |
134 |
+ # This shouldn't happen. |
135 |
+ return None |
136 |
+ |
137 |
+ if unmatched_node.installed and not matched_node.installed: |
138 |
+ return "New USE are correctly set, but --newuse wasn't" + \ |
139 |
+ " requested, so an installed package with incorrect USE " + \ |
140 |
+ "happened to get pulled into the dependency graph. " + \ |
141 |
+ "In order to solve " + \ |
142 |
+ "this, either specify the --newuse option or explicitly " + \ |
143 |
+ " reinstall '%s'." % matched_node.slot_atom |
144 |
+ |
145 |
+ if matched_node.installed and not unmatched_node.installed: |
146 |
+ atoms = [atom for parent, atom in matched_atoms] |
147 |
+ explanation = ("New USE for '%s' are incorrectly set. " + \ |
148 |
+ "In order to solve this, adjust USE to satisfy '%s'") % \ |
149 |
+ (matched_node.slot_atom, atoms[0]) |
150 |
+ if len(atoms) > 1: |
151 |
+ for atom in atoms[1:-1]: |
152 |
+ explanation += ", '%s'" % (atom,) |
153 |
+ if len(atoms) > 2: |
154 |
+ explanation += "," |
155 |
+ explanation += " and '%s'" % (atoms[-1],) |
156 |
+ explanation += "." |
157 |
+ return explanation |
158 |
+ |
159 |
+ return None |
160 |
+ |
161 |
def _process_slot_conflicts(self): |
162 |
""" |
163 |
Process slot conflict data to identify specific atoms which |