Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r12133 - in main/branches/prefix: bin man pym/_emerge
Date: Mon, 01 Dec 2008 21:14:53
Message-Id: E1L7G6T-0007Ka-EW@stork.gentoo.org
1 Author: grobian
2 Date: 2008-12-01 21:14:48 +0000 (Mon, 01 Dec 2008)
3 New Revision: 12133
4
5 Modified:
6 main/branches/prefix/bin/ebuild.sh
7 main/branches/prefix/man/emerge.1
8 main/branches/prefix/pym/_emerge/__init__.py
9 Log:
10 Merged from trunk -r12117:12126
11
12 | 12120 | Add 'automatically resolved' blockers to the --pretend docs. |
13 | zmedico | |
14
15 | 12122 | Add a sanity check inside depgraph._add_pkg() to ensure that |
16 | zmedico | the dependencies of the same package are never processed |
17 | | more than once. |
18
19 | 12124 | Change depgraph._slot_collision_info() from a set to a dict |
20 | zmedico | that contains sets of packages pulled into a given slot. |
21 | | This will make the data easier to analyze when implementing |
22 | | a fix for bug #249185. |
23
24 | 12125 | Bug #249185 - For more useful output in cases when one or |
25 | zmedico | more USE deps trigger "SLOT conflicts", show the specific |
26 | | atoms that triggered the conflict. TODO: Distiguish between |
27 | | various possible causes and tailor messages to suit them. |
28
29 | 12126 | Fix inconsistencies between the "clean" and "cleanrm" |
30 | zmedico | phases. |
31
32
33 Modified: main/branches/prefix/bin/ebuild.sh
34 ===================================================================
35 --- main/branches/prefix/bin/ebuild.sh 2008-12-01 21:10:53 UTC (rev 12132)
36 +++ main/branches/prefix/bin/ebuild.sh 2008-12-01 21:14:48 UTC (rev 12133)
37 @@ -1810,7 +1810,7 @@
38 unset BIN_PATH BIN BODY FUNC_SRC
39 fi
40
41 -if ! hasq ${EBUILD_PHASE} clean depend && \
42 +if ! hasq "$EBUILD_PHASE" clean cleanrm depend && \
43 [ -f "${T}"/environment ] ; then
44 # The environment may have been extracted from environment.bz2 or
45 # may have come from another version of ebuild.sh or something.
46 @@ -1856,7 +1856,7 @@
47 source_all_bashrcs
48 fi
49
50 -if ! hasq ${EBUILD_PHASE} clean && \
51 +if ! hasq "$EBUILD_PHASE" clean cleanrm && \
52 (
53 hasq ${EBUILD_PHASE} depend || \
54 [ ! -f "${T}"/environment ] || \
55 @@ -1903,7 +1903,7 @@
56 [[ -n ${EAPI/prefix/} ]] || EAPI="${EAPI}${EAPI:+ }0"
57
58 # enable bashrc support for the clean phase
59 -[[ ${EBUILD_PHASE} == clean ]] && source_all_bashrcs
60 +hasq "$EBUILD_PHASE" clean cleanrm && source_all_bashrcs
61
62 # unset USE_EXPAND variables that contain only the special "*" token
63 for x in ${USE_EXPAND} ; do
64
65 Modified: main/branches/prefix/man/emerge.1
66 ===================================================================
67 --- main/branches/prefix/man/emerge.1 2008-12-01 21:10:53 UTC (rev 12132)
68 +++ main/branches/prefix/man/emerge.1 2008-12-01 21:14:48 UTC (rev 12133)
69 @@ -405,7 +405,8 @@
70 F fetch restricted (must be manually downloaded)
71 f fetch restricted (already downloaded)
72 I interactive (requires user input)
73 -B blocked by an already installed package
74 +B blocked by another package (unresolved conflict)
75 +b blocked by another package (automatically resolved conflict)
76 .TE
77 .TP
78 .BR "\-\-quiet " (\fB\-q\fR)
79
80 Modified: main/branches/prefix/pym/_emerge/__init__.py
81 ===================================================================
82 --- main/branches/prefix/pym/_emerge/__init__.py 2008-12-01 21:10:53 UTC (rev 12132)
83 +++ main/branches/prefix/pym/_emerge/__init__.py 2008-12-01 21:14:48 UTC (rev 12133)
84 @@ -4346,10 +4346,12 @@
85 self._irrelevant_blockers = digraph()
86 # Contains only unsolvable Package -> Blocker edges
87 self._unsolvable_blockers = digraph()
88 - self._slot_collision_info = set()
89 + self._slot_collision_info = {}
90 # Slot collision nodes are not allowed to block other packages since
91 # blocker validation is only able to account for one package per slot.
92 self._slot_collision_nodes = set()
93 + self._parent_atoms = {}
94 + self._slot_conflict_parent_atoms = set()
95 self._serialized_tasks_cache = None
96 self._scheduler_graph = None
97 self._displayed_list = None
98 @@ -4373,8 +4375,26 @@
99 the packages. In some cases it may be possible to resolve this
100 automatically, but support for backtracking (removal nodes that have
101 already been selected) will be required in order to handle all possible
102 - cases."""
103 + cases.
104
105 + When a slot conflict occurs due to USE deps, there are a few
106 + different cases to consider:
107 +
108 + 1) New USE are correctly set but --newuse wasn't requested so an
109 + installed package with incorrect USE happened to get pulled
110 + into graph before the new one.
111 +
112 + 2) New USE are incorrectly set but an installed package has correct
113 + USE so it got pulled into the graph, and a new instance also got
114 + pulled in due to --newuse or an upgrade.
115 +
116 + 3) Multiple USE deps exist that can't be satisfied simultaneously,
117 + and multiple package instances got pulled into the same slot to
118 + satisfy the conflicting deps.
119 +
120 + TODO: Distinguish the above cases and tailor messages to suit them.
121 + """
122 +
123 if not self._slot_collision_info:
124 return
125
126 @@ -4388,46 +4408,64 @@
127 indent = " "
128 # Max number of parents shown, to avoid flooding the display.
129 max_parents = 3
130 - for slot_atom, root in self._slot_collision_info:
131 + for (slot_atom, root), slot_nodes \
132 + in self._slot_collision_info.iteritems():
133 msg.append(str(slot_atom))
134 msg.append("\n\n")
135 - slot_nodes = []
136 - for node in self._slot_collision_nodes:
137 - if node.slot_atom == slot_atom:
138 - slot_nodes.append(node)
139 - slot_nodes.append(self._slot_pkg_map[root][slot_atom])
140 +
141 for node in slot_nodes:
142 msg.append(indent)
143 msg.append(str(node))
144 - parents = self.digraph.parent_nodes(node)
145 - if parents:
146 - omitted_parents = 0
147 - if len(parents) > max_parents:
148 - pruned_list = []
149 + parent_atoms = self._parent_atoms.get(node)
150 + if parent_atoms:
151 + pruned_list = set()
152 + # Prefer conflict atoms over others.
153 + for parent_atom in parent_atoms:
154 + if len(pruned_list) >= max_parents:
155 + break
156 + if parent_atom in self._slot_conflict_parent_atoms:
157 + pruned_list.add(parent_atom)
158 +
159 + # If this package was pulled in by conflict atoms then
160 + # show those alone since those are the most interesting.
161 + if not pruned_list:
162 # When generating the pruned list, prefer instances
163 # of DependencyArg over instances of Package.
164 - for parent in parents:
165 + for parent_atom in parent_atoms:
166 + if len(pruned_list) >= max_parents:
167 + break
168 + parent, atom = parent_atom
169 if isinstance(parent, DependencyArg):
170 - pruned_list.append(parent)
171 + pruned_list.add(parent_atom)
172 # Prefer Packages instances that themselves have been
173 # pulled into collision slots.
174 - for parent in parents:
175 + for parent_atom in parent_atoms:
176 + if len(pruned_list) >= max_parents:
177 + break
178 + parent, atom = parent_atom
179 if isinstance(parent, Package) and \
180 (parent.slot_atom, parent.root) \
181 in self._slot_collision_info:
182 - pruned_list.append(parent)
183 - for parent in parents:
184 + pruned_list.add(parent_atom)
185 + for parent_atom in parent_atoms:
186 if len(pruned_list) >= max_parents:
187 break
188 - if not isinstance(parent, DependencyArg) and \
189 - parent not in pruned_list:
190 - pruned_list.append(parent)
191 - omitted_parents = len(parents) - len(pruned_list)
192 - parents = pruned_list
193 + pruned_list.add(parent_atom)
194 + omitted_parents = len(parent_atoms) - len(pruned_list)
195 + parent_atoms = pruned_list
196 msg.append(" pulled in by\n")
197 - for parent in parents:
198 + for parent_atom in parent_atoms:
199 + parent, atom = parent_atom
200 msg.append(2*indent)
201 - msg.append(str(parent))
202 + if isinstance(parent,
203 + (PackageArg, AtomArg)):
204 + # For PackageArg and AtomArg types, it's
205 + # redundant to display the atom attribute.
206 + msg.append(str(parent))
207 + else:
208 + # Display the specific atom from SetArg or
209 + # Package types.
210 + msg.append("%s required by %s" % (atom, parent))
211 msg.append("\n")
212 if omitted_parents:
213 msg.append(2*indent)
214 @@ -4467,6 +4505,40 @@
215 f.end_paragraph(1)
216 f.writer.flush()
217
218 + def _process_slot_conflicts(self):
219 + """
220 + Process slot conflict data to identify specific atoms which
221 + lead to conflict. These atoms only match a subset of the
222 + packages that have been pulled into a given slot.
223 + """
224 + for (slot_atom, root), slot_nodes \
225 + in self._slot_collision_info.iteritems():
226 +
227 + all_parent_atoms = set()
228 + for pkg in slot_nodes:
229 + parent_atoms = self._parent_atoms.get(pkg)
230 + if not parent_atoms:
231 + continue
232 + all_parent_atoms.update(parent_atoms)
233 +
234 + for pkg in slot_nodes:
235 + parent_atoms = self._parent_atoms.get(pkg)
236 + if parent_atoms is None:
237 + parent_atoms = set()
238 + self._parent_atoms[pkg] = parent_atoms
239 + for parent_atom in all_parent_atoms:
240 + if parent_atom in parent_atoms:
241 + continue
242 + # Use package set for matching since it will match via
243 + # PROVIDE when necessary, while match_from_list does not.
244 + parent, atom = parent_atom
245 + atom_set = InternalPackageSet(
246 + initial_atoms=(atom,))
247 + if atom_set.findAtomForPackage(pkg):
248 + parent_atoms.add(parent_atom)
249 + else:
250 + self._slot_conflict_parent_atoms.add(parent_atom)
251 +
252 def _reinstall_for_flags(self, forced_flags,
253 orig_use, orig_iuse, cur_use, cur_iuse):
254 """Return a set of flags that trigger reinstallation, or None if there
255 @@ -4579,12 +4651,14 @@
256 #IUSE-aware emerge -> USE DEP aware depgraph
257 #"no downgrade" emerge
258 """
259 + # Ensure that the dependencies of the same package
260 + # are never processed more than once.
261 + previously_added = pkg in self.digraph
262
263 # select the correct /var database that we'll be checking against
264 vardbapi = self.trees[pkg.root]["vartree"].dbapi
265 pkgsettings = self.pkgsettings[pkg.root]
266
267 - args = None
268 arg_atoms = None
269 if True:
270 try:
271 @@ -4595,8 +4669,6 @@
272 pkg, pkg.metadata["PROVIDE"], str(e))
273 return 0
274 del e
275 - else:
276 - args = [arg for arg, atom in arg_atoms]
277
278 if not pkg.onlydeps:
279 if not pkg.installed and \
280 @@ -4626,10 +4698,12 @@
281 existing_node_matches = False
282 if existing_node_matches:
283 # The existing node can be reused.
284 - if args:
285 - for arg in args:
286 - self.digraph.add(existing_node, arg,
287 + if arg_atoms:
288 + for parent_atom in arg_atoms:
289 + parent, atom = parent_atom
290 + self.digraph.add(existing_node, parent,
291 priority=priority)
292 + self._add_parent_atom(existing_node, parent_atom)
293 # If a direct circular dependency is not an unsatisfied
294 # buildtime dependency then drop it here since otherwise
295 # it can skew the merge order calculation in an unwanted
296 @@ -4638,32 +4712,16 @@
297 (priority.buildtime and not priority.satisfied):
298 self.digraph.addnode(existing_node, myparent,
299 priority=priority)
300 + if dep.atom is not None and dep.parent is not None:
301 + self._add_parent_atom(existing_node,
302 + (dep.parent, dep.atom))
303 return 1
304 else:
305
306 - if pkg.cpv == existing_node.cpv and \
307 - dep.atom is not None and \
308 - dep.atom.use:
309 - # Multiple different instances of the same version
310 - # (typically one installed and another not yet
311 - # installed) have been pulled into the graph due
312 - # to a USE dependency. The "slot collision" display
313 - # is not helpful in a case like this, so display it
314 - # as an unsatisfied dependency.
315 - self._unsatisfied_deps_for_display.append(
316 - ((dep.root, dep.atom), {"myparent":dep.parent}))
317 - self._slot_collision_info.add((pkg.slot_atom, pkg.root))
318 - self._slot_collision_nodes.add(pkg)
319 - self.digraph.addnode(pkg, myparent, priority=priority)
320 - return 0
321 -
322 - if pkg in self._slot_collision_nodes:
323 - return 1
324 # A slot collision has occurred. Sometimes this coincides
325 # with unresolvable blockers, so the slot collision will be
326 # shown later if there are no unresolvable blockers.
327 - self._slot_collision_info.add((pkg.slot_atom, pkg.root))
328 - self._slot_collision_nodes.add(pkg)
329 + self._add_slot_conflict(pkg)
330 slot_collision = True
331
332 if slot_collision:
333 @@ -4682,8 +4740,6 @@
334 self._slot_pkg_map[pkg.root][pkg.slot_atom] = pkg
335 self.mydbapi[pkg.root].cpv_inject(pkg)
336
337 - self.digraph.addnode(pkg, myparent, priority=priority)
338 -
339 if not pkg.installed:
340 # Allow this package to satisfy old-style virtuals in case it
341 # doesn't already. Any pre-existing providers will be preferred
342 @@ -4701,18 +4757,22 @@
343 del e
344 return 0
345
346 - if args:
347 + if arg_atoms:
348 self._set_nodes.add(pkg)
349
350 # Do this even when addme is False (--onlydeps) so that the
351 # parent/child relationship is always known in case
352 # self._show_slot_collision_notice() needs to be called later.
353 - if pkg.onlydeps:
354 - self.digraph.add(pkg, myparent, priority=priority)
355 - if args:
356 - for arg in args:
357 - self.digraph.add(pkg, arg, priority=priority)
358 + self.digraph.add(pkg, myparent, priority=priority)
359 + if dep.atom is not None and dep.parent is not None:
360 + self._add_parent_atom(pkg, (dep.parent, dep.atom))
361
362 + if arg_atoms:
363 + for parent_atom in arg_atoms:
364 + parent, atom = parent_atom
365 + self.digraph.add(pkg, parent, priority=priority)
366 + self._add_parent_atom(pkg, parent_atom)
367 +
368 """ This section determines whether we go deeper into dependencies or not.
369 We want to go deeper on a few occasions:
370 Installing package A, we need to make sure package A's deps are met.
371 @@ -4728,12 +4788,30 @@
372
373 self.spinner.update()
374
375 - if args:
376 + if arg_atoms:
377 depth = 0
378 pkg.depth = depth
379 - dep_stack.append(pkg)
380 + if not previously_added:
381 + dep_stack.append(pkg)
382 return 1
383
384 + def _add_parent_atom(self, pkg, parent_atom):
385 + parent_atoms = self._parent_atoms.get(pkg)
386 + if parent_atoms is None:
387 + parent_atoms = set()
388 + self._parent_atoms[pkg] = parent_atoms
389 + parent_atoms.add(parent_atom)
390 +
391 + def _add_slot_conflict(self, pkg):
392 + self._slot_collision_nodes.add(pkg)
393 + slot_key = (pkg.slot_atom, pkg.root)
394 + slot_nodes = self._slot_collision_info.get(slot_key)
395 + if slot_nodes is None:
396 + slot_nodes = set()
397 + slot_nodes.add(self._slot_pkg_map[pkg.root][pkg.slot_atom])
398 + self._slot_collision_info[slot_key] = slot_nodes
399 + slot_nodes.add(pkg)
400 +
401 def _add_pkg_deps(self, pkg, allow_unsatisfied=False):
402
403 mytype = pkg.type_name
404 @@ -6288,6 +6366,9 @@
405 if not self.validate_blockers():
406 raise self._unknown_internal_error()
407
408 + if self._slot_collision_info:
409 + self._process_slot_conflicts()
410 +
411 def _serialize_tasks(self):
412 scheduler_graph = self.digraph.copy()
413 mygraph=self.digraph.copy()