diff options
author | Gary Oberbrunner <garyo@oberbrunner.com> | 2012-05-19 22:16:42 (GMT) |
---|---|---|
committer | Gary Oberbrunner <garyo@oberbrunner.com> | 2012-05-19 22:16:42 (GMT) |
commit | bcff49f744d5ab7a69381e5b1ee24f172403378a (patch) | |
tree | 52e04144ac53a6efb7dc802b61f9b9e43efb5d41 /src/engine | |
parent | f011342d8018a0cd8ef18de017d84a12cd157f6d (diff) | |
parent | 65986dc7db253685d1e44753a49691b63cf53433 (diff) | |
download | SCons-bcff49f744d5ab7a69381e5b1ee24f172403378a.zip SCons-bcff49f744d5ab7a69381e5b1ee24f172403378a.tar.gz SCons-bcff49f744d5ab7a69381e5b1ee24f172403378a.tar.bz2 |
Merge mortoray/SCons fix for #2821, copy Builders when env is cloned.
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/SCons/Environment.py | 19 | ||||
-rw-r--r-- | src/engine/SCons/Util.py | 14 |
2 files changed, 18 insertions, 15 deletions
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index b308765..529e3a3 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -72,6 +72,7 @@ CleanTargets = {} CalculatorArgs = {} semi_deepcopy = SCons.Util.semi_deepcopy +semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict # Pull UserError into the global name space for the benefit of # Environment().SourceSignatures(), which has some import statements @@ -303,7 +304,9 @@ class BuilderDict(UserDict): UserDict.__init__(self, dict) def __semi_deepcopy__(self): - return self.__class__(self.data, self.env) + # These cannot be copied since they would both modify the same builder object, and indeed + # just copying would modify the original builder + raise TypeError( 'cannot semi_deepcopy a BuilderDict' ) def __setitem__(self, item, val): try: @@ -1374,15 +1377,15 @@ class Base(SubstitutionEnvironment): (like a function). There are no references to any mutable objects in the original Environment. """ - clone = copy.copy(self) - clone._dict = semi_deepcopy(self._dict) - try: - cbd = clone._dict['BUILDERS'] + builders = self._dict['BUILDERS'] except KeyError: pass - else: - clone._dict['BUILDERS'] = BuilderDict(cbd, clone) + + clone = copy.copy(self) + # BUILDERS is not safe to do a simple copy + clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS']) + clone._dict['BUILDERS'] = BuilderDict(builders, clone) # Check the methods added via AddMethod() and re-bind them to # the cloned environment. Only do this if the attribute hasn't @@ -1733,7 +1736,7 @@ class Base(SubstitutionEnvironment): except KeyError: pass else: - kwbd = semi_deepcopy(kwbd) + kwbd = BuilderDict(kwbd,self) del kw['BUILDERS'] self.__setitem__('BUILDERS', kwbd) kw = copy_non_reserved_keywords(kw) diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 2523eda..822d524 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -430,15 +430,15 @@ def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, # references to anything else it finds. # # A special case is any object that has a __semi_deepcopy__() method, -# which we invoke to create the copy, which is used by the BuilderDict -# class because of its extra initialization argument. +# which we invoke to create the copy. Currently only used by +# BuilderDict to actually prevent the copy operation (as invalid on that object) # # The dispatch table approach used here is a direct rip-off from the # normal Python copy module. _semi_deepcopy_dispatch = d = {} -def _semi_deepcopy_dict(x): +def semi_deepcopy_dict(x, exclude = [] ): copy = {} for key, val in x.items(): # The regular Python copy.deepcopy() also deepcopies the key, @@ -447,9 +447,10 @@ def _semi_deepcopy_dict(x): # copy[semi_deepcopy(key)] = semi_deepcopy(val) # # Doesn't seem like we need to, but we'll comment it just in case. - copy[key] = semi_deepcopy(val) + if key not in exclude: + copy[key] = semi_deepcopy(val) return copy -d[dict] = _semi_deepcopy_dict +d[dict] = semi_deepcopy_dict def _semi_deepcopy_list(x): return list(map(semi_deepcopy, x)) @@ -467,14 +468,13 @@ def semi_deepcopy(x): if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__): return x.__semi_deepcopy__() elif isinstance(x, UserDict): - return x.__class__(_semi_deepcopy_dict(x)) + return x.__class__(semi_deepcopy_dict(x)) elif isinstance(x, UserList): return x.__class__(_semi_deepcopy_list(x)) return x - class Proxy(object): """A simple generic Proxy class, forwarding all calls to subject. So, for the benefit of the python newbie, what does |