diff options
author | William Deegan <bill@baddogconsulting.com> | 2017-04-16 00:25:08 (GMT) |
---|---|---|
committer | William Deegan <bill@baddogconsulting.com> | 2017-04-16 00:25:08 (GMT) |
commit | 62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5 (patch) | |
tree | 44f57730990d219d817f01557fad7fa7a445e625 | |
parent | 2c7b4f7cd5a2277208902c3b59c98b8530fd8698 (diff) | |
parent | 1098541638a57e6672de8e29d9e02d713a4644a7 (diff) | |
download | SCons-62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5.zip SCons-62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5.tar.gz SCons-62bdd33553c4df9e658855b5bfb32e9f1d4ec6a5.tar.bz2 |
merge from upstream
-rw-r--r-- | src/CHANGES.txt | 4 | ||||
-rw-r--r-- | src/engine/SCons/Defaults.py | 5 | ||||
-rw-r--r-- | src/engine/SCons/Node/Python.py | 11 | ||||
-rw-r--r-- | src/engine/SCons/Node/PythonTests.py | 6 | ||||
-rw-r--r-- | src/engine/SCons/SConf.py | 8 | ||||
-rw-r--r-- | src/engine/SCons/SConfTests.py | 38 | ||||
-rw-r--r-- | src/engine/SCons/Util.py | 18 | ||||
-rw-r--r-- | src/script/sconsign.py | 5 | ||||
-rw-r--r-- | test/option--tree.py | 24 |
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: |