summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2009-02-21 21:51:13 +0000
committerZac Medico <zmedico@gentoo.org>2009-02-21 21:51:13 +0000
commitb612926a04a7ef31029e27229dea2a9d1dbddb2c (patch)
tree6b5b7757eb2092e6b1e2a651633fede13c0d136e
parente708e87e1a5d4e1e2411241382020dbcf4753494 (diff)
downloadportage-b612926a04a7ef31029e27229dea2a9d1dbddb2c.tar.gz
portage-b612926a04a7ef31029e27229dea2a9d1dbddb2c.tar.bz2
portage-b612926a04a7ef31029e27229dea2a9d1dbddb2c.zip
In config.setcpv(), use LazyItemsDict to implement lazy evaluation of
PORTAGE_IUSE. 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). Thanks to Marat Radchenko <slonopotamusorama@gmail.com> for identifying this performance issue and submitting the initial patch which used a memoization approach instead of lazy evaluation. svn path=/main/trunk/; revision=12673
-rw-r--r--pym/portage/__init__.py24
-rw-r--r--pym/portage/util.py42
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')