summaryrefslogtreecommitdiffstats
path: root/SCons/Node
diff options
context:
space:
mode:
Diffstat (limited to 'SCons/Node')
-rw-r--r--SCons/Node/Alias.py18
-rw-r--r--SCons/Node/AliasTests.py7
-rw-r--r--SCons/Node/FS.py78
-rw-r--r--SCons/Node/FSTests.py24
-rw-r--r--SCons/Node/NodeTests.py9
-rw-r--r--SCons/Node/Python.py33
-rw-r--r--SCons/Node/PythonTests.py6
-rw-r--r--SCons/Node/__init__.py92
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):