diff options
Diffstat (limited to 'SCons/Node')
-rw-r--r-- | SCons/Node/Alias.py | 18 | ||||
-rw-r--r-- | SCons/Node/AliasTests.py | 7 | ||||
-rw-r--r-- | SCons/Node/FS.py | 78 | ||||
-rw-r--r-- | SCons/Node/FSTests.py | 24 | ||||
-rw-r--r-- | SCons/Node/NodeTests.py | 9 | ||||
-rw-r--r-- | SCons/Node/Python.py | 33 | ||||
-rw-r--r-- | SCons/Node/PythonTests.py | 6 | ||||
-rw-r--r-- | SCons/Node/__init__.py | 92 |
8 files changed, 112 insertions, 155 deletions
diff --git a/SCons/Node/Alias.py b/SCons/Node/Alias.py index 55d94f9..64054d2 100644 --- a/SCons/Node/Alias.py +++ b/SCons/Node/Alias.py @@ -1,14 +1,6 @@ - -"""scons.Node.Alias - -Alias nodes. - -This creates a hash of global Aliases (dummy targets). - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,9 +20,11 @@ This creates a hash of global Aliases (dummy targets). # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Alias nodes. + +This creates a hash of global Aliases (dummy targets). +""" import collections diff --git a/SCons/Node/AliasTests.py b/SCons/Node/AliasTests.py index 613a5c0..14662fd 100644 --- a/SCons/Node/AliasTests.py +++ b/SCons/Node/AliasTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import sys import unittest import SCons.Errors diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py index ad9dd6f..290fcb3 100644 --- a/SCons/Node/FS.py +++ b/SCons/Node/FS.py @@ -1,17 +1,6 @@ -"""scons.Node.FS - -File system nodes. - -These Nodes represent the canonical external objects that people think -of when they think of building software: files and directories. - -This holds a "default_fs" variable that should be initialized with an FS -that can be used by scripts or modules looking for the canonical default. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -31,7 +20,15 @@ that can be used by scripts or modules looking for the canonical default. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +"""File system nodes. + +These Nodes represent the canonical external objects that people think +of when they think of building software: files and directories. + +This holds a "default_fs" variable that should be initialized with an FS +that can be used by scripts or modules looking for the canonical default. +""" import fnmatch import os @@ -46,7 +43,7 @@ import importlib.util import SCons.Action import SCons.Debug -from SCons.Debug import logInstanceCreation +from SCons.Debug import logInstanceCreation, Trace import SCons.Errors import SCons.Memoize import SCons.Node @@ -56,8 +53,6 @@ import SCons.Util from SCons.Util import MD5signature, MD5filesignature, MD5collect import SCons.Warnings -from SCons.Debug import Trace - print_duplicate = 0 MD5_TIMESTAMP_DEBUG = False @@ -439,7 +434,7 @@ class EntryProxy(SCons.Util.Proxy): # In PY3 if a class defines __eq__, then it must explicitly provide # __hash__. Since SCons.Util.Proxy provides __eq__ we need the following - # see: https://docs.python.org/3.1/reference/datamodel.html#object.__hash__ + # see: https://docs.python.org/3/reference/datamodel.html#object.__hash__ __hash__ = SCons.Util.Delegate('__hash__') def __get_abspath(self): @@ -2698,11 +2693,13 @@ class File(Base): def scanner_key(self): return self.get_suffix() - def get_contents(self): + def get_contents(self) -> bytes: + """Return the contents of the file as bytes.""" return SCons.Node._get_contents_map[self._func_get_contents](self) - def get_text_contents(self): - """ + def get_text_contents(self) -> str: + """Return the contents of the file in text form. + This attempts to figure out what the encoding of the text is based upon the BOM bytes, and then decodes the contents so that it's a valid python string. @@ -2726,15 +2723,13 @@ class File(Base): try: return contents.decode('latin-1') except UnicodeDecodeError as e: - return contents.decode('utf-8', error='backslashreplace') + return contents.decode('utf-8', errors='backslashreplace') - def get_content_hash(self): - """ - Compute and return the MD5 hash for this file. - """ + def get_content_hash(self) -> str: + """Compute and return the hash of the file contents.""" if not self.rexists(): - return MD5signature('') + return MD5signature(SCons.Util.NOFILE) fname = self.rfile().get_abspath() try: cs = MD5filesignature(fname, chunksize=File.md5_chunksize) @@ -2745,7 +2740,7 @@ class File(Base): return cs @SCons.Memoize.CountMethodCall - def get_size(self): + def get_size(self) -> int: try: return self._memo['get_size'] except KeyError: @@ -2754,14 +2749,14 @@ class File(Base): if self.rexists(): size = self.rfile().getsize() else: - size = 0 + # sentinel value for doesn't exist, even in repository + size = -1 self._memo['get_size'] = size - return size @SCons.Memoize.CountMethodCall - def get_timestamp(self): + def get_timestamp(self) -> int: try: return self._memo['get_timestamp'] except KeyError: @@ -2773,7 +2768,6 @@ class File(Base): timestamp = 0 self._memo['get_timestamp'] = timestamp - return timestamp convert_copy_attrs = [ @@ -2785,7 +2779,6 @@ class File(Base): 'ninfo', ] - convert_sig_attrs = [ 'bsourcesigs', 'bimplicitsigs', @@ -3178,7 +3171,7 @@ class File(Base): # SIGNATURE SUBSYSTEM # - def get_max_drift_csig(self): + def get_max_drift_csig(self) -> str: """ Returns the content signature currently stored for this node if it's been unmodified longer than the max_drift value, or the @@ -3204,15 +3197,8 @@ class File(Base): return None - def get_csig(self): - """ - Generate a node's content signature, the digested signature - of its content. - - node - the node - cache - alternate node to use for the signature cache - returns - the content signature - """ + def get_csig(self) -> str: + """Generate a node's content signature.""" ninfo = self.get_ninfo() try: return ninfo.csig @@ -3221,9 +3207,11 @@ class File(Base): csig = self.get_max_drift_csig() if csig is None: - try: - if self.get_size() < File.md5_chunksize: + size = self.get_size() + if size == -1: + contents = SCons.Util.NOFILE + elif size < File.md5_chunksize: contents = self.get_contents() else: csig = self.get_content_hash() diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py index 77c6dbb..1f886d7 100644 --- a/SCons/Node/FSTests.py +++ b/SCons/Node/FSTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,11 +20,8 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.compat - import os import os.path import sys @@ -1694,7 +1692,6 @@ class FSTestCase(_tempdirTestCase): except AttributeError: # could be python 3.7 or newer, make sure splitdrive can do UNC assert ntpath.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive' - pass path = strip_slash(path) return '//' + path[1:] @@ -2689,8 +2686,11 @@ class FileTestCase(_tempdirTestCase): print("%15s -> csig:%s" % (i3.name, i3.ninfo.csig)) print("%15s -> csig:%s" % (i4.name, i4.ninfo.csig)) - self.assertEqual(i2.name, i2.ninfo.csig, - "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig) + self.assertEqual( + i2.name, + i2.ninfo.csig, + "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig, + ) class GlobTestCase(_tempdirTestCase): @@ -3676,7 +3676,8 @@ class CacheDirTestCase(unittest.TestCase): f9 = fs.File('f9') r = f9.get_cachedir_csig() - assert r == 'd41d8cd98f00b204e9800998ecf8427e', r + exsig = SCons.Util.MD5signature(SCons.Util.NOFILE) + assert r == exsig, r class clearTestCase(unittest.TestCase): @@ -3725,6 +3726,13 @@ class clearTestCase(unittest.TestCase): assert not f.exists() assert not f.rexists() assert str(f) == test.workpath('f'), str(f) + # Now verify clear() resets optional File-specific attributes + optional_attrs = ['cachedir_csig', 'cachesig', 'contentsig'] + for attr in optional_attrs: + setattr(f, attr, 'xyz') + f.clear() + for attr in optional_attrs: + assert not hasattr(f, attr), attr class disambiguateTestCase(unittest.TestCase): diff --git a/SCons/Node/NodeTests.py b/SCons/Node/NodeTests.py index 729be01..29a3887 100644 --- a/SCons/Node/NodeTests.py +++ b/SCons/Node/NodeTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,14 +21,10 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" - import SCons.compat import collections -import os import re -import sys import unittest import SCons.Errors @@ -1300,6 +1297,7 @@ class NodeTestCase(unittest.TestCase): n.includes = 'testincludes' n.Tag('found_includes', {'testkey':'testvalue'}) n.implicit = 'testimplicit' + n.cached = 1 x = MyExecutor() n.set_executor(x) @@ -1307,6 +1305,7 @@ class NodeTestCase(unittest.TestCase): n.clear() assert n.includes is None, n.includes + assert n.cached == 0, n.cached assert x.cleaned_up def test_get_subst_proxy(self): diff --git a/SCons/Node/Python.py b/SCons/Node/Python.py index 68c6ee8..738682c 100644 --- a/SCons/Node/Python.py +++ b/SCons/Node/Python.py @@ -1,11 +1,6 @@ -"""scons.Node.Python - -Python nodes. - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -25,9 +20,8 @@ Python nodes. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""Python nodes.""" import SCons.Node @@ -135,7 +129,7 @@ class Value(SCons.Node.Node): self.built_value = self.value return self.built_value - def get_text_contents(self): + def get_text_contents(self) -> str: """By the assumption that the node.built_value is a deterministic product of the sources, the contents of a Value are the concatenation of all the contents of its sources. As @@ -144,27 +138,20 @@ class Value(SCons.Node.Node): ###TODO: something reasonable about universal newlines contents = str(self.value) for kid in self.children(None): - contents = contents + kid.get_contents().decode() + # Get csig() value of child as this is more efficent + contents = contents + kid.get_csig() return contents - def get_contents(self): - """ - Get contents for signature calculations. - :return: bytes - """ - text_contents = self.get_text_contents() - try: - return text_contents.encode() - except UnicodeDecodeError: - # Already encoded as python2 str are bytes - return text_contents + def get_contents(self) -> bytes: + """Get contents for signature calculations.""" + return self.get_text_contents().encode() def changed_since_last_build(self, target, prev_ni): cur_csig = self.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: - return 1 + return True def get_csig(self, calc=None): """Because we're a Python value node and don't have a real diff --git a/SCons/Node/PythonTests.py b/SCons/Node/PythonTests.py index b6fa859..b6a3f79 100644 --- a/SCons/Node/PythonTests.py +++ b/SCons/Node/PythonTests.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index f7d9289..3685af3 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -1,26 +1,6 @@ -"""SCons.Node - -The Node package for the SCons software construction utility. - -This is, in many ways, the heart of SCons. - -A Node is where we encapsulate all of the dependency information about -any thing that SCons can build, or about any thing which SCons can use -to build some other thing. The canonical "thing," of course, is a file, -but a Node can also represent something remote (like a web page) or -something completely abstract (like an Alias). - -Each specific type of "thing" is specifically represented by a subclass -of the Node base class: Node.FS.File for files, Node.Alias for aliases, -etc. Dependency information is kept here in the base class, and -information specific to files/aliases/etc. is in the subclass. The -goal, if we've done this correctly, is that any type of "thing" should -be able to depend on any other type of "thing." - -""" - +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -41,28 +21,36 @@ be able to depend on any other type of "thing." # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +"""The Node package for the SCons software construction utility. + +This is, in many ways, the heart of SCons. + +A Node is where we encapsulate all of the dependency information about +any thing that SCons can build, or about any thing which SCons can use +to build some other thing. The canonical "thing," of course, is a file, +but a Node can also represent something remote (like a web page) or +something completely abstract (like an Alias). + +Each specific type of "thing" is specifically represented by a subclass +of the Node base class: Node.FS.File for files, Node.Alias for aliases, +etc. Dependency information is kept here in the base class, and +information specific to files/aliases/etc. is in the subclass. The +goal, if we've done this correctly, is that any type of "thing" should +be able to depend on any other type of "thing." + +""" -import os import collections import copy -from itertools import chain - -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest +from itertools import chain, zip_longest import SCons.Debug -from SCons.Debug import logInstanceCreation import SCons.Executor import SCons.Memoize import SCons.Util -from SCons.Util import MD5signature - -from SCons.Debug import Trace - from SCons.compat import NoSlotsPyPy +from SCons.Debug import logInstanceCreation, Trace +from SCons.Util import MD5signature print_duplicate = 0 @@ -823,25 +811,21 @@ class Node(object, metaclass=NoSlotsPyPy): def release_target_info(self): """Called just after this node has been marked - up-to-date or was built completely. + up-to-date or was built completely. - This is where we try to release as many target node infos - as possible for clean builds and update runs, in order - to minimize the overall memory consumption. + This is where we try to release as many target node infos + as possible for clean builds and update runs, in order + to minimize the overall memory consumption. - By purging attributes that aren't needed any longer after - a Node (=File) got built, we don't have to care that much how - many KBytes a Node actually requires...as long as we free - the memory shortly afterwards. + By purging attributes that aren't needed any longer after + a Node (=File) got built, we don't have to care that much how + many KBytes a Node actually requires...as long as we free + the memory shortly afterwards. - @see: built() and File.release_target_info() - """ + @see: built() and File.release_target_info() + """ pass - # - # - # - def add_to_waiting_s_e(self, node): self.waiting_s_e.add(node) @@ -877,10 +861,12 @@ class Node(object, metaclass=NoSlotsPyPy): self.clear_memoized_values() self.ninfo = self.new_ninfo() self.executor_cleanup() - try: - delattr(self, '_calculated_sig') - except AttributeError: - pass + for attr in ['cachedir_csig', 'cachesig', 'contentsig']: + try: + delattr(self, attr) + except AttributeError: + pass + self.cached = 0 self.includes = None def clear_memoized_values(self): |