Gentoo Archives: gentoo-commits

From: "Zac Medico (zmedico)" <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r9966 - in main/branches/2.1.2: bin doc/dependency_resolution
Date: Fri, 25 Apr 2008 02:30:45
Message-Id: E1JpDhw-0006LZ-TJ@stork.gentoo.org
1 Author: zmedico
2 Date: 2008-04-25 02:30:39 +0000 (Fri, 25 Apr 2008)
3 New Revision: 9966
4
5 Modified:
6 main/branches/2.1.2/bin/emerge
7 main/branches/2.1.2/doc/dependency_resolution/task_scheduling.docbook
8 Log:
9 Bug #172812 - If any Uninstall tasks need to be executed in order
10 to avoid a conflict, complete the graph with any dependencies that
11 may have been initially neglected (to ensure that unsafe Uninstall
12 tasks are properly identified and blocked from execution).
13 (trunk r9962:9965)
14
15
16 Modified: main/branches/2.1.2/bin/emerge
17 ===================================================================
18 --- main/branches/2.1.2/bin/emerge 2008-04-25 01:53:44 UTC (rev 9965)
19 +++ main/branches/2.1.2/bin/emerge 2008-04-25 02:30:39 UTC (rev 9966)
20 @@ -365,9 +365,7 @@
21 # recurse: go into the dependencies
22 # deep: go into the dependencies of already merged packages
23 # empty: pretend nothing is merged
24 - # consistent: ensure that installation of new packages does not break
25 - # any deep dependencies of required sets (args, system, or
26 - # world).
27 + # complete: completely account for all known dependencies
28 myparams = set(["recurse"])
29 if "--update" in myopts or \
30 "--newuse" in myopts or \
31 @@ -383,7 +381,7 @@
32 if "--deep" in myopts:
33 myparams.add("deep")
34 if "--complete-graph" in myopts:
35 - myparams.add("consistent")
36 + myparams.add("complete")
37 return myparams
38
39 # search functionality
40 @@ -1852,7 +1850,7 @@
41 # Slot collision nodes are not allowed to block other packages since
42 # blocker validation is only able to account for one package per slot.
43 self._slot_collision_nodes = set()
44 - self._altlist_cache = {}
45 + self._serialized_tasks_cache = None
46 self._pprovided_args = []
47 self._missing_args = []
48 self._masked_installed = []
49 @@ -1999,7 +1997,6 @@
50 nodeps = "--nodeps" in self.myopts
51 empty = "empty" in self.myparams
52 deep = "deep" in self.myparams
53 - consistent = "consistent" in self.myparams
54 update = "--update" in self.myopts and dep.depth <= 1
55 if dep.blocker:
56 if not buildpkgonly and \
57 @@ -2043,8 +2040,7 @@
58 # should have been masked.
59 raise
60 if not myarg:
61 - if consistent:
62 - self._ignored_deps.append(dep)
63 + self._ignored_deps.append(dep)
64 return 1
65
66 if not self._add_pkg(dep_pkg, dep.parent,
67 @@ -2191,8 +2187,6 @@
68 return 1
69 elif pkg.installed and \
70 "deep" not in self.myparams:
71 - if "consistent" not in self.myparams:
72 - return 1
73 dep_stack = self._ignored_deps
74
75 self.spinner.update()
76 @@ -2716,7 +2710,7 @@
77
78 if not self.validate_blockers():
79 return False, myfavorites
80 -
81 +
82 # We're true here unless we are missing binaries.
83 return (not missing,myfavorites)
84
85 @@ -3089,7 +3083,7 @@
86 Since this method can consume enough time to disturb users, it is
87 currently only enabled by the --complete-graph option.
88 """
89 - if "consistent" not in self.myparams:
90 + if "complete" not in self.myparams:
91 # Skip this to avoid consuming enough time to disturb users.
92 return 1
93
94 @@ -3382,9 +3376,17 @@
95 blocker, set()).add(parent)
96 if not self.blocker_parents[blocker]:
97 del self.blocker_parents[blocker]
98 - # Validate blockers that depend on merge order.
99 - if not self.blocker_digraph.empty():
100 +
101 + # This checks whether or not it's possible to resolve blocker
102 + # conflicts that depend on installation order or require
103 + # uninstallation of a currently installed package. Note that
104 + # this can lead to the current method being called recursively
105 + # if changes to the dependency graph are required.
106 + try:
107 self.altlist()
108 + except self._unknown_internal_error:
109 + return False
110 +
111 if self._slot_collision_info:
112 # The user is only notified of a slot collision if there are no
113 # unresolvable blocks.
114 @@ -3416,13 +3418,19 @@
115 mygraph.order.sort(cmp_merge_preference)
116
117 def altlist(self, reversed=False):
118 - if reversed in self._altlist_cache:
119 - return self._altlist_cache[reversed][:]
120 +
121 + while self._serialized_tasks_cache is None:
122 + try:
123 + self._serialized_tasks_cache = self._serialize_tasks()
124 + except self._serialize_tasks_retry:
125 + pass
126 +
127 + retlist = self._serialized_tasks_cache[:]
128 if reversed:
129 - retlist = self.altlist()
130 retlist.reverse()
131 - self._altlist_cache[reversed] = retlist[:]
132 - return retlist
133 + return retlist
134 +
135 + def _serialize_tasks(self):
136 mygraph=self.digraph.copy()
137 # Prune "nomerge" root nodes if nothing depends on them, since
138 # otherwise they slow down merge order calculation. Don't remove
139 @@ -3460,7 +3468,11 @@
140 # correspond to blocker conflicts that could not be
141 # resolved.
142 ignored_uninstall_tasks = set()
143 - blocker_deps = None
144 + have_uninstall_task = False
145 + complete = "complete" in self.myparams
146 + myblocker_parents = self.blocker_parents.copy()
147 + for k, v in myblocker_parents.iteritems():
148 + myblocker_parents[k] = v.copy()
149 asap_nodes = []
150 portage_node = None
151 def get_nodes(**kwargs):
152 @@ -3650,43 +3662,54 @@
153 inst_pkg = self._pkg_cache[
154 ("installed", task.root, task.cpv, "nomerge")]
155
156 - # For packages in the system set, don't take
157 - # any chances. If the conflict can't be resolved
158 - # by a normal upgrade operation then require
159 - # user intervention.
160 - skip = False
161 - try:
162 - for atom in root_config.sets[
163 - "system"].iterAtomsForPackage(task):
164 - skip = True
165 - break
166 - except portage_exception.InvalidDependString:
167 - skip = True
168 - if skip:
169 + if self.digraph.contains(inst_pkg):
170 continue
171
172 - # For packages in the world set, go ahead an uninstall
173 - # when necessary, as long as the atom will be satisfied
174 - # in the final state.
175 - graph_db = self.mydbapi[task.root]
176 - try:
177 - for atom in root_config.sets[
178 - "world"].iterAtomsForPackage(task):
179 - satisfied = False
180 - for cpv in graph_db.match(atom):
181 - if cpv == inst_pkg.cpv and \
182 - inst_pkg in graph_db:
183 - continue
184 - satisfied = True
185 - break
186 - if not satisfied:
187 + if "/" == task.root:
188 + # For packages in the system set, don't take
189 + # any chances. If the conflict can't be resolved
190 + # by a normal replacement operation then abort.
191 + skip = False
192 + try:
193 + for atom in root_config.sets[
194 + "system"].iterAtomsForPackage(task):
195 skip = True
196 break
197 - except portage_exception.InvalidDependString:
198 - skip = True
199 - if skip:
200 - continue
201 + except portage_exception.InvalidDependString:
202 + skip = True
203 + if skip:
204 + continue
205
206 + # Note that the world check isn't always
207 + # necessary since self._complete_graph() will
208 + # add all packages from the system and world sets to the
209 + # graph. This just allows unresolved conflicts to be
210 + # detected as early as possible, which makes it possible
211 + # to avoid calling self._complete_graph() when it is
212 + # unnecessary due to blockers triggering an abortion.
213 + if not complete:
214 + # For packages in the world set, go ahead an uninstall
215 + # when necessary, as long as the atom will be satisfied
216 + # in the final state.
217 + graph_db = self.mydbapi[task.root]
218 + try:
219 + for atom in root_config.sets[
220 + "world"].iterAtomsForPackage(task):
221 + satisfied = False
222 + for cpv in graph_db.match(atom):
223 + if cpv == inst_pkg.cpv and \
224 + inst_pkg in graph_db:
225 + continue
226 + satisfied = True
227 + break
228 + if not satisfied:
229 + skip = True
230 + break
231 + except portage_exception.InvalidDependString:
232 + skip = True
233 + if skip:
234 + continue
235 +
236 # Check the deps of parent nodes to ensure that
237 # the chosen task produces a leaf node. Maybe
238 # this can be optimized some more to make the
239 @@ -3778,6 +3801,7 @@
240 # and uninstallation tasks.
241 uninst_task = None
242 if isinstance(node, Uninstall):
243 + have_uninstall_task = True
244 uninst_task = node
245 else:
246 vardb = self.trees[node.root]["vartree"].dbapi
247 @@ -3803,24 +3827,32 @@
248 unresolved = \
249 self._unresolved_blocker_parents.get(blocker)
250 if unresolved:
251 - self.blocker_parents[blocker] = unresolved
252 + myblocker_parents[blocker] = unresolved
253 else:
254 - del self.blocker_parents[blocker]
255 + del myblocker_parents[blocker]
256
257 if node[-1] != "nomerge":
258 retlist.append(list(node))
259 mygraph.remove(node)
260
261 - if not reversed:
262 - """Blocker validation does not work with reverse mode,
263 - so self.altlist() should first be called with reverse disabled
264 - so that blockers are properly validated."""
265 - self.blocker_digraph = myblockers
266 + for blocker in myblocker_parents:
267 + retlist.append(list(blocker))
268
269 - """ Add any unresolved blocks so that they can be displayed."""
270 - for blocker in self.blocker_parents:
271 - retlist.append(list(blocker))
272 - self._altlist_cache[reversed] = retlist[:]
273 + # If any Uninstall tasks need to be executed in order
274 + # to avoid a conflict, complete the graph with any
275 + # dependencies that may have been initially
276 + # neglected (to ensure that unsafe Uninstall tasks
277 + # are properly identified and blocked from execution).
278 + if have_uninstall_task and \
279 + not complete and \
280 + not myblocker_parents:
281 + self.myparams.add("complete")
282 + if not self._complete_graph():
283 + raise self._unknown_internal_error("")
284 + if not self.validate_blockers():
285 + raise self._unknown_internal_error("")
286 + raise self._serialize_tasks_retry("")
287 +
288 return retlist
289
290 def display(self, mylist, favorites=[], verbosity=None):
291 @@ -4718,6 +4750,22 @@
292 fakedb[myroot].cpv_inject(pkg)
293 self.spinner.update()
294
295 + class _unknown_internal_error(portage_exception.PortageException):
296 + """
297 + Used by the depgraph internally to terminate graph creation.
298 + The specific reason for the failure should have been dumped
299 + to stderr, unfortunately, the exact reason for the failure
300 + may not be known.
301 + """
302 +
303 + class _serialize_tasks_retry(portage_exception.PortageException):
304 + """
305 + This is raised by the _serialize_tasks() method when it needs to
306 + be called again for some reason. The only case that it's currently
307 + used for is when neglected dependencies need to be added to the
308 + graph in order to avoid making a potentially unsafe decision.
309 + """
310 +
311 class _dep_check_composite_db(portage.dbapi):
312 """
313 A dbapi-like interface that is optimized for use in dep_check() calls.
314
315 Modified: main/branches/2.1.2/doc/dependency_resolution/task_scheduling.docbook
316 ===================================================================
317 --- main/branches/2.1.2/doc/dependency_resolution/task_scheduling.docbook 2008-04-25 01:53:44 UTC (rev 9965)
318 +++ main/branches/2.1.2/doc/dependency_resolution/task_scheduling.docbook 2008-04-25 02:30:39 UTC (rev 9966)
319 @@ -29,13 +29,14 @@
320 Installed packages that have been pulled into the current dependency
321 graph will not be uninstalled. Due to
322 <link linkend='dependency-resolution-package-modeling-dependency-neglection'>
323 - dependency neglection</link>, other checks may be necessary in order
324 + dependency neglection</link> and special properties of packages
325 + in the "system" set, other checks may be necessary in order
326 to protect inappropriate packages from being uninstalled.
327 </listitem>
328 <listitem>
329 An installed package that is matched by a dependency atom from the
330 "system" set will not be uninstalled in advance since it might not
331 - be safe. Such a package will be uninstalled through replacement.
332 + be safe. Such a package will be only uninstalled through replacement.
333 </listitem>
334 <listitem>
335 An installed package that is matched by a dependency atom from the
336
337 --
338 gentoo-commits@l.g.o mailing list