Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r10814 - in main/branches/prefix: cnf pym/_emerge pym/portage pym/portage/cache pym/portage/dbapi
Date: Fri, 27 Jun 2008 14:47:27
Message-Id: E1KCFEP-0000UW-2U@stork.gentoo.org
1 Author: grobian
2 Date: 2008-06-27 14:47:19 +0000 (Fri, 27 Jun 2008)
3 New Revision: 10814
4
5 Modified:
6 main/branches/prefix/cnf/sets.conf
7 main/branches/prefix/pym/_emerge/__init__.py
8 main/branches/prefix/pym/portage/__init__.py
9 main/branches/prefix/pym/portage/cache/mappings.py
10 main/branches/prefix/pym/portage/dbapi/bintree.py
11 main/branches/prefix/pym/portage/dbapi/porttree.py
12 main/branches/prefix/pym/portage/getbinpkg.py
13 main/branches/prefix/pym/portage/util.py
14 Log:
15 Merged from trunk 10788:10801
16
17 | 10789 | Swap out the whole Package.root_config attribute inside |
18 | zmedico | depgraph.break_refs(). |
19
20 | 10790 | Add a generic portage.cache.mappings.slot_dict_class() |
21 | zmedico | function which generates mapping classes that behave similar |
22 | | to a dict but store values as object attributes that are |
23 | | allocated via __slots__. Instances of these objects have a |
24 | | smaller memory footprint than a normal dict object. These |
25 | | classes are used to reduce the memory footprint of the |
26 | | dbapi.aux_get() caches and the Package.metadata attribute. |
27
28 | 10791 | Fix indentation. |
29 | zmedico | |
30
31 | 10792 | Fix KeyError constructor style. |
32 | zmedico | |
33
34 | 10793 | Fix typo. |
35 | zmedico | |
36
37 | 10794 | Add docstring to slot_dict_class(). |
38 | zmedico | |
39
40 | 10795 | Fix typo. |
41 | zmedico | |
42
43 | 10796 | Use SlotDict where appropriate in binarytree._populate(). |
44 | zmedico | |
45
46 | 10797 | Make PackageIndex use SlotDict for package metadata storage. |
47 | zmedico | The set of allowed keys is passed into the PackageIndex |
48 | | constructor (normal dict instances will be used if the set |
49 | | of keys is not passed in for some reason). A |
50 | | SlotDict.allowed_keys attribute now provides access to a |
51 | | frozenset of allowed keys. |
52
53 | 10798 | Implement lazy initialization of global "portdb", "settings" |
54 | zmedico | and other variables that pollute the portage module. This |
55 | | works by initializing the global variables with dummy |
56 | | "proxy" objects that serve as a means to trigger lazy |
57 | | initialization. As soon as the first attribute access or |
58 | | method call occurs on one of the proxy objects, it causes |
59 | | all the proxy objects to be replaced with the real ones. |
60 | | It's possible for an unsupported attribute access or method |
61 | | call on a proxy object to trigger an error, leading to |
62 | | breakage. However, hopefully these such corner cases will |
63 | | negligible (only time will tell). |
64
65 | 10799 | Use a separate proxy type to trigger portage.portdb |
66 | zmedico | initialization separately from the rest of the legacy global |
67 | | variables. This can be useful since sometimes the other |
68 | | variables are needed while the portdb is not. |
69
70 | 10800 | Also use a separate proxy type for portage.mtimedb since |
71 | zmedico | it's independent from the portdb and settings. |
72
73 | 10801 | change default name of EverythingSet to @all-installed (bug |
74 | genone | #229467) |
75
76
77 Modified: main/branches/prefix/cnf/sets.conf
78 ===================================================================
79 --- main/branches/prefix/cnf/sets.conf 2008-06-27 12:11:33 UTC (rev 10813)
80 +++ main/branches/prefix/cnf/sets.conf 2008-06-27 14:47:19 UTC (rev 10814)
81 @@ -25,7 +25,7 @@
82 world-candidate = False
83
84 # Again, not much to change here, though people might prefer a different name
85 -[everything]
86 +[all-installed]
87 class = portage.sets.dbapi.EverythingSet
88 world-candidate = False
89
90
91 Modified: main/branches/prefix/pym/_emerge/__init__.py
92 ===================================================================
93 --- main/branches/prefix/pym/_emerge/__init__.py 2008-06-27 12:11:33 UTC (rev 10813)
94 +++ main/branches/prefix/pym/_emerge/__init__.py 2008-06-27 14:47:19 UTC (rev 10814)
95 @@ -1398,108 +1398,33 @@
96 return True
97 return False
98
99 -class _PackageMetadataWrapper(object):
100 +_all_metadata_keys = set(x for x in portage.auxdbkeys \
101 + if not x.startswith("UNUSED_"))
102 +_all_metadata_keys.discard("CDEPEND")
103 +_all_metadata_keys.update(Package.metadata_keys)
104 +
105 +from portage.cache.mappings import slot_dict_class
106 +_PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
107 +
108 +class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
109 """
110 Detect metadata updates and synchronize Package attributes.
111 """
112 - _keys = set(x for x in portage.auxdbkeys \
113 - if not x.startswith("UNUSED_"))
114 - _keys.discard("CDEPEND")
115 - _keys.update(Package.metadata_keys)
116 - _keys = tuple(sorted(_keys))
117 - __slots__ = ("__weakref__", "_pkg") + tuple("_val_" + k for k in _keys)
118 +
119 + __slots__ = ("_pkg",)
120 _wrapped_keys = frozenset(
121 ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
122
123 def __init__(self, pkg, metadata):
124 + _PackageMetadataWrapperBase.__init__(self)
125 self._pkg = pkg
126 self.update(metadata)
127
128 - def __iter__(self):
129 - for k, v in self.iteritems():
130 - yield k
131 -
132 - def __len__(self):
133 - l = 0
134 - for i in self.iteritems():
135 - l += 1
136 - return l
137 -
138 - def keys(self):
139 - return list(self)
140 -
141 - def iteritems(self):
142 - for k in self._keys:
143 - try:
144 - yield (k, getattr(self, "_val_" + k))
145 - except AttributeError:
146 - pass
147 -
148 - def items(self):
149 - return list(self.iteritems())
150 -
151 - def itervalues(self):
152 - for k, v in self.itervalues():
153 - yield v
154 -
155 - def values(self):
156 - return list(self.itervalues())
157 -
158 - def __delitem__(self, k):
159 - try:
160 - delattr(self, "_val_" + k)
161 - except AttributeError:
162 - raise KeyError(k)
163 -
164 def __setitem__(self, k, v):
165 - setattr(self, "_val_" + k, v)
166 + _PackageMetadataWrapperBase.__setitem__(self, k, v)
167 if k in self._wrapped_keys:
168 getattr(self, "_set_" + k.lower())(k, v)
169
170 - def update(self, d):
171 - i = getattr(d, "iteritems", None)
172 - if i is None:
173 - i = d
174 - else:
175 - i = i()
176 - for k, v in i:
177 - self[k] = v
178 -
179 - def __getitem__(self, k):
180 - try:
181 - return getattr(self, "_val_" + k)
182 - except AttributeError:
183 - raise KeyError(k)
184 -
185 - def get(self, key, default=None):
186 - try:
187 - return self[key]
188 - except KeyError:
189 - return default
190 -
191 - def __contains__(self, k):
192 - return hasattr(self, "_val_" + k)
193 -
194 - def pop(self, key, *args):
195 - if len(args) > 1:
196 - raise TypeError("pop expected at most 2 arguments, got " + \
197 - repr(1 + len(args)))
198 - try:
199 - value = self[key]
200 - except KeyError:
201 - if args:
202 - return args[0]
203 - raise
204 - del self[key]
205 - return value
206 -
207 - def clear(self):
208 - for k in self._keys:
209 - try:
210 - delattr(self, "_val_" + k)
211 - except AttributError:
212 - pass
213 -
214 def _set_inherited(self, k, v):
215 if isinstance(v, basestring):
216 v = frozenset(v.split())
217 @@ -3977,18 +3902,15 @@
218 if not isinstance(node, Package):
219 continue
220
221 - # The visible packages cache has fullfilled it's purpose
222 - # and it's no longer needed, so free the memory.
223 - node.root_config.visible_pkgs.clear()
224 + # The FakeVartree references the _package_cache which
225 + # references the depgraph. So that Package instances don't
226 + # hold the depgraph and FakeVartree on the heap, replace
227 + # the RootConfig that references the FakeVartree with the
228 + # original RootConfig instance which references the actual
229 + # vartree.
230 + node.root_config = \
231 + self._trees_orig[node.root]["root_config"]
232
233 - if isinstance(node.root_config.trees["vartree"], FakeVartree):
234 - # The FakeVartree references the _package_cache which
235 - # references the depgraph. So that Package instances don't
236 - # hold the depgraph and FakeVartree on the heap, replace
237 - # the FakeVartree reference with the real vartree.
238 - node.root_config.trees["vartree"] = \
239 - self._trees_orig[node.root]["vartree"]
240 -
241 def _resolve_conflicts(self):
242 if not self._complete_graph():
243 raise self._unknown_internal_error()
244
245 Modified: main/branches/prefix/pym/portage/__init__.py
246 ===================================================================
247 --- main/branches/prefix/pym/portage/__init__.py 2008-06-27 12:11:33 UTC (rev 10813)
248 +++ main/branches/prefix/pym/portage/__init__.py 2008-06-27 14:47:19 UTC (rev 10814)
249 @@ -6993,6 +6993,54 @@
250 binarytree, myroot, mysettings["PKGDIR"], settings=mysettings)
251 return trees
252
253 +class _LegacyGlobalProxy(portage.util.ObjectProxy):
254 + """
255 + Instances of these serve as proxies to global variables
256 + that are initialized on demand.
257 + """
258 + def __init__(self, name):
259 + portage.util.ObjectProxy.__init__(self)
260 + object.__setattr__(self, '_name', name)
261 +
262 + def _get_target(self):
263 + init_legacy_globals()
264 + name = object.__getattribute__(self, '_name')
265 + return globals()[name]
266 +
267 +class _PortdbProxy(portage.util.ObjectProxy):
268 + """
269 + The portdb is initialized separately from the rest
270 + of the variables, since sometimes the other variables
271 + are needed while the portdb is not.
272 + """
273 +
274 + def _get_target(self):
275 + init_legacy_globals()
276 + global db, portdb, root, _portdb_initialized
277 + if not _portdb_initialized:
278 + portdb = db[root]["porttree"].dbapi
279 + _portdb_initialized = True
280 + return portdb
281 +
282 +class _MtimedbProxy(portage.util.ObjectProxy):
283 + """
284 + The mtimedb is independent from the portdb and other globals.
285 + """
286 +
287 + def __init__(self, name):
288 + portage.util.ObjectProxy.__init__(self)
289 + object.__setattr__(self, '_name', name)
290 +
291 + def _get_target(self):
292 + global mtimedb, mtimedbfile, _mtimedb_initialized
293 + if not _mtimedb_initialized:
294 + mtimedbfile = os.path.join("/",
295 + CACHE_PATH.lstrip(os.path.sep), "mtimedb")
296 + mtimedb = MtimeDB(mtimedbfile)
297 + _mtimedb_initialized = True
298 + name = object.__getattribute__(self, '_name')
299 + return globals()[name]
300 +
301 # Initialization of legacy globals. No functions/classes below this point
302 # please! When the above functions and classes become independent of the
303 # below global variables, it will be possible to make the below code
304 @@ -7002,6 +7050,11 @@
305 # overhead (and other issues!) of initializing the legacy globals.
306
307 def init_legacy_globals():
308 + global _globals_initialized
309 + if _globals_initialized:
310 + return
311 + _globals_initialized = True
312 +
313 global db, settings, root, portdb, selinux_enabled, mtimedbfile, mtimedb, \
314 archlist, features, groups, pkglines, thirdpartymirrors, usedefaults, \
315 profiledir, flushmtimedb
316 @@ -7019,18 +7072,14 @@
317 del _initializing_globals
318
319 settings = db["/"]["vartree"].settings
320 - portdb = db["/"]["porttree"].dbapi
321
322 for myroot in db:
323 if myroot != "/":
324 settings = db[myroot]["vartree"].settings
325 - portdb = db[myroot]["porttree"].dbapi
326 break
327
328 root = settings["ROOT"]
329
330 - mtimedbfile = os.path.join("/", CACHE_PATH.lstrip(os.path.sep), "mtimedb")
331 - mtimedb = MtimeDB(mtimedbfile)
332
333 # ========================================================================
334 # COMPATIBILITY
335 @@ -7060,8 +7109,22 @@
336 # use within Portage. External use of this variable is unsupported because
337 # it is experimental and it's behavior is likely to change.
338 if "PORTAGE_LEGACY_GLOBALS" not in os.environ:
339 - init_legacy_globals()
340
341 + _mtimedb_initialized = False
342 + mtimedb = _MtimedbProxy("mtimedb")
343 + mtimedbfile = _MtimedbProxy("mtimedbfile")
344 +
345 + _portdb_initialized = False
346 + portdb = _PortdbProxy()
347 +
348 + _globals_initialized = False
349 +
350 + for k in ("db", "settings", "root", "selinux_enabled",
351 + "archlist", "features", "groups",
352 + "pkglines", "thirdpartymirrors", "usedefaults", "profiledir",
353 + "flushmtimedb"):
354 + globals()[k] = _LegacyGlobalProxy(k)
355 +
356 # Clear the cache
357 dircache={}
358
359
360 Modified: main/branches/prefix/pym/portage/cache/mappings.py
361 ===================================================================
362 --- main/branches/prefix/pym/portage/cache/mappings.py 2008-06-27 12:11:33 UTC (rev 10813)
363 +++ main/branches/prefix/pym/portage/cache/mappings.py 2008-06-27 14:47:19 UTC (rev 10814)
364 @@ -4,6 +4,7 @@
365 # $Id$
366
367 import UserDict
368 +import weakref
369
370 class ProtectedDict(UserDict.DictMixin):
371 """
372 @@ -101,3 +102,140 @@
373 self.pull = None
374 return key in self.d
375
376 +_slot_dict_classes = weakref.WeakValueDictionary()
377 +
378 +def slot_dict_class(keys):
379 + """
380 + Generates mapping classes that behave similar to a dict but store values
381 + as object attributes that are allocated via __slots__. Instances of these
382 + objects have a smaller memory footprint than a normal dict object.
383 +
384 + @param keys: Fixed set of allowed keys
385 + @type keys: iterable
386 + @rtype: SlotDict
387 + @returns: A class that constructs SlotDict instances
388 + having the specified keys.
389 + """
390 + if isinstance(keys, frozenset):
391 + keys_set = keys
392 + else:
393 + keys_set = frozenset(keys)
394 + v = _slot_dict_classes.get(keys_set)
395 + if v is None:
396 +
397 + class SlotDict(object):
398 +
399 + allowed_keys = keys_set
400 + __slots__ = ("__weakref__",) + \
401 + tuple("_val_" + k for k in allowed_keys)
402 +
403 + def __iter__(self):
404 + for k, v in self.iteritems():
405 + yield k
406 +
407 + def __len__(self):
408 + l = 0
409 + for i in self.iteritems():
410 + l += 1
411 + return l
412 +
413 + def keys(self):
414 + return list(self)
415 +
416 + def iteritems(self):
417 + for k in self.allowed_keys:
418 + try:
419 + yield (k, getattr(self, "_val_" + k))
420 + except AttributeError:
421 + pass
422 +
423 + def items(self):
424 + return list(self.iteritems())
425 +
426 + def itervalues(self):
427 + for k, v in self.iteritems():
428 + yield v
429 +
430 + def values(self):
431 + return list(self.itervalues())
432 +
433 + def __delitem__(self, k):
434 + try:
435 + delattr(self, "_val_" + k)
436 + except AttributeError:
437 + raise KeyError(k)
438 +
439 + def __setitem__(self, k, v):
440 + setattr(self, "_val_" + k, v)
441 +
442 + def setdefault(self, key, default=None):
443 + try:
444 + return self[key]
445 + except KeyError:
446 + self[key] = default
447 + return default
448 +
449 + def update(self, d):
450 + i = getattr(d, "iteritems", None)
451 + if i is None:
452 + i = d
453 + else:
454 + i = i()
455 + for k, v in i:
456 + self[k] = v
457 +
458 + def __getitem__(self, k):
459 + try:
460 + return getattr(self, "_val_" + k)
461 + except AttributeError:
462 + raise KeyError(k)
463 +
464 + def get(self, key, default=None):
465 + try:
466 + return self[key]
467 + except KeyError:
468 + return default
469 +
470 + def __contains__(self, k):
471 + return hasattr(self, "_val_" + k)
472 +
473 + def has_key(self, k):
474 + return k in self
475 +
476 + def pop(self, key, *args):
477 + if len(args) > 1:
478 + raise TypeError(
479 + "pop expected at most 2 arguments, got " + \
480 + repr(1 + len(args)))
481 + try:
482 + value = self[key]
483 + except KeyError:
484 + if args:
485 + return args[0]
486 + raise
487 + del self[key]
488 + return value
489 +
490 + def popitem(self):
491 + try:
492 + k, v = self.iteritems().next()
493 + except StopIteration:
494 + raise KeyError('container is empty')
495 + del self[k]
496 + return (k, v)
497 +
498 + def copy(self):
499 + c = self.__class__()
500 + c.update(self)
501 + return c
502 +
503 + def clear(self):
504 + for k in self.allowed_keys:
505 + try:
506 + delattr(self, "_val_" + k)
507 + except AttributeError:
508 + pass
509 +
510 + v = SlotDict
511 + _slot_dict_classes[v.allowed_keys] = v
512 + return v
513
514 Modified: main/branches/prefix/pym/portage/dbapi/bintree.py
515 ===================================================================
516 --- main/branches/prefix/pym/portage/dbapi/bintree.py 2008-06-27 12:11:33 UTC (rev 10813)
517 +++ main/branches/prefix/pym/portage/dbapi/bintree.py 2008-06-27 14:47:19 UTC (rev 10814)
518 @@ -2,6 +2,7 @@
519 # Distributed under the terms of the GNU General Public License v2
520 # $Id$
521
522 +from portage.cache.mappings import slot_dict_class
523 from portage.dep import isvalidatom, isjustname, dep_getkey, match_from_list
524 from portage.dbapi.virtual import fakedbapi
525 from portage.exception import InvalidPackageName, InvalidAtom, \
526 @@ -18,7 +19,7 @@
527
528 import os, errno, stat
529 import re
530 -from itertools import izip
531 +from itertools import chain, izip
532
533 class bindbapi(fakedbapi):
534 _known_keys = frozenset(list(fakedbapi._known_keys) + \
535 @@ -35,6 +36,7 @@
536 "LICENSE", "PDEPEND", "PROVIDE",
537 "RDEPEND", "repository", "RESTRICT", "SLOT", "USE",
538 "EPREFIX"])
539 + self._aux_cache_slot_dict = slot_dict_class(self._aux_cache_keys)
540 self._aux_cache = {}
541
542 def match(self, *pargs, **kwargs):
543 @@ -77,7 +79,7 @@
544 if not mydata.setdefault("EAPI", "0"):
545 mydata["EAPI"] = "0"
546 if cache_me:
547 - aux_cache = {}
548 + aux_cache = self._aux_cache_slot_dict()
549 for x in self._aux_cache_keys:
550 aux_cache[x] = mydata.get(x, "")
551 self._aux_cache[mycpv] = aux_cache
552 @@ -187,6 +189,16 @@
553 ("repository" , "REPO"),
554 )
555
556 + self._pkgindex_allowed_pkg_keys = set(chain(
557 + self._pkgindex_keys,
558 + self._pkgindex_aux_keys,
559 + self._pkgindex_hashes,
560 + self._pkgindex_default_pkg_data,
561 + self._pkgindex_inherited_keys,
562 + self._pkgindex_default_header_data,
563 + chain(*self._pkgindex_translated_keys)
564 + ))
565 +
566 def move_ent(self, mylist):
567 if not self.populated:
568 self.populate()
569 @@ -483,7 +495,7 @@
570 update_pkgindex = True
571 self.dbapi.cpv_inject(mycpv)
572 if not self.dbapi._aux_cache_keys.difference(d):
573 - aux_cache = {}
574 + aux_cache = self.dbapi._aux_cache_slot_dict()
575 for k in self.dbapi._aux_cache_keys:
576 aux_cache[k] = d[k]
577 self.dbapi._aux_cache[mycpv] = aux_cache
578 @@ -580,7 +592,7 @@
579 d.pop("PATH", None)
580 metadata[mycpv] = d
581 if not self.dbapi._aux_cache_keys.difference(d):
582 - aux_cache = {}
583 + aux_cache = self.dbapi._aux_cache_slot_dict()
584 for k in self.dbapi._aux_cache_keys:
585 aux_cache[k] = d[k]
586 self.dbapi._aux_cache[mycpv] = aux_cache
587 @@ -835,6 +847,7 @@
588
589 def _new_pkgindex(self):
590 return portage.getbinpkg.PackageIndex(
591 + allowed_pkg_keys=self._pkgindex_allowed_pkg_keys,
592 default_header_data=self._pkgindex_default_header_data,
593 default_pkg_data=self._pkgindex_default_pkg_data,
594 inherited_keys=self._pkgindex_inherited_keys,
595
596 Modified: main/branches/prefix/pym/portage/dbapi/porttree.py
597 ===================================================================
598 --- main/branches/prefix/pym/portage/dbapi/porttree.py 2008-06-27 12:11:33 UTC (rev 10813)
599 +++ main/branches/prefix/pym/portage/dbapi/porttree.py 2008-06-27 14:47:19 UTC (rev 10814)
600 @@ -3,6 +3,7 @@
601 # $Id$
602
603 from portage.cache.cache_errors import CacheError
604 +from portage.cache.mappings import slot_dict_class
605 from portage.const import REPO_NAME_LOC
606 from portage.data import portage_gid, secpass
607 from portage.dbapi import dbapi
608 @@ -138,6 +139,10 @@
609 ["DEPEND", "EAPI", "IUSE", "KEYWORDS", "LICENSE",
610 "PDEPEND", "PROVIDE", "RDEPEND", "repository",
611 "RESTRICT", "SLOT"])
612 +
613 + # Repoman modifies _aux_cache_keys, so delay _aux_cache_slot_dict
614 + # initialization until the first aux_get call.
615 + self._aux_cache_slot_dict = None
616 self._aux_cache = {}
617 self._broken_ebuilds = set()
618
619 @@ -386,7 +391,10 @@
620 returnme.append(mydata.get(x,""))
621
622 if cache_me:
623 - aux_cache = {}
624 + if self._aux_cache_slot_dict is None:
625 + self._aux_cache_slot_dict = \
626 + slot_dict_class(self._aux_cache_keys)
627 + aux_cache = self._aux_cache_slot_dict()
628 for x in self._aux_cache_keys:
629 aux_cache[x] = mydata.get(x, "")
630 self._aux_cache[mycpv] = aux_cache
631 @@ -866,4 +874,3 @@
632 except Exception, e:
633 pass
634 return myslot
635 -
636
637 Modified: main/branches/prefix/pym/portage/getbinpkg.py
638 ===================================================================
639 --- main/branches/prefix/pym/portage/getbinpkg.py 2008-06-27 12:11:33 UTC (rev 10813)
640 +++ main/branches/prefix/pym/portage/getbinpkg.py 2008-06-27 14:47:19 UTC (rev 10814)
641 @@ -4,6 +4,7 @@
642 # $Id$
643
644 from portage.output import red, yellow, green
645 +from portage.cache.mappings import slot_dict_class
646 import portage.xpak
647 import HTMLParser
648 import sys
649 @@ -681,8 +682,17 @@
650
651 class PackageIndex(object):
652
653 - def __init__(self, default_header_data=None, default_pkg_data=None,
654 - inherited_keys=None, translated_keys=None):
655 + def __init__(self,
656 + allowed_pkg_keys=None,
657 + default_header_data=None,
658 + default_pkg_data=None,
659 + inherited_keys=None,
660 + translated_keys=None):
661 +
662 + self._pkg_slot_dict = None
663 + if allowed_pkg_keys is not None:
664 + self._pkg_slot_dict = slot_dict_class(allowed_pkg_keys)
665 +
666 self._default_header_data = default_header_data
667 self._default_pkg_data = default_pkg_data
668 self._inherited_keys = inherited_keys
669 @@ -697,8 +707,15 @@
670 self.packages = []
671 self.modified = True
672
673 - def _readpkgindex(self, pkgfile):
674 - d = {}
675 + def _readpkgindex(self, pkgfile, pkg_entry=True):
676 +
677 + allowed_keys = None
678 + if self._pkg_slot_dict is None or not pkg_entry:
679 + d = {}
680 + else:
681 + d = self._pkg_slot_dict()
682 + allowed_keys = d.allowed_keys
683 +
684 for line in pkgfile:
685 line = line.rstrip("\n")
686 if not line:
687 @@ -709,7 +726,11 @@
688 k, v = line
689 if v:
690 v = v[1:]
691 - d[self._read_translation_map.get(k, k)] = v
692 + k = self._read_translation_map.get(k, k)
693 + if allowed_keys is not None and \
694 + k not in allowed_keys:
695 + continue
696 + d[k] = v
697 return d
698
699 def _writepkgindex(self, pkgfile, items):
700 @@ -723,7 +744,7 @@
701 self.readBody(pkgfile)
702
703 def readHeader(self, pkgfile):
704 - self.header.update(self._readpkgindex(pkgfile))
705 + self.header.update(self._readpkgindex(pkgfile, pkg_entry=False))
706
707 def readBody(self, pkgfile):
708 while True:
709
710 Modified: main/branches/prefix/pym/portage/util.py
711 ===================================================================
712 --- main/branches/prefix/pym/portage/util.py 2008-06-27 12:11:33 UTC (rev 10813)
713 +++ main/branches/prefix/pym/portage/util.py 2008-06-27 14:47:19 UTC (rev 10814)
714 @@ -913,6 +913,67 @@
715 perms_modified = apply_permissions(dir_path, *args, **kwargs)
716 return created_dir or perms_modified
717
718 +class ObjectProxy(object):
719 +
720 + """
721 + Object that acts as a proxy to another object, forwarding
722 + attribute accesses and method calls. This can be useful
723 + for implementing lazy initialization.
724 + """
725 +
726 + def _get_target(self):
727 + raise NotImplementedError(self)
728 +
729 + def __getattribute__(self, attr):
730 + result = object.__getattribute__(self, '_get_target')()
731 + return getattr(result, attr)
732 +
733 + def __setattr__(self, attr, value):
734 + result = object.__getattribute__(self, '_get_target')()
735 + setattr(result, attr, value)
736 +
737 + def __call__(self, *args, **kwargs):
738 + result = object.__getattribute__(self, '_get_target')()
739 + return result(*args, **kwargs)
740 +
741 + def __setitem__(self, key, value):
742 + object.__getattribute__(self, '_get_target')()[key] = value
743 +
744 + def __getitem__(self, key):
745 + return object.__getattribute__(self, '_get_target')()[key]
746 +
747 + def __delitem__(self, key):
748 + del object.__getattribute__(self, '_get_target')()[key]
749 +
750 + def __contains__(self, key):
751 + return key in object.__getattribute__(self, '_get_target')()
752 +
753 + def __iter__(self):
754 + return iter(object.__getattribute__(self, '_get_target')())
755 +
756 + def __len__(self):
757 + return len(object.__getattribute__(self, '_get_target')())
758 +
759 + def __repr__(self):
760 + return repr(object.__getattribute__(self, '_get_target')())
761 +
762 + def __str__(self):
763 + return str(object.__getattribute__(self, '_get_target')())
764 +
765 + def __hash__(self):
766 + return hash(object.__getattribute__(self, '_get_target')())
767 +
768 + def __eq__(self, other):
769 + return object.__getattribute__(self, '_get_target')() == other
770 +
771 + def __ne__(self, other):
772 + return object.__getattribute__(self, '_get_target')() != other
773 +
774 + def __nonzero__(self):
775 + if object.__getattribute__(self, '_get_target')():
776 + return True
777 + return False
778 +
779 class LazyItemsDict(dict):
780 """A mapping object that behaves like a standard dict except that it allows
781 for lazy initialization of values via callable objects. Lazy items can be
782
783 --
784 gentoo-commits@l.g.o mailing list