summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2017-04-16 00:25:08 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2017-04-16 00:25:08 (GMT)
commit62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5 (patch)
tree44f57730990d219d817f01557fad7fa7a445e625
parent2c7b4f7cd5a2277208902c3b59c98b8530fd8698 (diff)
parent1098541638a57e6672de8e29d9e02d713a4644a7 (diff)
downloadSCons-62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5.zip
SCons-62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5.tar.gz
SCons-62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5.tar.bz2
merge from upstream
-rw-r--r--src/CHANGES.txt4
-rw-r--r--src/engine/SCons/Defaults.py5
-rw-r--r--src/engine/SCons/Node/Python.py11
-rw-r--r--src/engine/SCons/Node/PythonTests.py6
-rw-r--r--src/engine/SCons/SConf.py8
-rw-r--r--src/engine/SCons/SConfTests.py38
-rw-r--r--src/engine/SCons/Util.py18
-rw-r--r--src/script/sconsign.py5
-rw-r--r--test/option--tree.py24
9 files changed, 84 insertions, 35 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index cb6ab21..5127c51 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -13,6 +13,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
RELEASE VERSION/DATE TO BE FILLED IN LATER
+ From Gaurav Juvekar:
+ - Fix issue #2910: Make --tree=all handle Unicode. (PR #427)
+ - Fix issue #2788: Fix typo in documentation example for sconf. (PR #388)
+
From Manish Vachharajani:
- Update debian rules, compat, and control to not use features
deprecated or obsolete in later versions of debhelpers
diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py
index ded9539..69d5c94 100644
--- a/src/engine/SCons/Defaults.py
+++ b/src/engine/SCons/Defaults.py
@@ -264,7 +264,10 @@ def copy_func(dest, src, symlinks=True):
shutil.copy2(src, dest)
return 0
else:
- return shutil.copytree(src, dest, symlinks)
+ shutil.copytree(src, dest, symlinks)
+ # copytree returns None in python2 and destination string in python3
+ # A error is raised in both cases, so we can just return 0 for success
+ return 0
Copy = ActionFactory(
copy_func,
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
index f151fc5..2a3ce98 100644
--- a/src/engine/SCons/Node/Python.py
+++ b/src/engine/SCons/Node/Python.py
@@ -58,7 +58,7 @@ class ValueNodeInfo(SCons.Node.NodeInfoBase):
del state['__weakref__']
except KeyError:
pass
-
+
return state
def __setstate__(self, state):
@@ -77,7 +77,7 @@ class ValueBuildInfo(SCons.Node.BuildInfoBase):
current_version_id = 2
class Value(SCons.Node.Node):
- """A class for Python variables, typically passed on the command line
+ """A class for Python variables, typically passed on the command line
or generated by a script, but not from a file or some other source.
"""
@@ -108,7 +108,7 @@ class Value(SCons.Node.Node):
is_up_to_date = SCons.Node.Node.children_are_up_to_date
def is_under(self, dir):
- # Make Value nodes get built regardless of
+ # Make Value nodes get built regardless of
# what directory scons was run from. Value nodes
# are outside the filesystem:
return 1
@@ -133,10 +133,11 @@ 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()
+ contents = contents + kid.get_contents().decode()
return contents
- get_contents = get_text_contents ###TODO should return 'bytes' value
+ def get_contents(self):
+ return self.get_text_contents().encode()
def changed_since_last_build(self, target, prev_ni):
cur_csig = self.get_csig()
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
index e2e36bf..346542b 100644
--- a/src/engine/SCons/Node/PythonTests.py
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -90,15 +90,15 @@ class ValueTestCase(unittest.TestCase):
"""
v1 = SCons.Node.Python.Value('aaa')
csig = v1.get_csig(None)
- assert csig == 'aaa', csig
+ assert csig.decode() == 'aaa', csig
v2 = SCons.Node.Python.Value(7)
csig = v2.get_csig(None)
- assert csig == '7', csig
+ assert csig.decode() == '7', csig
v3 = SCons.Node.Python.Value(None)
csig = v3.get_csig(None)
- assert csig == 'None', csig
+ assert csig.decode() == 'None', csig
class ValueNodeInfoTestCase(unittest.TestCase):
def test___init__(self):
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index 31d9402..889af4a 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -110,7 +110,7 @@ def _createConfigH(target, source, env):
#define %(DEFNAME)s_SEEN
""" % {'DEFNAME' : defname})
- t.write(source[0].get_contents())
+ t.write(source[0].get_contents().decode())
t.write("""
#endif /* %(DEFNAME)s_SEEN */
""" % {'DEFNAME' : defname})
@@ -164,11 +164,11 @@ class ConfigureCacheError(SConfError):
# define actions for building text files
def _createSource( target, source, env ):
fd = open(str(target[0]), "w")
- fd.write(source[0].get_contents())
+ fd.write(source[0].get_contents().decode())
fd.close()
def _stringSource( target, source, env ):
return (str(target[0]) + ' <-\n |' +
- source[0].get_contents().replace( '\n', "\n |" ) )
+ source[0].get_contents().decode().replace( '\n', "\n |" ) )
class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
"""
@@ -609,7 +609,7 @@ class SConfBase(object):
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
del self.env['BUILDERS']['SConfActionBuilder']
if ok:
- outputStr = self.lastTarget.get_contents()
+ outputStr = self.lastTarget.get_contents().decode()
return (1, outputStr)
return (0, "")
diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py
index b2aa3b4..0daf31c 100644
--- a/src/engine/SCons/SConfTests.py
+++ b/src/engine/SCons/SConfTests.py
@@ -48,7 +48,7 @@ class SConfTestCase(unittest.TestCase):
def setUp(self):
# we always want to start with a clean directory
self.save_cwd = os.getcwd()
- self.test = TestCmd.TestCmd(workdir = '')
+ self.test = TestCmd.TestCmd(workdir = '')
os.chdir(self.test.workpath(''))
def tearDown(self):
@@ -109,7 +109,7 @@ class SConfTestCase(unittest.TestCase):
# TryCompile and TryLink are much the same, so we can test them
# in one method, we pass the function as a string ('TryCompile',
# 'TryLink'), so we are aware of reloading modules.
-
+
def checks(self, sconf, TryFuncString):
TryFunc = self.SConf.SConfBase.__dict__[TryFuncString]
res1 = TryFunc( sconf, "int main() { return 0; }\n", ".c" )
@@ -128,7 +128,7 @@ class SConfTestCase(unittest.TestCase):
assert res[0] and not res[1], res
finally:
sconf.Finish()
-
+
# 2.1 test the error caching mechanism (no dependencies have changed)
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
@@ -139,9 +139,9 @@ class SConfTestCase(unittest.TestCase):
assert res[0] and not res[1], res
finally:
sconf.Finish()
- # we should have exactly one one error cached
+ # we should have exactly one one error cached
log = str(self.test.read( self.test.workpath('config.log') ))
- expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
+ expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
firstOcc = expr.match( log )
assert firstOcc is not None, log
secondOcc = expr.match( log, firstOcc.end(0) )
@@ -239,11 +239,11 @@ class SConfTestCase(unittest.TestCase):
"""Test SConf.TryCompile
"""
self._baseTryXXX( "TryCompile" ) #self.SConf.SConf.TryCompile )
-
+
def test_TryLink(self):
"""Test SConf.TryLink
"""
- self._baseTryXXX( "TryLink" ) #self.SConf.SConf.TryLink )
+ self._baseTryXXX( "TryLink" ) #self.SConf.SConf.TryLink )
def test_TryRun(self):
"""Test SConf.TryRun
@@ -256,10 +256,10 @@ int main() {
return 0;
}
"""
- res1 = sconf.TryRun( prog, ".c" )
+ res1 = sconf.TryRun( prog, ".c" )
res2 = sconf.TryRun( "not a c program\n", ".c" )
return (res1, res2)
-
+
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
conf_dir=self.test.workpath('config.tests'),
@@ -307,7 +307,7 @@ int main() {
log_file=self.test.workpath('config.log'))
try:
(ret, output) = sconf.TryAction(action=actionOK)
- assert ret and output == bytearray("RUN OK"+os.linesep,'utf-8'), (ret, output)
+ assert ret and output.encode('utf-8') == bytearray("RUN OK"+os.linesep,'utf-8'), (ret, output)
(ret, output) = sconf.TryAction(action=actionFAIL)
assert not ret and output == "", (ret, output)
finally:
@@ -354,7 +354,7 @@ int main() {
try:
self._test_check_compilers('CC', sconf.CheckCC, 'CheckCC')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -370,7 +370,7 @@ int main() {
try:
self._test_check_compilers('SHCC', sconf.CheckSHCC, 'CheckSHCC')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -386,7 +386,7 @@ int main() {
try:
self._test_check_compilers('CXX', sconf.CheckCXX, 'CheckCXX')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -402,7 +402,7 @@ int main() {
try:
self._test_check_compilers('SHCXX', sconf.CheckSHCXX, 'CheckSHCXX')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -627,8 +627,8 @@ int main() {
else:
r = sconf.CheckProg('cmd.exe')
self.assertIn('cmd.exe',r)
-
-
+
+
r = sconf.CheckProg('hopefully-not-a-program')
assert r is None
@@ -717,7 +717,7 @@ int main() {
# In ANSI C, malloc should be available in stdlib
r = sconf.CheckDeclaration('malloc', includes = "#include <stdlib.h>")
assert r, "malloc not declared ??"
- # For C++, __cplusplus should be declared
+ # For C++, __cplusplus should be declared
r = sconf.CheckDeclaration('__cplusplus', language = 'C++')
assert r, "__cplusplus not declared in C++ ??"
r = sconf.CheckDeclaration('__cplusplus', language = 'C')
@@ -761,7 +761,7 @@ int main() {
test.Result( ret )
assert ret and output == "Hello", (ret, output)
return ret
-
+
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
@@ -773,7 +773,7 @@ int main() {
assert ret, ret
finally:
sconf.Finish()
-
+
if __name__ == "__main__":
suite = unittest.makeSuite(SConfTestCase, 'test_')
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index a8a6990..2d8e75a 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -31,6 +31,7 @@ import sys
import copy
import re
import types
+import codecs
try:
from UserDict import UserDict
@@ -148,7 +149,7 @@ class NodeList(UserList):
# else:
# self.data = [ initlist,]
-
+
def __nonzero__(self):
return len(self.data) != 0
@@ -170,10 +171,10 @@ class NodeList(UserList):
return self.__class__(result)
def __getitem__(self, index):
- """
+ """
This comes for free on py2,
but py3 slices of NodeList are returning a list
- breaking slicing nodelist and refering to
+ breaking slicing nodelist and refering to
properties and methods on contained object
"""
# return self.__class__(self.data[index])
@@ -289,6 +290,17 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
"""
rname = str(root)
+ if sys.version_info.major < 3:
+ # Python 2 UTF-8 encoded str are str. escape_encode is a str to str
+ # encoding
+ rname = codecs.escape_encode(rname)[0]
+ else:
+ # Python 3 UTF-8 encoded str are bytes. escape_encode is a byte to byte
+ # encoding here.
+ rname = rname.encode('utf-8')
+ rname = codecs.escape_encode(rname)[0]
+ # Finally, we need a string again.
+ rname = rname.decode('ascii')
# Initialize 'visited' dict, if required
if visited is None:
diff --git a/src/script/sconsign.py b/src/script/sconsign.py
index 8f1722a..2e7a550 100644
--- a/src/script/sconsign.py
+++ b/src/script/sconsign.py
@@ -241,6 +241,11 @@ def default_mapper(entry, name):
val = eval("entry."+name)
except:
val = None
+ if sys.version_info.major >= 3 and isinstance(val, bytes):
+ # This is a dirty hack for py 2/3 compatibility. csig is a bytes object
+ # in Python3 while Python2 bytes are str. Hence, we decode the csig to a
+ # Python3 string
+ val = val.decode()
return str(val)
def map_action(entry, name):
diff --git a/test/option--tree.py b/test/option--tree.py
index a50433c..a9618d8 100644
--- a/test/option--tree.py
+++ b/test/option--tree.py
@@ -51,6 +51,30 @@ scons: warning: The --debug=tree option is deprecated; please use --tree=all ins
""",
status = 0, match=TestSCons.match_re_dotall)
+
+# Test that unicode characters can be printed (escaped) with the --tree option
+test.write('SConstruct',
+"""
+env = Environment()
+env.Tool("textfile")
+try:
+ # Python 2
+ write = unichr(0xe7).encode('utf-8')
+except NameError:
+ # Python 3
+ # str is utf-8 by default
+ write = chr(0xe7)
+env.Textfile("Foo", write)
+""")
+
+test.run(arguments = '-Q --tree=all',
+ stdout = """Creating 'Foo.txt'
++-.
+ +-Foo.txt
+ | +-\\xc3\\xa7
+ +-SConstruct
+""",
+ status = 0)
test.pass_test()
# Local Variables: