1 |
Author: grobian |
2 |
Date: 2008-06-25 09:00:23 +0000 (Wed, 25 Jun 2008) |
3 |
New Revision: 10781 |
4 |
|
5 |
Modified: |
6 |
main/branches/prefix/pym/_emerge/__init__.py |
7 |
main/branches/prefix/pym/portage/__init__.py |
8 |
main/branches/prefix/pym/portage/dbapi/vartree.py |
9 |
main/branches/prefix/pym/portage/dep.py |
10 |
Log: |
11 |
Merged from trunk 10770:10780 |
12 |
|
13 |
| 10771 | Bug #229233 - Fix Atom -> str breakage in the | |
14 |
| zmedico | depgraph.display_problems() package.provided warning | |
15 |
| | message. | |
16 |
|
17 |
| 10772 | Use weakref.WeakValueDictionary to make cached Atom | |
18 |
| zmedico | instances eligible for garbage collection when no strong | |
19 |
| | references remain. | |
20 |
|
21 |
| 10773 | If dep calculation time exceeds 20 seconds then | |
22 |
| zmedico | automatically enable "complete" mode since any performance | |
23 |
| | difference is not as likely to be noticed by the user after | |
24 |
| | this much time has passed. | |
25 |
|
26 |
| 10774 | Fix spelling of depgraph._complete_threshold. | |
27 |
| zmedico | | |
28 |
|
29 |
| 10775 | Bug #229069 - Before deleting the depgraph, break references | |
30 |
| zmedico | pointing to the depgraph from Package instances in the merge | |
31 |
| | list. This helps reduce the heap size a lot. | |
32 |
|
33 |
| 10776 | For the Package.metadata attribute, only implement the dict | |
34 |
| zmedico | interface instead of actually inheriting from dict. This | |
35 |
| | slightly decreases the memory footprint by defining | |
36 |
| | __slots__ and storing items as object attributes. | |
37 |
|
38 |
| 10777 | Remove the BlockerDB._blocker_cache attribute and just | |
39 |
| zmedico | create new instances on demand instead of taking space on | |
40 |
| | the heap. | |
41 |
|
42 |
| 10778 | Make clear_caches() call portage.dircache.clear(). | |
43 |
| zmedico | | |
44 |
|
45 |
| 10779 | Use os.listdir() instead of portage.listdir() to avoid | |
46 |
| zmedico | needless caching of directories that only need to be listed | |
47 |
| | once. | |
48 |
|
49 |
| 10780 | Implement __contains__, pop() and clear() for | |
50 |
| zmedico | Package.metadata attributes. | |
51 |
|
52 |
|
53 |
Modified: main/branches/prefix/pym/_emerge/__init__.py |
54 |
=================================================================== |
55 |
--- main/branches/prefix/pym/_emerge/__init__.py 2008-06-25 08:42:02 UTC (rev 10780) |
56 |
+++ main/branches/prefix/pym/_emerge/__init__.py 2008-06-25 09:00:23 UTC (rev 10781) |
57 |
@@ -1312,7 +1312,7 @@ |
58 |
def __init__(self, **kwargs): |
59 |
Task.__init__(self, **kwargs) |
60 |
self.root = self.root_config.root |
61 |
- self.metadata = self._metadata_wrapper(self, self.metadata) |
62 |
+ self.metadata = _PackageMetadataWrapper(self, self.metadata) |
63 |
self.cp = portage.cpv_getkey(self.cpv) |
64 |
self.slot_atom = portage.dep.Atom("%s:%s" % (self.cp, self.slot)) |
65 |
self.category, self.pf = portage.catsplit(self.cpv) |
66 |
@@ -1359,60 +1359,6 @@ |
67 |
chain((re.escape(x) for x in all), iuse_implicit))) |
68 |
return object.__getattribute__(self, name) |
69 |
|
70 |
- class _metadata_wrapper(dict): |
71 |
- """ |
72 |
- Detect metadata updates and synchronize Package attributes. |
73 |
- """ |
74 |
- _wrapped_keys = frozenset( |
75 |
- ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"]) |
76 |
- |
77 |
- def __init__(self, pkg, metadata): |
78 |
- dict.__init__(self) |
79 |
- self._pkg = pkg |
80 |
- i = getattr(metadata, "iteritems", None) |
81 |
- if i is None: |
82 |
- i = metadata |
83 |
- else: |
84 |
- i = i() |
85 |
- for k, v in i: |
86 |
- self[k] = v |
87 |
- |
88 |
- def __setitem__(self, k, v): |
89 |
- dict.__setitem__(self, k, v) |
90 |
- if k in self._wrapped_keys: |
91 |
- getattr(self, "_set_" + k.lower())(k, v) |
92 |
- |
93 |
- def _set_inherited(self, k, v): |
94 |
- if isinstance(v, basestring): |
95 |
- v = frozenset(v.split()) |
96 |
- self._pkg.inherited = v |
97 |
- |
98 |
- def _set_iuse(self, k, v): |
99 |
- self._pkg.iuse = self._pkg._iuse( |
100 |
- v.split(), self._pkg.root_config.iuse_implicit) |
101 |
- |
102 |
- def _set_slot(self, k, v): |
103 |
- self._pkg.slot = v |
104 |
- |
105 |
- def _set_use(self, k, v): |
106 |
- self._pkg.use = self._pkg._use(v.split()) |
107 |
- |
108 |
- def _set_counter(self, k, v): |
109 |
- if isinstance(v, basestring): |
110 |
- try: |
111 |
- v = int(v.strip()) |
112 |
- except ValueError: |
113 |
- v = 0 |
114 |
- self._pkg.counter = v |
115 |
- |
116 |
- def _set__mtime_(self, k, v): |
117 |
- if isinstance(v, basestring): |
118 |
- try: |
119 |
- v = float(v.strip()) |
120 |
- except ValueError: |
121 |
- v = 0 |
122 |
- self._pkg.mtime = v |
123 |
- |
124 |
def _get_hash_key(self): |
125 |
hash_key = getattr(self, "_hash_key", None) |
126 |
if hash_key is None: |
127 |
@@ -1452,6 +1398,135 @@ |
128 |
return True |
129 |
return False |
130 |
|
131 |
+class _PackageMetadataWrapper(object): |
132 |
+ """ |
133 |
+ Detect metadata updates and synchronize Package attributes. |
134 |
+ """ |
135 |
+ _keys = Package.metadata_keys |
136 |
+ __slots__ = ("__weakref__", "_pkg") + tuple("_val_" + k for k in _keys) |
137 |
+ _wrapped_keys = frozenset( |
138 |
+ ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"]) |
139 |
+ |
140 |
+ def __init__(self, pkg, metadata): |
141 |
+ self._pkg = pkg |
142 |
+ self.update(metadata) |
143 |
+ |
144 |
+ def __iter__(self): |
145 |
+ for k, v in self.iteritems(): |
146 |
+ yield k |
147 |
+ |
148 |
+ def __len__(self): |
149 |
+ l = 0 |
150 |
+ for i in self.iteritems(): |
151 |
+ l += 1 |
152 |
+ return l |
153 |
+ |
154 |
+ def keys(self): |
155 |
+ return list(self) |
156 |
+ |
157 |
+ def iteritems(self): |
158 |
+ for k in self._keys: |
159 |
+ try: |
160 |
+ yield (k, getattr(self, "_val_" + k)) |
161 |
+ except AttributeError: |
162 |
+ pass |
163 |
+ |
164 |
+ def items(self): |
165 |
+ return list(self.iteritems()) |
166 |
+ |
167 |
+ def itervalues(self): |
168 |
+ for k, v in self.itervalues(): |
169 |
+ yield v |
170 |
+ |
171 |
+ def values(self): |
172 |
+ return list(self.itervalues()) |
173 |
+ |
174 |
+ def __delitem__(self, k): |
175 |
+ try: |
176 |
+ delattr(self, "_val_" + k) |
177 |
+ except AttributeError: |
178 |
+ raise KeyError(k) |
179 |
+ |
180 |
+ def __setitem__(self, k, v): |
181 |
+ setattr(self, "_val_" + k, v) |
182 |
+ if k in self._wrapped_keys: |
183 |
+ getattr(self, "_set_" + k.lower())(k, v) |
184 |
+ |
185 |
+ def update(self, d): |
186 |
+ i = getattr(d, "iteritems", None) |
187 |
+ if i is None: |
188 |
+ i = d |
189 |
+ else: |
190 |
+ i = i() |
191 |
+ for k, v in i: |
192 |
+ self[k] = v |
193 |
+ |
194 |
+ def __getitem__(self, k): |
195 |
+ try: |
196 |
+ return getattr(self, "_val_" + k) |
197 |
+ except AttributeError: |
198 |
+ raise KeyError(k) |
199 |
+ |
200 |
+ def get(self, key, default=None): |
201 |
+ try: |
202 |
+ return self[key] |
203 |
+ except KeyError: |
204 |
+ return default |
205 |
+ |
206 |
+ def __contains__(self, k): |
207 |
+ return hasattr(self, "_val_" + k) |
208 |
+ |
209 |
+ def pop(self, key, *args): |
210 |
+ if len(args) > 1: |
211 |
+ raise TypeError("pop expected at most 2 arguments, got " + \ |
212 |
+ repr(1 + len(args))) |
213 |
+ try: |
214 |
+ value = self[key] |
215 |
+ except KeyError: |
216 |
+ if args: |
217 |
+ return args[0] |
218 |
+ raise |
219 |
+ del self[key] |
220 |
+ return value |
221 |
+ |
222 |
+ def clear(self): |
223 |
+ for k in self._keys: |
224 |
+ try: |
225 |
+ delattr(self, "_val_" + k) |
226 |
+ except AttributError: |
227 |
+ pass |
228 |
+ |
229 |
+ def _set_inherited(self, k, v): |
230 |
+ if isinstance(v, basestring): |
231 |
+ v = frozenset(v.split()) |
232 |
+ self._pkg.inherited = v |
233 |
+ |
234 |
+ def _set_iuse(self, k, v): |
235 |
+ self._pkg.iuse = self._pkg._iuse( |
236 |
+ v.split(), self._pkg.root_config.iuse_implicit) |
237 |
+ |
238 |
+ def _set_slot(self, k, v): |
239 |
+ self._pkg.slot = v |
240 |
+ |
241 |
+ def _set_use(self, k, v): |
242 |
+ self._pkg.use = self._pkg._use(v.split()) |
243 |
+ |
244 |
+ def _set_counter(self, k, v): |
245 |
+ if isinstance(v, basestring): |
246 |
+ try: |
247 |
+ v = int(v.strip()) |
248 |
+ except ValueError: |
249 |
+ v = 0 |
250 |
+ self._pkg.counter = v |
251 |
+ |
252 |
+ def _set__mtime_(self, k, v): |
253 |
+ if isinstance(v, basestring): |
254 |
+ try: |
255 |
+ v = float(v.strip()) |
256 |
+ except ValueError: |
257 |
+ v = 0 |
258 |
+ self._pkg.mtime = v |
259 |
+ |
260 |
class DependencyArg(object): |
261 |
def __init__(self, arg=None, root_config=None): |
262 |
self.arg = arg |
263 |
@@ -1657,15 +1732,14 @@ |
264 |
self._root_config = root_config |
265 |
self._vartree = root_config.trees["vartree"] |
266 |
self._portdb = root_config.trees["porttree"].dbapi |
267 |
- self._blocker_cache = \ |
268 |
- BlockerCache(self._vartree.root, self._vartree.dbapi) |
269 |
+ |
270 |
self._dep_check_trees = { self._vartree.root : { |
271 |
"porttree" : self._vartree, |
272 |
"vartree" : self._vartree, |
273 |
}} |
274 |
|
275 |
def findInstalledBlockers(self, new_pkg, acquire_lock=0): |
276 |
- blocker_cache = self._blocker_cache |
277 |
+ blocker_cache = BlockerCache(self._vartree.root, self._vartree.dbapi) |
278 |
dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"] |
279 |
dep_check_trees = self._dep_check_trees |
280 |
settings = self._vartree.settings |
281 |
@@ -1714,7 +1788,7 @@ |
282 |
blocker_parents = digraph() |
283 |
blocker_atoms = [] |
284 |
for pkg in installed_pkgs: |
285 |
- for blocker_atom in self._blocker_cache[pkg.cpv].atoms: |
286 |
+ for blocker_atom in blocker_cache[pkg.cpv].atoms: |
287 |
blocker_atom = blocker_atom[1:] |
288 |
blocker_atoms.append(blocker_atom) |
289 |
blocker_parents.add(blocker_atom, pkg) |
290 |
@@ -1801,6 +1875,15 @@ |
291 |
self._cp_map = {} |
292 |
self._cpv_map = {} |
293 |
|
294 |
+ def clear(self): |
295 |
+ """ |
296 |
+ Remove all packages. |
297 |
+ """ |
298 |
+ if self._cpv_map: |
299 |
+ self._clear_cache() |
300 |
+ self._cp_map.clear() |
301 |
+ self._cpv_map.clear() |
302 |
+ |
303 |
def copy(self): |
304 |
obj = PackageVirtualDbapi(self.settings) |
305 |
obj._match_cache = self._match_cache.copy() |
306 |
@@ -1908,7 +1991,14 @@ |
307 |
|
308 |
_dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"] |
309 |
|
310 |
+ # If dep calculation time exceeds this value then automatically |
311 |
+ # enable "complete" mode since any performance difference is |
312 |
+ # not as likely to be noticed by the user after this much time |
313 |
+ # has passed. |
314 |
+ _complete_threshold = 20 |
315 |
+ |
316 |
def __init__(self, settings, trees, myopts, myparams, spinner): |
317 |
+ self._creation_time = time.time() |
318 |
self.settings = settings |
319 |
self.target_root = settings["ROOT"] |
320 |
self.myopts = myopts |
321 |
@@ -3409,16 +3499,20 @@ |
322 |
intially satisfied. |
323 |
|
324 |
Since this method can consume enough time to disturb users, it is |
325 |
- currently only enabled by the --complete-graph option. |
326 |
+ currently only enabled by the --complete-graph option, or when |
327 |
+ dep calculation time exceeds self._complete_threshold. |
328 |
""" |
329 |
- if "complete" not in self.myparams: |
330 |
- # Skip this to avoid consuming enough time to disturb users. |
331 |
- return 1 |
332 |
- |
333 |
if "--buildpkgonly" in self.myopts or \ |
334 |
"recurse" not in self.myparams: |
335 |
return 1 |
336 |
|
337 |
+ if "complete" not in self.myparams: |
338 |
+ if time.time() - self._creation_time > self._complete_threshold: |
339 |
+ self.myparams.add("complete") |
340 |
+ else: |
341 |
+ # Skip this to avoid consuming enough time to disturb users. |
342 |
+ return 1 |
343 |
+ |
344 |
# Put the depgraph into a mode that causes it to only |
345 |
# select packages that have already been added to the |
346 |
# graph or those that are installed and have not been |
347 |
@@ -3860,6 +3954,29 @@ |
348 |
retlist.reverse() |
349 |
return retlist |
350 |
|
351 |
+ def break_refs(self, mergelist): |
352 |
+ """ |
353 |
+ Take a mergelist like that returned from self.altlist() and |
354 |
+ break any references that lead back to the depgraph. This is |
355 |
+ useful if you want to hold references to packages without |
356 |
+ also holding the depgraph on the heap. |
357 |
+ """ |
358 |
+ for node in mergelist: |
359 |
+ if not isinstance(node, Package): |
360 |
+ continue |
361 |
+ |
362 |
+ # The visible packages cache has fullfilled it's purpose |
363 |
+ # and it's no longer needed, so free the memory. |
364 |
+ node.root_config.visible_pkgs.clear() |
365 |
+ |
366 |
+ if isinstance(node.root_config.trees["vartree"], FakeVartree): |
367 |
+ # The FakeVartree references the _package_cache which |
368 |
+ # references the depgraph. So that Package instances don't |
369 |
+ # hold the depgraph and FakeVartree on the heap, replace |
370 |
+ # the FakeVartree reference with the real vartree. |
371 |
+ node.root_config.trees["vartree"] = \ |
372 |
+ self._trees_orig[node.root]["vartree"] |
373 |
+ |
374 |
def _resolve_conflicts(self): |
375 |
if not self._complete_graph(): |
376 |
raise self._unknown_internal_error() |
377 |
@@ -5249,7 +5366,7 @@ |
378 |
refs.sort() |
379 |
ref_string = ", ".join(["'%s'" % name for name in refs]) |
380 |
ref_string = " pulled in by " + ref_string |
381 |
- msg.append(" %s%s\n" % (colorize("INFORM", arg), ref_string)) |
382 |
+ msg.append(" %s%s\n" % (colorize("INFORM", str(arg)), ref_string)) |
383 |
msg.append("\n") |
384 |
if "world" in problems_sets: |
385 |
msg.append("This problem can be solved in one of the following ways:\n\n") |
386 |
@@ -8829,6 +8946,7 @@ |
387 |
mtimedb.filename = None |
388 |
time.sleep(3) # allow the parent to have first fetch |
389 |
mymergelist = mydepgraph.altlist() |
390 |
+ mydepgraph.break_refs(mymergelist) |
391 |
del mydepgraph |
392 |
clear_caches(trees) |
393 |
|
394 |
@@ -8872,6 +8990,7 @@ |
395 |
|
396 |
pkglist = mydepgraph.altlist() |
397 |
mydepgraph.saveNomergeFavorites() |
398 |
+ mydepgraph.break_refs(pkglist) |
399 |
del mydepgraph |
400 |
clear_caches(trees) |
401 |
|
402 |
@@ -9004,6 +9123,7 @@ |
403 |
d["porttree"].dbapi._aux_cache.clear() |
404 |
d["bintree"].dbapi._aux_cache.clear() |
405 |
d["bintree"].dbapi._clear_cache() |
406 |
+ portage.dircache.clear() |
407 |
gc.collect() |
408 |
|
409 |
def load_emerge_config(trees=None): |
410 |
|
411 |
Modified: main/branches/prefix/pym/portage/__init__.py |
412 |
=================================================================== |
413 |
--- main/branches/prefix/pym/portage/__init__.py 2008-06-25 08:42:02 UTC (rev 10780) |
414 |
+++ main/branches/prefix/pym/portage/__init__.py 2008-06-25 09:00:23 UTC (rev 10781) |
415 |
@@ -1956,7 +1956,7 @@ |
416 |
pkginternaluse = "" |
417 |
iuse = "" |
418 |
if mydb: |
419 |
- if isinstance(mydb, dict): |
420 |
+ if not hasattr(mydb, "aux_get"): |
421 |
slot = mydb["SLOT"] |
422 |
iuse = mydb["IUSE"] |
423 |
else: |
424 |
@@ -2434,7 +2434,7 @@ |
425 |
if len(self.virtuals) == 0: |
426 |
self.getvirtuals() |
427 |
# Grab the virtuals this package provides and add them into the tree virtuals. |
428 |
- if isinstance(mydbapi, dict): |
429 |
+ if not hasattr(mydbapi, "aux_get"): |
430 |
provides = mydbapi["PROVIDE"] |
431 |
else: |
432 |
provides = mydbapi.aux_get(mycpv, ["PROVIDE"])[0] |
433 |
@@ -2443,7 +2443,7 @@ |
434 |
if isinstance(mydbapi, portdbapi): |
435 |
self.setcpv(mycpv, mydb=mydbapi) |
436 |
myuse = self["PORTAGE_USE"] |
437 |
- elif isinstance(mydbapi, dict): |
438 |
+ elif not hasattr(mydbapi, "aux_get"): |
439 |
myuse = mydbapi["USE"] |
440 |
else: |
441 |
myuse = mydbapi.aux_get(mycpv, ["USE"])[0] |
442 |
|
443 |
Modified: main/branches/prefix/pym/portage/dbapi/vartree.py |
444 |
=================================================================== |
445 |
--- main/branches/prefix/pym/portage/dbapi/vartree.py 2008-06-25 08:42:02 UTC (rev 10780) |
446 |
+++ main/branches/prefix/pym/portage/dbapi/vartree.py 2008-06-25 09:00:23 UTC (rev 10781) |
447 |
@@ -1630,7 +1630,7 @@ |
448 |
# name of the dir; the package may have been moved. |
449 |
myebuildpath = None |
450 |
ebuild_phase = "prerm" |
451 |
- mystuff = listdir(self.dbdir, EmptyOnError=1) |
452 |
+ mystuff = os.listdir(self.dbdir) |
453 |
for x in mystuff: |
454 |
if x.endswith(".ebuild"): |
455 |
myebuildpath = os.path.join(self.dbdir, self.pkg + ".ebuild") |
456 |
@@ -2665,7 +2665,7 @@ |
457 |
return a |
458 |
|
459 |
# copy "info" files (like SLOT, CFLAGS, etc.) into the database |
460 |
- for x in listdir(inforoot): |
461 |
+ for x in os.listdir(inforoot): |
462 |
self.copyfile(inforoot+"/"+x) |
463 |
|
464 |
# write local package counter for recording |
465 |
|
466 |
Modified: main/branches/prefix/pym/portage/dep.py |
467 |
=================================================================== |
468 |
--- main/branches/prefix/pym/portage/dep.py 2008-06-25 08:42:02 UTC (rev 10780) |
469 |
+++ main/branches/prefix/pym/portage/dep.py 2008-06-25 09:00:23 UTC (rev 10781) |
470 |
@@ -19,6 +19,7 @@ |
471 |
# |
472 |
|
473 |
import re, sys, types |
474 |
+import weakref |
475 |
from itertools import chain |
476 |
import portage.exception |
477 |
from portage.exception import InvalidData, InvalidAtom |
478 |
@@ -412,7 +413,7 @@ |
479 |
""" |
480 |
|
481 |
__metaclass__ = _AtomCache |
482 |
- _atoms = {} |
483 |
+ _atoms = weakref.WeakValueDictionary() |
484 |
|
485 |
_str_methods = ("endswith", "find", "index", "lstrip", "replace", |
486 |
"startswith", "strip", "rindex", "rfind", "rstrip", "__getitem__", |
487 |
|
488 |
-- |
489 |
gentoo-commits@l.g.o mailing list |