diff options
-rw-r--r-- | pym/portage/__init__.py | 24 | ||||
-rw-r--r-- | pym/portage/util.py | 42 |
2 files changed, 58 insertions, 8 deletions
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index c18d43013..992f257cb 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -958,6 +958,19 @@ def check_config_instance(test): if not isinstance(test, config): raise TypeError("Invalid type for config object: %s (should be %s)" % (test.__class__, config)) +def _lazy_iuse_regex(iuse_implicit): + """ + The PORTAGE_IUSE value is lazily evaluated since re.escape() is slow + and the value is only used when an ebuild phase needs to be executed + (it's used only to generate QA notices). + """ + # Escape anything except ".*" which is supposed to pass through from + # _get_implicit_iuse(). + regex = sorted(re.escape(x) for x in iuse_implicit) + regex = "^(%s)$" % "|".join(regex) + regex = regex.replace("\\.\\*", ".*") + return regex + class config(object): """ This class encompasses the main portage configuration. Data is pulled from @@ -1484,7 +1497,7 @@ class config(object): self.configlist.append(self.mygcfg) self.configdict["conf"]=self.configlist[-1] - self.configlist.append({}) + self.configlist.append(util.LazyItemsDict()) self.configdict["pkg"]=self.configlist[-1] #auto-use: @@ -2077,12 +2090,9 @@ class config(object): iuse_implicit = self._get_implicit_iuse() iuse_implicit.update(x.lstrip("+-") for x in iuse.split()) - # Escape anything except ".*" which is supposed - # to pass through from _get_implicit_iuse() - regex = sorted(re.escape(x) for x in iuse_implicit) - regex = "^(%s)$" % "|".join(regex) - regex = regex.replace("\\.\\*", ".*") - self.configdict["pkg"]["PORTAGE_IUSE"] = regex + # PORTAGE_IUSE is not always needed so it's lazily evaluated. + self.configdict["pkg"].addLazySingleton( + "PORTAGE_IUSE", _lazy_iuse_regex, iuse_implicit) ebuild_force_test = self.get("EBUILD_FORCE_TEST") == "1" if ebuild_force_test and \ diff --git a/pym/portage/util.py b/pym/portage/util.py index 33a61a26b..ce226a4f7 100644 --- a/pym/portage/util.py +++ b/pym/portage/util.py @@ -2,7 +2,6 @@ # Distributed under the terms of the GNU General Public License v2 # $Id$ - import os import errno import logging @@ -1244,6 +1243,47 @@ class LazyItemsDict(dict): del self.lazy_items[item_key] dict.__delitem__(self, item_key) + def clear(self): + self.lazy_items.clear() + dict.clear(self) + + def copy(self): + return self.__copy__() + + def __copy__(self): + return self.__class__(self) + + def __deepcopy__(self, memo=None): + """ + WARNING: If any of the lazy items contains a bound method then it's + typical for deepcopy() to raise an exception like this: + + File "/usr/lib/python2.5/copy.py", line 189, in deepcopy + y = _reconstruct(x, rv, 1, memo) + File "/usr/lib/python2.5/copy.py", line 322, in _reconstruct + y = callable(*args) + File "/usr/lib/python2.5/copy_reg.py", line 92, in __newobj__ + return cls.__new__(cls, *args) + TypeError: instancemethod expected at least 2 arguments, got 0 + + If deepcopy() needs to work, this problem can be avoided by + implementing lazy items with normal (non-bound) functions. + """ + if memo is None: + memo = {} + from copy import deepcopy + result = self.__class__() + memo[id(self)] = result + for k in self: + k_copy = deepcopy(k, memo) + if k in self.lazy_items: + dict.__setitem__(result, k_copy, None) + result.lazy_items[k_copy] = \ + deepcopy(self.lazy_items[k], memo) + else: + dict.__setitem__(result, k_copy, deepcopy(self[k], memo)) + return result + class _SingletonWrapper(object): __slots__ = ('_parent', '_key', '_callable', '_pargs', '_kwargs') |