Gentoo Archives: gentoo-commits

From: "Zac Medico (zmedico)" <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r12125 - main/trunk/pym/_emerge
Date: Mon, 01 Dec 2008 06:51:32
Message-Id: E1L72cz-0000tF-VN@stork.gentoo.org
1 Author: zmedico
2 Date: 2008-12-01 06:51:28 +0000 (Mon, 01 Dec 2008)
3 New Revision: 12125
4
5 Modified:
6 main/trunk/pym/_emerge/__init__.py
7 Log:
8 Bug #249185 - For more useful output in cases when one or more USE deps
9 trigger "SLOT conflicts", show the specific atoms that triggered the
10 conflict. TODO: Distiguish between various possible causes and tailor
11 messages to suit them.
12
13
14 Modified: main/trunk/pym/_emerge/__init__.py
15 ===================================================================
16 --- main/trunk/pym/_emerge/__init__.py 2008-11-30 00:12:34 UTC (rev 12124)
17 +++ main/trunk/pym/_emerge/__init__.py 2008-12-01 06:51:28 UTC (rev 12125)
18 @@ -4323,6 +4323,8 @@
19 # Slot collision nodes are not allowed to block other packages since
20 # blocker validation is only able to account for one package per slot.
21 self._slot_collision_nodes = set()
22 + self._parent_atoms = {}
23 + self._slot_conflict_parent_atoms = set()
24 self._serialized_tasks_cache = None
25 self._scheduler_graph = None
26 self._displayed_list = None
27 @@ -4346,8 +4348,26 @@
28 the packages. In some cases it may be possible to resolve this
29 automatically, but support for backtracking (removal nodes that have
30 already been selected) will be required in order to handle all possible
31 - cases."""
32 + cases.
33
34 + When a slot conflict occurs due to USE deps, there are a few
35 + different cases to consider:
36 +
37 + 1) New USE are correctly set but --newuse wasn't requested so an
38 + installed package with incorrect USE happened to get pulled
39 + into graph before the new one.
40 +
41 + 2) New USE are incorrectly set but an installed package has correct
42 + USE so it got pulled into the graph, and a new instance also got
43 + pulled in due to --newuse or an upgrade.
44 +
45 + 3) Multiple USE deps exist that can't be satisfied simultaneously,
46 + and multiple package instances got pulled into the same slot to
47 + satisfy the conflicting deps.
48 +
49 + TODO: Distinguish the above cases and tailor messages to suit them.
50 + """
51 +
52 if not self._slot_collision_info:
53 return
54
55 @@ -4369,35 +4389,56 @@
56 for node in slot_nodes:
57 msg.append(indent)
58 msg.append(str(node))
59 - parents = self.digraph.parent_nodes(node)
60 - if parents:
61 - omitted_parents = 0
62 - if len(parents) > max_parents:
63 - pruned_list = []
64 + parent_atoms = self._parent_atoms.get(node)
65 + if parent_atoms:
66 + pruned_list = set()
67 + # Prefer conflict atoms over others.
68 + for parent_atom in parent_atoms:
69 + if len(pruned_list) >= max_parents:
70 + break
71 + if parent_atom in self._slot_conflict_parent_atoms:
72 + pruned_list.add(parent_atom)
73 +
74 + # If this package was pulled in by conflict atoms then
75 + # show those alone since those are the most interesting.
76 + if not pruned_list:
77 # When generating the pruned list, prefer instances
78 # of DependencyArg over instances of Package.
79 - for parent in parents:
80 + for parent_atom in parent_atoms:
81 + if len(pruned_list) >= max_parents:
82 + break
83 + parent, atom = parent_atom
84 if isinstance(parent, DependencyArg):
85 - pruned_list.append(parent)
86 + pruned_list.add(parent_atom)
87 # Prefer Packages instances that themselves have been
88 # pulled into collision slots.
89 - for parent in parents:
90 + for parent_atom in parent_atoms:
91 + if len(pruned_list) >= max_parents:
92 + break
93 + parent, atom = parent_atom
94 if isinstance(parent, Package) and \
95 (parent.slot_atom, parent.root) \
96 in self._slot_collision_info:
97 - pruned_list.append(parent)
98 - for parent in parents:
99 + pruned_list.add(parent_atom)
100 + for parent_atom in parent_atoms:
101 if len(pruned_list) >= max_parents:
102 break
103 - if not isinstance(parent, DependencyArg) and \
104 - parent not in pruned_list:
105 - pruned_list.append(parent)
106 - omitted_parents = len(parents) - len(pruned_list)
107 - parents = pruned_list
108 + pruned_list.add(parent_atom)
109 + omitted_parents = len(parent_atoms) - len(pruned_list)
110 + parent_atoms = pruned_list
111 msg.append(" pulled in by\n")
112 - for parent in parents:
113 + for parent_atom in parent_atoms:
114 + parent, atom = parent_atom
115 msg.append(2*indent)
116 - msg.append(str(parent))
117 + if isinstance(parent,
118 + (PackageArg, AtomArg)):
119 + # For PackageArg and AtomArg types, it's
120 + # redundant to display the atom attribute.
121 + msg.append(str(parent))
122 + else:
123 + # Display the specific atom from SetArg or
124 + # Package types.
125 + msg.append("%s required by %s" % (atom, parent))
126 msg.append("\n")
127 if omitted_parents:
128 msg.append(2*indent)
129 @@ -4437,6 +4478,40 @@
130 f.end_paragraph(1)
131 f.writer.flush()
132
133 + def _process_slot_conflicts(self):
134 + """
135 + Process slot conflict data to identify specific atoms which
136 + lead to conflict. These atoms only match a subset of the
137 + packages that have been pulled into a given slot.
138 + """
139 + for (slot_atom, root), slot_nodes \
140 + in self._slot_collision_info.iteritems():
141 +
142 + all_parent_atoms = set()
143 + for pkg in slot_nodes:
144 + parent_atoms = self._parent_atoms.get(pkg)
145 + if not parent_atoms:
146 + continue
147 + all_parent_atoms.update(parent_atoms)
148 +
149 + for pkg in slot_nodes:
150 + parent_atoms = self._parent_atoms.get(pkg)
151 + if parent_atoms is None:
152 + parent_atoms = set()
153 + self._parent_atoms[pkg] = parent_atoms
154 + for parent_atom in all_parent_atoms:
155 + if parent_atom in parent_atoms:
156 + continue
157 + # Use package set for matching since it will match via
158 + # PROVIDE when necessary, while match_from_list does not.
159 + parent, atom = parent_atom
160 + atom_set = InternalPackageSet(
161 + initial_atoms=(atom,))
162 + if atom_set.findAtomForPackage(pkg):
163 + parent_atoms.add(parent_atom)
164 + else:
165 + self._slot_conflict_parent_atoms.add(parent_atom)
166 +
167 def _reinstall_for_flags(self, forced_flags,
168 orig_use, orig_iuse, cur_use, cur_iuse):
169 """Return a set of flags that trigger reinstallation, or None if there
170 @@ -4557,7 +4632,6 @@
171 vardbapi = self.trees[pkg.root]["vartree"].dbapi
172 pkgsettings = self.pkgsettings[pkg.root]
173
174 - args = None
175 arg_atoms = None
176 if True:
177 try:
178 @@ -4568,8 +4642,6 @@
179 pkg, pkg.metadata["PROVIDE"], str(e))
180 return 0
181 del e
182 - else:
183 - args = [arg for arg, atom in arg_atoms]
184
185 if not pkg.onlydeps:
186 if not pkg.installed and \
187 @@ -4599,10 +4671,12 @@
188 existing_node_matches = False
189 if existing_node_matches:
190 # The existing node can be reused.
191 - if args:
192 - for arg in args:
193 - self.digraph.add(existing_node, arg,
194 + if arg_atoms:
195 + for parent_atom in arg_atoms:
196 + parent, atom = parent_atom
197 + self.digraph.add(existing_node, parent,
198 priority=priority)
199 + self._add_parent_atom(existing_node, parent_atom)
200 # If a direct circular dependency is not an unsatisfied
201 # buildtime dependency then drop it here since otherwise
202 # it can skew the merge order calculation in an unwanted
203 @@ -4611,26 +4685,12 @@
204 (priority.buildtime and not priority.satisfied):
205 self.digraph.addnode(existing_node, myparent,
206 priority=priority)
207 + if dep.atom is not None and dep.parent is not None:
208 + self._add_parent_atom(existing_node,
209 + (dep.parent, dep.atom))
210 return 1
211 else:
212
213 - if pkg.cpv == existing_node.cpv and \
214 - dep.atom is not None and \
215 - dep.atom.use:
216 - # Multiple different instances of the same version
217 - # (typically one installed and another not yet
218 - # installed) have been pulled into the graph due
219 - # to a USE dependency. The "slot collision" display
220 - # is not helpful in a case like this, so display it
221 - # as an unsatisfied dependency.
222 - self._unsatisfied_deps_for_display.append(
223 - ((dep.root, dep.atom), {"myparent":dep.parent}))
224 - self._add_slot_conflict(pkg)
225 - self.digraph.addnode(pkg, myparent, priority=priority)
226 - return 0
227 -
228 - if pkg in self._slot_collision_nodes:
229 - return 1
230 # A slot collision has occurred. Sometimes this coincides
231 # with unresolvable blockers, so the slot collision will be
232 # shown later if there are no unresolvable blockers.
233 @@ -4653,8 +4713,6 @@
234 self._slot_pkg_map[pkg.root][pkg.slot_atom] = pkg
235 self.mydbapi[pkg.root].cpv_inject(pkg)
236
237 - self.digraph.addnode(pkg, myparent, priority=priority)
238 -
239 if not pkg.installed:
240 # Allow this package to satisfy old-style virtuals in case it
241 # doesn't already. Any pre-existing providers will be preferred
242 @@ -4672,18 +4730,22 @@
243 del e
244 return 0
245
246 - if args:
247 + if arg_atoms:
248 self._set_nodes.add(pkg)
249
250 # Do this even when addme is False (--onlydeps) so that the
251 # parent/child relationship is always known in case
252 # self._show_slot_collision_notice() needs to be called later.
253 - if pkg.onlydeps:
254 - self.digraph.add(pkg, myparent, priority=priority)
255 - if args:
256 - for arg in args:
257 - self.digraph.add(pkg, arg, priority=priority)
258 + self.digraph.add(pkg, myparent, priority=priority)
259 + if dep.atom is not None and dep.parent is not None:
260 + self._add_parent_atom(pkg, (dep.parent, dep.atom))
261
262 + if arg_atoms:
263 + for parent_atom in arg_atoms:
264 + parent, atom = parent_atom
265 + self.digraph.add(pkg, parent, priority=priority)
266 + self._add_parent_atom(pkg, parent_atom)
267 +
268 """ This section determines whether we go deeper into dependencies or not.
269 We want to go deeper on a few occasions:
270 Installing package A, we need to make sure package A's deps are met.
271 @@ -4699,13 +4761,20 @@
272
273 self.spinner.update()
274
275 - if args:
276 + if arg_atoms:
277 depth = 0
278 pkg.depth = depth
279 if not previously_added:
280 dep_stack.append(pkg)
281 return 1
282
283 + def _add_parent_atom(self, pkg, parent_atom):
284 + parent_atoms = self._parent_atoms.get(pkg)
285 + if parent_atoms is None:
286 + parent_atoms = set()
287 + self._parent_atoms[pkg] = parent_atoms
288 + parent_atoms.add(parent_atom)
289 +
290 def _add_slot_conflict(self, pkg):
291 self._slot_collision_nodes.add(pkg)
292 slot_key = (pkg.slot_atom, pkg.root)
293 @@ -6266,6 +6335,9 @@
294 if not self.validate_blockers():
295 raise self._unknown_internal_error()
296
297 + if self._slot_collision_info:
298 + self._process_slot_conflicts()
299 +
300 def _serialize_tasks(self):
301 scheduler_graph = self.digraph.copy()
302 mygraph=self.digraph.copy()