From 916e4fa90ee512fedeba05665fb357ffd208319c Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Sun, 26 Mar 2017 15:59:59 +0530 Subject: string-escape unicode characters while printing --tree Fixes #2910 --- src/engine/SCons/Util.py | 8 ++++---- test/option--tree.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index a8a6990..ecdd77f 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -148,7 +148,7 @@ class NodeList(UserList): # else: # self.data = [ initlist,] - + def __nonzero__(self): return len(self.data) != 0 @@ -170,10 +170,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]) @@ -288,7 +288,7 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None): or in the whole tree if prune. """ - rname = str(root) + rname = str(root).encode('string-escape') # Initialize 'visited' dict, if required if visited is None: diff --git a/test/option--tree.py b/test/option--tree.py index a50433c..a8c360e 100644 --- a/test/option--tree.py +++ b/test/option--tree.py @@ -51,6 +51,23 @@ 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 with the --tree option +test.write('SConstruct', +""" +env = Environment() +env.Tool("textfile") +env.Textfile("Foo", unichr(0xe7).encode('utf-8')) +""") + +test.run(arguments = '-Q --tree=all', + stdout = """Creating 'Foo.txt' ++-. + +-Foo.txt + | +-\\xc3\\xa7 + +-SConstruct +""", + status = 0) test.pass_test() # Local Variables: -- cgit v0.12 From b34164950ee97eb57f28ed665137e95de70effb9 Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Sun, 26 Mar 2017 16:06:01 +0530 Subject: Reword comment in test case to highlight that unicode is printed escaped --- test/option--tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/option--tree.py b/test/option--tree.py index a8c360e..1c1832b 100644 --- a/test/option--tree.py +++ b/test/option--tree.py @@ -52,7 +52,7 @@ 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 with the --tree option +# Test that unicode characters can be printed (escaped) with the --tree option test.write('SConstruct', """ env = Environment() -- cgit v0.12 From 52f4d73e7b8577660ccf9d8c0a9f6fb5837c2e28 Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Mon, 27 Mar 2017 12:32:29 +0530 Subject: Make --tree=all work with Python 3 The codecs module is used which is distributed in the python standard library. --- src/engine/SCons/Util.py | 14 +++++++++++++- test/option--tree.py | 9 ++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index ecdd77f..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 @@ -288,7 +289,18 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None): or in the whole tree if prune. """ - rname = str(root).encode('string-escape') + 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/test/option--tree.py b/test/option--tree.py index 1c1832b..a9618d8 100644 --- a/test/option--tree.py +++ b/test/option--tree.py @@ -57,7 +57,14 @@ test.write('SConstruct', """ env = Environment() env.Tool("textfile") -env.Textfile("Foo", unichr(0xe7).encode('utf-8')) +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', -- cgit v0.12 From 4e4854aabb4f3283972737440aa64dd221e7aeee Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Mon, 27 Mar 2017 12:40:17 +0530 Subject: Add contribution to src/CHANGES.txt --- src/CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) 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 -- cgit v0.12 From 7284dcce49a1b67799b01245a9c8d48c7cd7d0ed Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 4 Apr 2017 20:53:36 -0400 Subject: pep8 --- src/engine/SCons/Defaults.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index f1d5bca..ded9539 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -485,6 +485,7 @@ def processDefines(defs): l = [str(defs)] return l + def _defines(prefix, defs, suffix, env, c=_concat_ixes): """A wrapper around _concat_ixes that turns a list or string into a list of C preprocessor command-line definitions. @@ -492,6 +493,7 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes): return c(prefix, env.subst_path(processDefines(defs)), suffix, env) + class NullCmdGenerator(object): """This is a callable class that can be used in place of other command generators if you don't want them to do anything. @@ -510,6 +512,7 @@ class NullCmdGenerator(object): def __call__(self, target, source, env, for_signature=None): return self.cmd + class Variable_Method_Caller(object): """A class for finding a construction variable on the stack and calling one of its methods. -- cgit v0.12 From d30050a18db0ef88c5bc1baa2fd7a5dd094cc034 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 4 Apr 2017 21:48:51 -0400 Subject: py2/3 exceptions in py3 seem to have full package name --- test/Errors/InternalError.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Errors/InternalError.py b/test/Errors/InternalError.py index 8ed6da1..a709597 100644 --- a/test/Errors/InternalError.py +++ b/test/Errors/InternalError.py @@ -47,7 +47,7 @@ test.run(stdout = "scons: Reading SConscript files ...\ninternal error\n", File ".+", line \d+, in .+ File ".+SConstruct", line \d+, in .+ raise InternalError\('error inside'\) -InternalError: error inside +(SCons\.Errors\.|)InternalError: error inside """, status=2) test.pass_test() -- cgit v0.12 From 7f43e9a8008bd6c2830ee1852f238246e68c1252 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 5 Apr 2017 12:39:27 -0700 Subject: py2/3 fix escaped unicode space to work for both py2/3 --- test/MSVS/vs-10.0-scc-files.py | 4 ++-- test/MSVS/vs-11.0-scc-files.py | 4 ++-- test/MSVS/vs-14.0-scc-files.py | 4 ++-- test/MSVS/vs-7.0-scc-files.py | 4 ++-- test/MSVS/vs-7.1-scc-files.py | 4 ++-- test/MSVS/vs-8.0-scc-files.py | 4 ++-- test/MSVS/vs-9.0-scc-files.py | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/MSVS/vs-10.0-scc-files.py b/test/MSVS/vs-10.0-scc-files.py index 32dd9ef..0b8bd76 100644 --- a/test/MSVS/vs-10.0-scc-files.py +++ b/test/MSVS/vs-10.0-scc-files.py @@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcxproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSccProjectUniqueName1 = Test.vcxproj \t\tSccLocalPath1 = . diff --git a/test/MSVS/vs-11.0-scc-files.py b/test/MSVS/vs-11.0-scc-files.py index 6d12c79..a25b954 100644 --- a/test/MSVS/vs-11.0-scc-files.py +++ b/test/MSVS/vs-11.0-scc-files.py @@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcxproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSccProjectUniqueName1 = Test.vcxproj \t\tSccLocalPath1 = . diff --git a/test/MSVS/vs-14.0-scc-files.py b/test/MSVS/vs-14.0-scc-files.py index c934ac9..b6db6d5 100644 --- a/test/MSVS/vs-14.0-scc-files.py +++ b/test/MSVS/vs-14.0-scc-files.py @@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcxproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSccProjectUniqueName1 = Test.vcxproj \t\tSccLocalPath1 = . diff --git a/test/MSVS/vs-7.0-scc-files.py b/test/MSVS/vs-7.0-scc-files.py index 76b4380..8586060 100644 --- a/test/MSVS/vs-7.0-scc-files.py +++ b/test/MSVS/vs-7.0-scc-files.py @@ -71,9 +71,9 @@ env.MSVSProject(target = 'Test.vcproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSolutionUniqueID = {SLNGUID} \t\tSccProjectUniqueName1 = Test.vcproj diff --git a/test/MSVS/vs-7.1-scc-files.py b/test/MSVS/vs-7.1-scc-files.py index 219bd0a..8404422 100644 --- a/test/MSVS/vs-7.1-scc-files.py +++ b/test/MSVS/vs-7.1-scc-files.py @@ -71,9 +71,9 @@ env.MSVSProject(target = 'Test.vcproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSolutionUniqueID = {SLNGUID} \t\tSccProjectUniqueName1 = Test.vcproj diff --git a/test/MSVS/vs-8.0-scc-files.py b/test/MSVS/vs-8.0-scc-files.py index 1baa407..05a8a5f 100644 --- a/test/MSVS/vs-8.0-scc-files.py +++ b/test/MSVS/vs-8.0-scc-files.py @@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSccProjectUniqueName1 = Test.vcproj \t\tSccLocalPath1 = . diff --git a/test/MSVS/vs-9.0-scc-files.py b/test/MSVS/vs-9.0-scc-files.py index e3d37c0..c270010 100644 --- a/test/MSVS/vs-9.0-scc-files.py +++ b/test/MSVS/vs-9.0-scc-files.py @@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcproj', expected_sln_sccinfo = """\ \tGlobalSection(SourceCodeControl) = preSolution \t\tSccNumberOfProjects = 2 -\t\tSccProjectName0 = Perforce\u0020Project +\t\tSccProjectName0 = Perforce\\u0020Project \t\tSccLocalPath0 = . -\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM +\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM \t\tCanCheckoutShared = true \t\tSccProjectUniqueName1 = Test.vcproj \t\tSccLocalPath1 = . -- cgit v0.12 From d7cc098cde8306ddb8ec017ce3bbb24c7aa64e8d Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 5 Apr 2017 14:35:33 -0700 Subject: remove duplicate definitions for to_bytes and to_str --- QMTest/TestCmd.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py index 2c0c0d3..07a3905 100644 --- a/QMTest/TestCmd.py +++ b/QMTest/TestCmd.py @@ -737,16 +737,6 @@ class Popen(subprocess.Popen): setattr(self, which, None) - def to_bytes (s): - if isinstance (s, bytes) or bytes is str: - return s - return bytes (s, 'utf-8') - - def to_str (s): - if bytes is str or is_String(s): - return s - return str (s, 'utf-8') - if sys.platform == 'win32':# and subprocess.mswindows: def send(self, input): input = to_bytes(input) -- cgit v0.12 From 1e58c30fd679aca066f330df7d06aa8a4b5e4a1a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 5 Apr 2017 15:26:35 -0700 Subject: py2/3 bytes/string issues. Added wrapper to re.sub to force items to bytes --- QMTest/TestSCons.py | 44 +++++++++++++++++++++++++++----------------- test/TEX/auxiliaries.py | 4 ++-- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py index b6366a6..5a9d21f 100644 --- a/QMTest/TestSCons.py +++ b/QMTest/TestSCons.py @@ -598,23 +598,33 @@ class TestSCons(TestCommon): return s + @staticmethod + def to_bytes_re_sub(pattern, repl, str, count=0, flags=0): + """ + Wrapper around re.sub to change pattern and repl to bytes to work with + both python 2 & 3 + """ + pattern = to_bytes(pattern) + repl = to_bytes(repl) + return re.sub(pattern, repl, str, count, flags) + def normalize_pdf(self, s): - s = re.sub(r'/(Creation|Mod)Date \(D:[^)]*\)', - r'/\1Date (D:XXXX)', s) - s = re.sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]', - r'/ID [ ]', s) - s = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}', - r'/\1 /XXXXXX', s) - s = re.sub(r'/Length \d+ *\n/Filter /FlateDecode\n', - r'/Length XXXX\n/Filter /FlateDecode\n', s) + s = self.to_bytes_re_sub(r'/(Creation|Mod)Date \(D:[^)]*\)', + r'/\1Date (D:XXXX)', s) + s = self.to_bytes_re_sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]', + r'/ID [ ]', s) + s = self.to_bytes_re_sub(r'/(BaseFont|FontName) /[A-Z]{6}', + r'/\1 /XXXXXX', s) + s = self.to_bytes_re_sub(r'/Length \d+ *\n/Filter /FlateDecode\n', + r'/Length XXXX\n/Filter /FlateDecode\n', s) try: import zlib except ImportError: pass else: - begin_marker = '/FlateDecode\n>>\nstream\n' - end_marker = 'endstream\nendobj' + begin_marker = to_bytes('/FlateDecode\n>>\nstream\n') + end_marker = to_bytes('endstream\nendobj') encoded = [] b = s.find(begin_marker, 0) @@ -629,16 +639,16 @@ class TestSCons(TestCommon): for b, e in encoded: r.append(s[x:b]) d = zlib.decompress(s[b:e]) - d = re.sub(r'%%CreationDate: [^\n]*\n', - r'%%CreationDate: 1970 Jan 01 00:00:00\n', d) - d = re.sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d', - r'%DVIPSSource: TeX output 1970.01.01:0000', d) - d = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}', - r'/\1 /XXXXXX', d) + d = self.to_bytes_re_sub(r'%%CreationDate: [^\n]*\n', + r'%%CreationDate: 1970 Jan 01 00:00:00\n', d) + d = self.to_bytes_re_sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d', + r'%DVIPSSource: TeX output 1970.01.01:0000', d) + d = self.to_bytes_re_sub(r'/(BaseFont|FontName) /[A-Z]{6}', + r'/\1 /XXXXXX', d) r.append(d) x = e r.append(s[x:]) - s = ''.join(r) + s = to_bytes('').join(r) return s diff --git a/test/TEX/auxiliaries.py b/test/TEX/auxiliaries.py index 98cbf41..8d220c5 100644 --- a/test/TEX/auxiliaries.py +++ b/test/TEX/auxiliaries.py @@ -120,7 +120,7 @@ test.write(['docs', 'test.tex'], tex_input) test.run(stderr=None) pdf_output_1 = test.read(['build', 'docs', 'test.pdf']) -ps_output_1 = test.read(['build', 'docs', 'test.ps']) +ps_output_1 = test.read(['build', 'docs', 'test.ps'], mode='r') # Adding blank lines will cause SCons to re-run the builds, but the # actual contents of the output files should be the same modulo @@ -130,7 +130,7 @@ test.write(['docs', 'test.tex'], tex_input + "\n\n\n") test.run(stderr=None) pdf_output_2 = test.read(['build', 'docs', 'test.pdf']) -ps_output_2 = test.read(['build', 'docs', 'test.ps']) +ps_output_2 = test.read(['build', 'docs', 'test.ps'], mode='r') -- cgit v0.12 From f03149b32d1bb216bdfcc5352102982eed19f6e0 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 5 Apr 2017 20:12:54 -0700 Subject: py2/3 Remove pdf from list of files to scan. This was causing errors as the binary files can't be regexed with strings on py3. A more complete solution may be called for as it likely doesn't make sense to try to scan: '.png', '.jpg', '.gif', '.tif' files either. --- src/engine/SCons/Scanner/LaTeX.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py index 0c54bf3..e5abb0c 100644 --- a/src/engine/SCons/Scanner/LaTeX.py +++ b/src/engine/SCons/Scanner/LaTeX.py @@ -37,7 +37,9 @@ import SCons.Util # list of graphics file extensions for TeX and LaTeX TexGraphics = ['.eps', '.ps'] -LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] +#LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] +LatexGraphics = [ '.png', '.jpg', '.gif', '.tif'] + # Used as a return value of modify_env_var if the variable is not set. class _Null(object): @@ -397,6 +399,7 @@ class LaTeX(SCons.Scanner.Base): include = queue.pop() inc_type, inc_subdir, inc_filename = include + try: if seen[inc_filename] == 1: continue -- cgit v0.12 From 1ae09a28744a7e3059576ddc732cd81902d41594 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 07:57:41 -0700 Subject: handle gettext.py rename to gettext_tool.py for bootstrap.py --- src/engine/MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in index af91b7c..c70466d 100644 --- a/src/engine/MANIFEST.in +++ b/src/engine/MANIFEST.in @@ -170,7 +170,7 @@ SCons/Variables/PackageVariable.py SCons/Variables/PathVariable.py SCons/Warnings.py SCons/Tool/GettextCommon.py -SCons/Tool/gettext.py +SCons/Tool/gettext_tool.py SCons/Tool/msgfmt.py SCons/Tool/msginit.py SCons/Tool/msgmerge.py -- cgit v0.12 From a890bcba24887fa0519be96dfcab6476c1c3205d Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 09:33:33 -0700 Subject: pep8 --- src/engine/SCons/Tool/GettextCommon.py | 650 ++++++++++++++++++--------------- 1 file changed, 353 insertions(+), 297 deletions(-) diff --git a/src/engine/SCons/Tool/GettextCommon.py b/src/engine/SCons/Tool/GettextCommon.py index e23a2d7..3b840a6 100644 --- a/src/engine/SCons/Tool/GettextCommon.py +++ b/src/engine/SCons/Tool/GettextCommon.py @@ -29,15 +29,32 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Warnings import re + ############################################################################# class XgettextToolWarning(SCons.Warnings.Warning): pass + + class XgettextNotFound(XgettextToolWarning): pass + + class MsginitToolWarning(SCons.Warnings.Warning): pass + + class MsginitNotFound(MsginitToolWarning): pass + + class MsgmergeToolWarning(SCons.Warnings.Warning): pass + + class MsgmergeNotFound(MsgmergeToolWarning): pass + + class MsgfmtToolWarning(SCons.Warnings.Warning): pass + + class MsgfmtNotFound(MsgfmtToolWarning): pass + + ############################################################################# SCons.Warnings.enableWarningClass(XgettextToolWarning) SCons.Warnings.enableWarningClass(XgettextNotFound) @@ -47,367 +64,406 @@ SCons.Warnings.enableWarningClass(MsgmergeToolWarning) SCons.Warnings.enableWarningClass(MsgmergeNotFound) SCons.Warnings.enableWarningClass(MsgfmtToolWarning) SCons.Warnings.enableWarningClass(MsgfmtNotFound) + + ############################################################################# ############################################################################# class _POTargetFactory(object): - """ A factory of `PO` target files. - - Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious` - (this is required by builders and actions gettext) and `noclean` flags by - default for all produced nodes. - """ - def __init__( self, env, nodefault = True, alias = None, precious = True - , noclean = True ): - """ Object constructor. - - **Arguments** - - - *env* (`SCons.Environment.Environment`) - - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored - from default target `'.'` - - *alias* (`string`) - if provided, produced nodes will be automatically - added to this alias, and alias will be set as `AlwaysBuild` - - *precious* (`boolean`) - if `True`, the produced nodes will be set as - `Precious`. - - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded - from `Clean`. + """ A factory of `PO` target files. + + Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious` + (this is required by builders and actions gettext) and `noclean` flags by + default for all produced nodes. """ - self.env = env - self.alias = alias - self.precious = precious - self.noclean = noclean - self.nodefault = nodefault - - def _create_node(self, name, factory, directory = None, create = 1): - """ Create node, and set it up to factory settings. """ - import SCons.Util - node = factory(name, directory, create) - node.set_noclean(self.noclean) - node.set_precious(self.precious) - if self.nodefault: - self.env.Ignore('.', node) - if self.alias: - self.env.AlwaysBuild(self.env.Alias(self.alias, node)) - return node - - def Entry(self, name, directory = None, create = 1): - """ Create `SCons.Node.FS.Entry` """ - return self._create_node(name, self.env.fs.Entry, directory, create) - - def File(self, name, directory = None, create = 1): - """ Create `SCons.Node.FS.File` """ - return self._create_node(name, self.env.fs.File, directory, create) + + def __init__(self, env, nodefault=True, alias=None, precious=True + , noclean=True): + """ Object constructor. + + **Arguments** + + - *env* (`SCons.Environment.Environment`) + - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored + from default target `'.'` + - *alias* (`string`) - if provided, produced nodes will be automatically + added to this alias, and alias will be set as `AlwaysBuild` + - *precious* (`boolean`) - if `True`, the produced nodes will be set as + `Precious`. + - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded + from `Clean`. + """ + self.env = env + self.alias = alias + self.precious = precious + self.noclean = noclean + self.nodefault = nodefault + + def _create_node(self, name, factory, directory=None, create=1): + """ Create node, and set it up to factory settings. """ + import SCons.Util + node = factory(name, directory, create) + node.set_noclean(self.noclean) + node.set_precious(self.precious) + if self.nodefault: + self.env.Ignore('.', node) + if self.alias: + self.env.AlwaysBuild(self.env.Alias(self.alias, node)) + return node + + def Entry(self, name, directory=None, create=1): + """ Create `SCons.Node.FS.Entry` """ + return self._create_node(name, self.env.fs.Entry, directory, create) + + def File(self, name, directory=None, create=1): + """ Create `SCons.Node.FS.File` """ + return self._create_node(name, self.env.fs.File, directory, create) + + ############################################################################# ############################################################################# _re_comment = re.compile(r'(#[^\n\r]+)$', re.M) _re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M) + + ############################################################################# -def _read_linguas_from_files(env, linguas_files = None): - """ Parse `LINGUAS` file and return list of extracted languages """ - import SCons.Util - import SCons.Environment - global _re_comment - global _re_lang - if not SCons.Util.is_List(linguas_files) \ - and not SCons.Util.is_String(linguas_files) \ - and not isinstance(linguas_files, SCons.Node.FS.Base) \ - and linguas_files: - # If, linguas_files==True or such, then read 'LINGUAS' file. - linguas_files = [ 'LINGUAS' ] - if linguas_files is None: - return [] - fnodes = env.arg2nodes(linguas_files) - linguas = [] - for fnode in fnodes: - contents = _re_comment.sub("", fnode.get_text_contents()) - ls = [ l for l in _re_lang.findall(contents) if l ] - linguas.extend(ls) - return linguas +def _read_linguas_from_files(env, linguas_files=None): + """ Parse `LINGUAS` file and return list of extracted languages """ + import SCons.Util + import SCons.Environment + global _re_comment + global _re_lang + if not SCons.Util.is_List(linguas_files) \ + and not SCons.Util.is_String(linguas_files) \ + and not isinstance(linguas_files, SCons.Node.FS.Base) \ + and linguas_files: + # If, linguas_files==True or such, then read 'LINGUAS' file. + linguas_files = ['LINGUAS'] + if linguas_files is None: + return [] + fnodes = env.arg2nodes(linguas_files) + linguas = [] + for fnode in fnodes: + contents = _re_comment.sub("", fnode.get_text_contents()) + ls = [l for l in _re_lang.findall(contents) if l] + linguas.extend(ls) + return linguas + + ############################################################################# ############################################################################# from SCons.Builder import BuilderBase + + ############################################################################# class _POFileBuilder(BuilderBase): - """ `PO` file builder. - - This is multi-target single-source builder. In typical situation the source - is single `POT` file, e.g. `messages.pot`, and there are multiple `PO` - targets to be updated from this `POT`. We must run - `SCons.Builder.BuilderBase._execute()` separatelly for each target to track - dependencies separatelly for each target file. + """ `PO` file builder. - **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)` - with target being list of all targets, all targets would be rebuilt each time - one of the targets from this list is missing. This would happen, for example, - when new language `ll` enters `LINGUAS_FILE` (at this moment there is no - `ll.po` file yet). To avoid this, we override - `SCons.Builder.BuilerBase._execute()` and call it separatelly for each - target. Here we also append to the target list the languages read from - `LINGUAS_FILE`. - """ - # - #* The argument for overriding _execute(): We must use environment with - # builder overrides applied (see BuilderBase.__init__(). Here it comes for - # free. - #* The argument against using 'emitter': The emitter is called too late - # by BuilderBase._execute(). If user calls, for example: - # - # env.POUpdate(LINGUAS_FILE = 'LINGUAS') - # - # the builder throws error, because it is called with target=None, - # source=None and is trying to "generate" sources or target list first. - # If user calls - # - # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS') - # - # the env.BuilderWrapper() calls our builder with target=None, - # source=['foo', 'baz']. The BuilderBase._execute() then splits execution - # and execute iterativelly (recursion) self._execute(None, source[i]). - # After that it calls emitter (which is quite too late). The emitter is - # also called in each iteration, what makes things yet worse. - def __init__(self, env, **kw): - if not 'suffix' in kw: - kw['suffix'] = '$POSUFFIX' - if not 'src_suffix' in kw: - kw['src_suffix'] = '$POTSUFFIX' - if not 'src_builder' in kw: - kw['src_builder'] = '_POTUpdateBuilder' - if not 'single_source' in kw: - kw['single_source'] = True - alias = None - if 'target_alias' in kw: - alias = kw['target_alias'] - del kw['target_alias'] - if not 'target_factory' in kw: - kw['target_factory'] = _POTargetFactory(env, alias=alias).File - BuilderBase.__init__(self, **kw) - - def _execute(self, env, target, source, *args, **kw): - """ Execute builder's actions. + This is multi-target single-source builder. In typical situation the source + is single `POT` file, e.g. `messages.pot`, and there are multiple `PO` + targets to be updated from this `POT`. We must run + `SCons.Builder.BuilderBase._execute()` separatelly for each target to track + dependencies separatelly for each target file. - Here we append to `target` the languages read from `$LINGUAS_FILE` and - apply `SCons.Builder.BuilderBase._execute()` separatelly to each target. - The arguments and return value are same as for - `SCons.Builder.BuilderBase._execute()`. + **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)` + with target being list of all targets, all targets would be rebuilt each time + one of the targets from this list is missing. This would happen, for example, + when new language `ll` enters `LINGUAS_FILE` (at this moment there is no + `ll.po` file yet). To avoid this, we override + `SCons.Builder.BuilerBase._execute()` and call it separatelly for each + target. Here we also append to the target list the languages read from + `LINGUAS_FILE`. """ - import SCons.Util - import SCons.Node - linguas_files = None - if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']: - linguas_files = env['LINGUAS_FILE'] - # This prevents endless recursion loop (we'll be invoked once for - # each target appended here, we must not extend the list again). - env['LINGUAS_FILE'] = None - linguas = _read_linguas_from_files(env,linguas_files) - if SCons.Util.is_List(target): - target.extend(linguas) - elif target is not None: - target = [target] + linguas - else: - target = linguas - if not target: - # Let the SCons.BuilderBase to handle this patologic situation - return BuilderBase._execute( self, env, target, source, *args, **kw) - # The rest is ours - if not SCons.Util.is_List(target): - target = [ target ] - result = [] - for tgt in target: - r = BuilderBase._execute( self, env, [tgt], source, *args, **kw) - result.extend(r) - if linguas_files is not None: - env['LINGUAS_FILE'] = linguas_files - return SCons.Node.NodeList(result) + + # + # * The argument for overriding _execute(): We must use environment with + # builder overrides applied (see BuilderBase.__init__(). Here it comes for + # free. + # * The argument against using 'emitter': The emitter is called too late + # by BuilderBase._execute(). If user calls, for example: + # + # env.POUpdate(LINGUAS_FILE = 'LINGUAS') + # + # the builder throws error, because it is called with target=None, + # source=None and is trying to "generate" sources or target list first. + # If user calls + # + # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS') + # + # the env.BuilderWrapper() calls our builder with target=None, + # source=['foo', 'baz']. The BuilderBase._execute() then splits execution + # and execute iterativelly (recursion) self._execute(None, source[i]). + # After that it calls emitter (which is quite too late). The emitter is + # also called in each iteration, what makes things yet worse. + def __init__(self, env, **kw): + if not 'suffix' in kw: + kw['suffix'] = '$POSUFFIX' + if not 'src_suffix' in kw: + kw['src_suffix'] = '$POTSUFFIX' + if not 'src_builder' in kw: + kw['src_builder'] = '_POTUpdateBuilder' + if not 'single_source' in kw: + kw['single_source'] = True + alias = None + if 'target_alias' in kw: + alias = kw['target_alias'] + del kw['target_alias'] + if not 'target_factory' in kw: + kw['target_factory'] = _POTargetFactory(env, alias=alias).File + BuilderBase.__init__(self, **kw) + + def _execute(self, env, target, source, *args, **kw): + """ Execute builder's actions. + + Here we append to `target` the languages read from `$LINGUAS_FILE` and + apply `SCons.Builder.BuilderBase._execute()` separatelly to each target. + The arguments and return value are same as for + `SCons.Builder.BuilderBase._execute()`. + """ + import SCons.Util + import SCons.Node + linguas_files = None + if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']: + linguas_files = env['LINGUAS_FILE'] + # This prevents endless recursion loop (we'll be invoked once for + # each target appended here, we must not extend the list again). + env['LINGUAS_FILE'] = None + linguas = _read_linguas_from_files(env, linguas_files) + if SCons.Util.is_List(target): + target.extend(linguas) + elif target is not None: + target = [target] + linguas + else: + target = linguas + if not target: + # Let the SCons.BuilderBase to handle this patologic situation + return BuilderBase._execute(self, env, target, source, *args, **kw) + # The rest is ours + if not SCons.Util.is_List(target): + target = [target] + result = [] + for tgt in target: + r = BuilderBase._execute(self, env, [tgt], source, *args, **kw) + result.extend(r) + if linguas_files is not None: + env['LINGUAS_FILE'] = linguas_files + return SCons.Node.NodeList(result) + + ############################################################################# import SCons.Environment + + ############################################################################# def _translate(env, target=None, source=SCons.Environment._null, *args, **kw): - """ Function for `Translate()` pseudo-builder """ - if target is None: target = [] - pot = env.POTUpdate(None, source, *args, **kw) - po = env.POUpdate(target, pot, *args, **kw) - return po + """ Function for `Translate()` pseudo-builder """ + if target is None: target = [] + pot = env.POTUpdate(None, source, *args, **kw) + po = env.POUpdate(target, pot, *args, **kw) + return po + + ############################################################################# ############################################################################# class RPaths(object): - """ Callable object, which returns pathnames relative to SCons current - working directory. - - It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths - for nodes that are outside of current working directory (`env.fs.getcwd()`). - Here, we often have `SConscript`, `POT` and `PO` files within `po/` - directory and source files (e.g. `*.c`) outside of it. When generating `POT` - template file, references to source files are written to `POT` template, so - a translator may later quickly jump to appropriate source file and line from - its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually - interpreted by `PO` editor as paths relative to the place, where `PO` file - lives. The absolute paths would make resultant `POT` file nonportable, as - the references would be correct only on the machine, where `POT` file was - recently re-created. For such reason, we need a function, which always - returns relative paths. This is the purpose of `RPaths` callable object. - - The `__call__` method returns paths relative to current working directory, but - we assume, that *xgettext(1)* is run from the directory, where target file is - going to be created. - - Note, that this may not work for files distributed over several hosts or - across different drives on windows. We assume here, that single local - filesystem holds both source files and target `POT` templates. - - Intended use of `RPaths` - in `xgettext.py`:: - - def generate(env): - from GettextCommon import RPaths - ... - sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)' - env.Append( - ... - XGETTEXTCOM = 'XGETTEXT ... ' + sources, - ... - XgettextRPaths = RPaths(env) - ) - """ - # NOTE: This callable object returns pathnames of dirs/files relative to - # current working directory. The pathname remains relative also for entries - # that are outside of current working directory (node, that - # SCons.Node.FS.File and siblings return absolute path in such case). For - # simplicity we compute path relative to current working directory, this - # seems be enough for our purposes (don't need TARGET variable and - # SCons.Defaults.Variable_Caller stuff). + """ Callable object, which returns pathnames relative to SCons current + working directory. - def __init__(self, env): - """ Initialize `RPaths` callable object. - - **Arguments**: - - - *env* - a `SCons.Environment.Environment` object, defines *current - working dir*. + It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths + for nodes that are outside of current working directory (`env.fs.getcwd()`). + Here, we often have `SConscript`, `POT` and `PO` files within `po/` + directory and source files (e.g. `*.c`) outside of it. When generating `POT` + template file, references to source files are written to `POT` template, so + a translator may later quickly jump to appropriate source file and line from + its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually + interpreted by `PO` editor as paths relative to the place, where `PO` file + lives. The absolute paths would make resultant `POT` file nonportable, as + the references would be correct only on the machine, where `POT` file was + recently re-created. For such reason, we need a function, which always + returns relative paths. This is the purpose of `RPaths` callable object. + + The `__call__` method returns paths relative to current working directory, but + we assume, that *xgettext(1)* is run from the directory, where target file is + going to be created. + + Note, that this may not work for files distributed over several hosts or + across different drives on windows. We assume here, that single local + filesystem holds both source files and target `POT` templates. + + Intended use of `RPaths` - in `xgettext.py`:: + + def generate(env): + from GettextCommon import RPaths + ... + sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)' + env.Append( + ... + XGETTEXTCOM = 'XGETTEXT ... ' + sources, + ... + XgettextRPaths = RPaths(env) + ) """ - self.env = env - # FIXME: I'm not sure, how it should be implemented (what the *args are in - # general, what is **kw). - def __call__(self, nodes, *args, **kw): - """ Return nodes' paths (strings) relative to current working directory. - - **Arguments**: + # NOTE: This callable object returns pathnames of dirs/files relative to + # current working directory. The pathname remains relative also for entries + # that are outside of current working directory (node, that + # SCons.Node.FS.File and siblings return absolute path in such case). For + # simplicity we compute path relative to current working directory, this + # seems be enough for our purposes (don't need TARGET variable and + # SCons.Defaults.Variable_Caller stuff). - - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes. - - *args* - currently unused. - - *kw* - currently unused. + def __init__(self, env): + """ Initialize `RPaths` callable object. + + **Arguments**: + + - *env* - a `SCons.Environment.Environment` object, defines *current + working dir*. + """ + self.env = env + + # FIXME: I'm not sure, how it should be implemented (what the *args are in + # general, what is **kw). + def __call__(self, nodes, *args, **kw): + """ Return nodes' paths (strings) relative to current working directory. + + **Arguments**: + + - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes. + - *args* - currently unused. + - *kw* - currently unused. + + **Returns**: + + - Tuple of strings, which represent paths relative to current working + directory (for given environment). + """ + import os + import SCons.Node.FS + rpaths = () + cwd = self.env.fs.getcwd().get_abspath() + for node in nodes: + rpath = None + if isinstance(node, SCons.Node.FS.Base): + rpath = os.path.relpath(node.get_abspath(), cwd) + # FIXME: Other types possible here? + if rpath is not None: + rpaths += (rpath,) + return rpaths - **Returns**: - - Tuple of strings, which represent paths relative to current working - directory (for given environment). - """ - import os - import SCons.Node.FS - rpaths = () - cwd = self.env.fs.getcwd().get_abspath() - for node in nodes: - rpath = None - if isinstance(node, SCons.Node.FS.Base): - rpath = os.path.relpath(node.get_abspath(), cwd) - # FIXME: Other types possible here? - if rpath is not None: - rpaths += (rpath,) - return rpaths ############################################################################# - + ############################################################################# def _init_po_files(target, source, env): - """ Action function for `POInit` builder. """ - nop = lambda target, source, env : 0 - if 'POAUTOINIT' in env: - autoinit = env['POAUTOINIT'] - else: - autoinit = False - # Well, if everything outside works well, this loop should do single - # iteration. Otherwise we are rebuilding all the targets even, if just - # one has changed (but is this our fault?). - for tgt in target: - if not tgt.exists(): - if autoinit: - action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR') - else: - msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \ - + 'If you are a translator, you can create it through: \n' \ - + '$MSGINITCOM' - action = SCons.Action.Action(nop, msg) - status = action([tgt], source, env) - if status: return status - return 0 + """ Action function for `POInit` builder. """ + nop = lambda target, source, env: 0 + if 'POAUTOINIT' in env: + autoinit = env['POAUTOINIT'] + else: + autoinit = False + # Well, if everything outside works well, this loop should do single + # iteration. Otherwise we are rebuilding all the targets even, if just + # one has changed (but is this our fault?). + for tgt in target: + if not tgt.exists(): + if autoinit: + action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR') + else: + msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \ + + 'If you are a translator, you can create it through: \n' \ + + '$MSGINITCOM' + action = SCons.Action.Action(nop, msg) + status = action([tgt], source, env) + if status: return status + return 0 + + ############################################################################# ############################################################################# def _detect_xgettext(env): - """ Detects *xgettext(1)* binary """ - if 'XGETTEXT' in env: - return env['XGETTEXT'] - xgettext = env.Detect('xgettext'); - if xgettext: - return xgettext - raise SCons.Errors.StopError(XgettextNotFound,"Could not detect xgettext") - return None + """ Detects *xgettext(1)* binary """ + if 'XGETTEXT' in env: + return env['XGETTEXT'] + xgettext = env.Detect('xgettext'); + if xgettext: + return xgettext + raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext") + return None + + ############################################################################# def _xgettext_exists(env): - return _detect_xgettext(env) + return _detect_xgettext(env) + + ############################################################################# ############################################################################# def _detect_msginit(env): - """ Detects *msginit(1)* program. """ - if 'MSGINIT' in env: - return env['MSGINIT'] - msginit = env.Detect('msginit'); - if msginit: - return msginit - raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit") - return None + """ Detects *msginit(1)* program. """ + if 'MSGINIT' in env: + return env['MSGINIT'] + msginit = env.Detect('msginit'); + if msginit: + return msginit + raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit") + return None + + ############################################################################# def _msginit_exists(env): - return _detect_msginit(env) + return _detect_msginit(env) + + ############################################################################# ############################################################################# def _detect_msgmerge(env): - """ Detects *msgmerge(1)* program. """ - if 'MSGMERGE' in env: - return env['MSGMERGE'] - msgmerge = env.Detect('msgmerge'); - if msgmerge: - return msgmerge - raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge") - return None + """ Detects *msgmerge(1)* program. """ + if 'MSGMERGE' in env: + return env['MSGMERGE'] + msgmerge = env.Detect('msgmerge'); + if msgmerge: + return msgmerge + raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge") + return None + + ############################################################################# def _msgmerge_exists(env): - return _detect_msgmerge(env) + return _detect_msgmerge(env) + + ############################################################################# ############################################################################# def _detect_msgfmt(env): - """ Detects *msgmfmt(1)* program. """ - if 'MSGFMT' in env: - return env['MSGFMT'] - msgfmt = env.Detect('msgfmt'); - if msgfmt: - return msgfmt - raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt") - return None + """ Detects *msgmfmt(1)* program. """ + if 'MSGFMT' in env: + return env['MSGFMT'] + msgfmt = env.Detect('msgfmt'); + if msgfmt: + return msgfmt + raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt") + return None + + ############################################################################# def _msgfmt_exists(env): - return _detect_msgfmt(env) + return _detect_msgfmt(env) + + ############################################################################# ############################################################################# def tool_list(platform, env): - """ List tools that shall be generated by top-level `gettext` tool """ - return [ 'xgettext', 'msginit', 'msgmerge', 'msgfmt' ] -############################################################################# + """ List tools that shall be generated by top-level `gettext` tool """ + return ['xgettext', 'msginit', 'msgmerge', 'msgfmt'] +############################################################################# -- cgit v0.12 From ab8f8b9186dbc9dc14580b00789a7c2aea0f1df9 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 09:33:54 -0700 Subject: pep8 --- src/engine/SCons/Tool/xgettext.py | 544 ++++++++++++++++++++------------------ 1 file changed, 283 insertions(+), 261 deletions(-) diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py index e9b49b7..2c0ce40 100644 --- a/src/engine/SCons/Tool/xgettext.py +++ b/src/engine/SCons/Tool/xgettext.py @@ -26,311 +26,333 @@ Tool specific initialization of `xgettext` tool. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + ############################################################################# class _CmdRunner(object): - """ Callabe object, which runs shell command storing its stdout and stderr to - variables. It also provides `strfunction()` method, which shall be used by - scons Action objects to print command string. """ - - def __init__(self, command, commandstr = None): - self.out = None - self.err = None - self.status = None - self.command = command - self.commandstr = commandstr - - def __call__(self, target, source, env): - import SCons.Action - import subprocess - import os - import sys - kw = { - 'stdin' : 'devnull', - 'stdout' : subprocess.PIPE, - 'stderr' : subprocess.PIPE, - 'universal_newlines' : True, - 'shell' : True - } - command = env.subst(self.command, target = target, source = source) - proc = SCons.Action._subproc(env, command, **kw) - self.out, self.err = proc.communicate() - self.status = proc.wait() - if self.err: - sys.stderr.write(unicode(self.err)) - return self.status - - def strfunction(self, target, source, env): - import os - comstr = self.commandstr - if env.subst(comstr, target = target, source = source) == "": - comstr = self.command - s = env.subst(comstr, target = target, source = source) - return s + """ Callable object, which runs shell command storing its stdout and stderr to + variables. It also provides `strfunction()` method, which shall be used by + scons Action objects to print command string. """ + + def __init__(self, command, commandstr=None): + self.out = None + self.err = None + self.status = None + self.command = command + self.commandstr = commandstr + + def __call__(self, target, source, env): + import SCons.Action + import subprocess + import os + import sys + kw = { + 'stdin': 'devnull', + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + 'universal_newlines': True, + 'shell': True + } + command = env.subst(self.command, target=target, source=source) + proc = SCons.Action._subproc(env, command, **kw) + self.out, self.err = proc.communicate() + self.status = proc.wait() + if self.err: + sys.stderr.write(unicode(self.err)) + return self.status + + def strfunction(self, target, source, env): + import os + comstr = self.commandstr + if env.subst(comstr, target=target, source=source) == "": + comstr = self.command + s = env.subst(comstr, target=target, source=source) + return s + + ############################################################################# ############################################################################# def _update_pot_file(target, source, env): - """ Action function for `POTUpdate` builder """ - import re - import os - import SCons.Action - nop = lambda target, source, env : 0 - - # Save scons cwd and os cwd (NOTE: they may be different. After the job, we - # revert each one to its original state). - save_cwd = env.fs.getcwd() - save_os_cwd = os.getcwd() - chdir = target[0].dir - chdir_str = repr(chdir.get_abspath()) - # Print chdir message (employ SCons.Action.Action for that. It knows better - # than me how to to this correctly). - env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str)) - # Go to target's directory and do our job - env.fs.chdir(chdir, 1) # Go into target's directory - try: - cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR') - action = SCons.Action.Action(cmd, strfunction=cmd.strfunction) - status = action([ target[0] ], source, env) - except: - # Something went wrong. + """ Action function for `POTUpdate` builder """ + import re + import os + import SCons.Action + nop = lambda target, source, env: 0 + + # Save scons cwd and os cwd (NOTE: they may be different. After the job, we + # revert each one to its original state). + save_cwd = env.fs.getcwd() + save_os_cwd = os.getcwd() + chdir = target[0].dir + chdir_str = repr(chdir.get_abspath()) + # Print chdir message (employ SCons.Action.Action for that. It knows better + # than me how to to this correctly). + env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str)) + # Go to target's directory and do our job + env.fs.chdir(chdir, 1) # Go into target's directory + try: + cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR') + action = SCons.Action.Action(cmd, strfunction=cmd.strfunction) + status = action([target[0]], source, env) + except: + # Something went wrong. + env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str)) + # Revert working dirs to previous state and re-throw exception. + env.fs.chdir(save_cwd, 0) + os.chdir(save_os_cwd) + raise + # Print chdir message. env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str)) - # Revert working dirs to previous state and re-throw exception. + # Revert working dirs to previous state. env.fs.chdir(save_cwd, 0) os.chdir(save_os_cwd) - raise - # Print chdir message. - env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str)) - # Revert working dirs to previous state. - env.fs.chdir(save_cwd, 0) - os.chdir(save_os_cwd) - # If the command was not successfull, return error code. - if status: return status - - new_content = cmd.out - - if not new_content: - # When xgettext finds no internationalized messages, no *.pot is created - # (because we don't want to bother translators with empty POT files). - needs_update = False - explain = "no internationalized messages encountered" - else: - if target[0].exists(): - # If the file already exists, it's left unaltered unless its messages - # are outdated (w.r.t. to these recovered by xgettext from sources). - old_content = target[0].get_text_contents() - re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M) - old_content_nocdate = re.sub(re_cdate,"",old_content) - new_content_nocdate = re.sub(re_cdate,"",new_content) - if(old_content_nocdate == new_content_nocdate): - # Messages are up-to-date + # If the command was not successfull, return error code. + if status: return status + + new_content = cmd.out + + if not new_content: + # When xgettext finds no internationalized messages, no *.pot is created + # (because we don't want to bother translators with empty POT files). needs_update = False - explain = "messages in file found to be up-to-date" - else: - # Messages are outdated - needs_update = True - explain = "messages in file were outdated" + explain = "no internationalized messages encountered" else: - # No POT file found, create new one - needs_update = True - explain = "new file" - if needs_update: - # Print message employing SCons.Action.Action for that. - msg = "Writing " + repr(str(target[0])) + " (" + explain + ")" - env.Execute(SCons.Action.Action(nop, msg)) - f = open(str(target[0]),"w") - f.write(new_content) - f.close() - return 0 - else: - # Print message employing SCons.Action.Action for that. - msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")" - env.Execute(SCons.Action.Action(nop, msg)) - return 0 + if target[0].exists(): + # If the file already exists, it's left unaltered unless its messages + # are outdated (w.r.t. to these recovered by xgettext from sources). + old_content = target[0].get_text_contents() + re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M) + old_content_nocdate = re.sub(re_cdate, "", old_content) + new_content_nocdate = re.sub(re_cdate, "", new_content) + if (old_content_nocdate == new_content_nocdate): + # Messages are up-to-date + needs_update = False + explain = "messages in file found to be up-to-date" + else: + # Messages are outdated + needs_update = True + explain = "messages in file were outdated" + else: + # No POT file found, create new one + needs_update = True + explain = "new file" + if needs_update: + # Print message employing SCons.Action.Action for that. + msg = "Writing " + repr(str(target[0])) + " (" + explain + ")" + env.Execute(SCons.Action.Action(nop, msg)) + f = open(str(target[0]), "w") + f.write(new_content) + f.close() + return 0 + else: + # Print message employing SCons.Action.Action for that. + msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")" + env.Execute(SCons.Action.Action(nop, msg)) + return 0 + + ############################################################################# ############################################################################# from SCons.Builder import BuilderBase + + ############################################################################# class _POTBuilder(BuilderBase): - def _execute(self, env, target, source, *args): - if not target: - if 'POTDOMAIN' in env and env['POTDOMAIN']: - domain = env['POTDOMAIN'] - else: - domain = 'messages' - target = [ domain ] - return BuilderBase._execute(self, env, target, source, *args) + def _execute(self, env, target, source, *args): + if not target: + if 'POTDOMAIN' in env and env['POTDOMAIN']: + domain = env['POTDOMAIN'] + else: + domain = 'messages' + target = [domain] + return BuilderBase._execute(self, env, target, source, *args) + + ############################################################################# ############################################################################# -def _scan_xgettext_from_files(target, source, env, files = None, path = None): - """ Parses `POTFILES.in`-like file and returns list of extracted file names. - """ - import re - import SCons.Util - import SCons.Node.FS - - if files is None: +def _scan_xgettext_from_files(target, source, env, files=None, path=None): + """ Parses `POTFILES.in`-like file and returns list of extracted file names. + """ + import re + import SCons.Util + import SCons.Node.FS + + if files is None: + return 0 + if not SCons.Util.is_List(files): + files = [files] + + if path is None: + if 'XGETTEXTPATH' in env: + path = env['XGETTEXTPATH'] + else: + path = [] + if not SCons.Util.is_List(path): + path = [path] + + path = SCons.Util.flatten(path) + + dirs = () + for p in path: + if not isinstance(p, SCons.Node.FS.Base): + if SCons.Util.is_String(p): + p = env.subst(p, source=source, target=target) + p = env.arg2nodes(p, env.fs.Dir) + dirs += tuple(p) + # cwd is the default search path (when no path is defined by user) + if not dirs: + dirs = (env.fs.getcwd(),) + + # Parse 'POTFILE.in' files. + re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M) + re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M) + re_trailws = re.compile(r'[ \t\r]+$') + for f in files: + # Find files in search path $XGETTEXTPATH + if isinstance(f, SCons.Node.FS.Base) and f.rexists(): + contents = f.get_text_contents() + contents = re_comment.sub("", contents) + contents = re_emptyln.sub("", contents) + contents = re_trailws.sub("", contents) + depnames = contents.splitlines() + for depname in depnames: + depfile = SCons.Node.FS.find_file(depname, dirs) + if not depfile: + depfile = env.arg2nodes(depname, dirs[0].File) + env.Depends(target, depfile) return 0 - if not SCons.Util.is_List(files): - files = [ files ] - if path is None: - if 'XGETTEXTPATH' in env: - path = env['XGETTEXTPATH'] - else: - path = [] - if not SCons.Util.is_List(path): - path = [ path ] - - path = SCons.Util.flatten(path) - - dirs = () - for p in path: - if not isinstance(p, SCons.Node.FS.Base): - if SCons.Util.is_String(p): - p = env.subst(p, source = source, target = target) - p = env.arg2nodes(p, env.fs.Dir) - dirs += tuple(p) - # cwd is the default search path (when no path is defined by user) - if not dirs: - dirs = (env.fs.getcwd(),) - - # Parse 'POTFILE.in' files. - re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M) - re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M) - re_trailws = re.compile(r'[ \t\r]+$') - for f in files: - # Find files in search path $XGETTEXTPATH - if isinstance(f, SCons.Node.FS.Base) and f.rexists(): - contents = f.get_text_contents() - contents = re_comment.sub("", contents) - contents = re_emptyln.sub("", contents) - contents = re_trailws.sub("", contents) - depnames = contents.splitlines() - for depname in depnames: - depfile = SCons.Node.FS.find_file(depname, dirs) - if not depfile: - depfile = env.arg2nodes(depname, dirs[0].File) - env.Depends(target, depfile) - return 0 + ############################################################################# ############################################################################# def _pot_update_emitter(target, source, env): - """ Emitter function for `POTUpdate` builder """ - from SCons.Tool.GettextCommon import _POTargetFactory - import SCons.Util - import SCons.Node.FS - - if 'XGETTEXTFROM' in env: - xfrom = env['XGETTEXTFROM'] - else: + """ Emitter function for `POTUpdate` builder """ + from SCons.Tool.GettextCommon import _POTargetFactory + import SCons.Util + import SCons.Node.FS + + if 'XGETTEXTFROM' in env: + xfrom = env['XGETTEXTFROM'] + else: + return target, source + if not SCons.Util.is_List(xfrom): + xfrom = [xfrom] + + xfrom = SCons.Util.flatten(xfrom) + + # Prepare list of 'POTFILE.in' files. + files = [] + for xf in xfrom: + if not isinstance(xf, SCons.Node.FS.Base): + if SCons.Util.is_String(xf): + # Interpolate variables in strings + xf = env.subst(xf, source=source, target=target) + xf = env.arg2nodes(xf) + files.extend(xf) + if files: + env.Depends(target, files) + _scan_xgettext_from_files(target, source, env, files) return target, source - if not SCons.Util.is_List(xfrom): - xfrom = [ xfrom ] - - xfrom = SCons.Util.flatten(xfrom) - - # Prepare list of 'POTFILE.in' files. - files = [] - for xf in xfrom: - if not isinstance(xf, SCons.Node.FS.Base): - if SCons.Util.is_String(xf): - # Interpolate variables in strings - xf = env.subst(xf, source = source, target = target) - xf = env.arg2nodes(xf) - files.extend(xf) - if files: - env.Depends(target, files) - _scan_xgettext_from_files(target, source, env, files) - return target, source + + ############################################################################# ############################################################################# from SCons.Environment import _null + + ############################################################################# def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw): - return env._POTUpdateBuilder(target, source, **kw) + return env._POTUpdateBuilder(target, source, **kw) + + ############################################################################# ############################################################################# def _POTUpdateBuilder(env, **kw): - """ Creates `POTUpdate` builder object """ - import SCons.Action - from SCons.Tool.GettextCommon import _POTargetFactory - kw['action'] = SCons.Action.Action(_update_pot_file, None) - kw['suffix'] = '$POTSUFFIX' - kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File - kw['emitter'] = _pot_update_emitter - return _POTBuilder(**kw) + """ Creates `POTUpdate` builder object """ + import SCons.Action + from SCons.Tool.GettextCommon import _POTargetFactory + kw['action'] = SCons.Action.Action(_update_pot_file, None) + kw['suffix'] = '$POTSUFFIX' + kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File + kw['emitter'] = _pot_update_emitter + return _POTBuilder(**kw) + + ############################################################################# ############################################################################# -def generate(env,**kw): - """ Generate `xgettext` tool """ - import SCons.Util - from SCons.Tool.GettextCommon import RPaths, _detect_xgettext - - try: - env['XGETTEXT'] = _detect_xgettext(env) - except: - env['XGETTEXT'] = 'xgettext' - # NOTE: sources="$SOURCES" would work as well. However, we use following - # construction to convert absolute paths provided by scons onto paths - # relative to current working dir. Note, that scons expands $SOURCE(S) to - # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in - # "../"). With source=$SOURCE these absolute paths would be written to the - # resultant *.pot file (and its derived *.po files) as references to lines in - # source code (e.g. referring lines in *.c files). Such references would be - # correct (e.g. in poedit) only on machine on which *.pot was generated and - # would be of no use on other hosts (having a copy of source code located - # in different place in filesystem). - sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \ - + ', SOURCES)} $)' - - # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file. - # This is required by the POTUpdate builder's action. - xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \ - + ' $_XGETTEXTFROMFLAGS -o - ' + sources - - xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \ - + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)' - xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \ - + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)' - - env.SetDefault( - _XGETTEXTDOMAIN = '${TARGET.filebase}', - XGETTEXTFLAGS = [ ], - XGETTEXTCOM = xgettextcom, - XGETTEXTCOMSTR = '', - XGETTEXTPATH = [ ], - XGETTEXTPATHPREFIX = '-D', - XGETTEXTPATHSUFFIX = '', - XGETTEXTFROM = None, - XGETTEXTFROMPREFIX = '-f', - XGETTEXTFROMSUFFIX = '', - _XGETTEXTPATHFLAGS = xgettextpathflags, - _XGETTEXTFROMFLAGS = xgettextfromflags, - POTSUFFIX = ['.pot'], - POTUPDATE_ALIAS = 'pot-update', - XgettextRPaths = RPaths(env) - ) - env.Append( BUILDERS = { - '_POTUpdateBuilder' : _POTUpdateBuilder(env) - } ) - env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate') - env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS')) +def generate(env, **kw): + """ Generate `xgettext` tool """ + import SCons.Util + from SCons.Tool.GettextCommon import RPaths, _detect_xgettext + + try: + env['XGETTEXT'] = _detect_xgettext(env) + except: + env['XGETTEXT'] = 'xgettext' + # NOTE: sources="$SOURCES" would work as well. However, we use following + # construction to convert absolute paths provided by scons onto paths + # relative to current working dir. Note, that scons expands $SOURCE(S) to + # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in + # "../"). With source=$SOURCE these absolute paths would be written to the + # resultant *.pot file (and its derived *.po files) as references to lines in + # source code (e.g. referring lines in *.c files). Such references would be + # correct (e.g. in poedit) only on machine on which *.pot was generated and + # would be of no use on other hosts (having a copy of source code located + # in different place in filesystem). + sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \ + + ', SOURCES)} $)' + + # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file. + # This is required by the POTUpdate builder's action. + xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \ + + ' $_XGETTEXTFROMFLAGS -o - ' + sources + + xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \ + + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)' + xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \ + + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)' + + env.SetDefault( + _XGETTEXTDOMAIN='${TARGET.filebase}', + XGETTEXTFLAGS=[], + XGETTEXTCOM=xgettextcom, + XGETTEXTCOMSTR='', + XGETTEXTPATH=[], + XGETTEXTPATHPREFIX='-D', + XGETTEXTPATHSUFFIX='', + XGETTEXTFROM=None, + XGETTEXTFROMPREFIX='-f', + XGETTEXTFROMSUFFIX='', + _XGETTEXTPATHFLAGS=xgettextpathflags, + _XGETTEXTFROMFLAGS=xgettextfromflags, + POTSUFFIX=['.pot'], + POTUPDATE_ALIAS='pot-update', + XgettextRPaths=RPaths(env) + ) + env.Append(BUILDERS={ + '_POTUpdateBuilder': _POTUpdateBuilder(env) + }) + env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate') + env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS')) + + ############################################################################# ############################################################################# def exists(env): - """ Check, whether the tool exists """ - from SCons.Tool.GettextCommon import _xgettext_exists - try: - return _xgettext_exists(env) - except: - return False + """ Check, whether the tool exists """ + from SCons.Tool.GettextCommon import _xgettext_exists + try: + return _xgettext_exists(env) + except: + return False + ############################################################################# # Local Variables: -- cgit v0.12 From 12826a83362d0da1abd16cb29edb38be48e8f172 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 09:34:44 -0700 Subject: py2/3 Need to add __hash__ function to EntryProxy as with py3 __hash__ function is removed when a class provides __eq__ --- src/engine/SCons/Node/FS.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 33e4a2d..8f26777 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -477,6 +477,11 @@ class EntryProxy(SCons.Util.Proxy): __str__ = SCons.Util.Delegate('__str__') + # 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__ + __hash__ = SCons.Util.Delegate('__hash__') + def __get_abspath(self): entry = self.get() return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(), @@ -574,6 +579,7 @@ class EntryProxy(SCons.Util.Proxy): else: return attr_function(self) + class Base(SCons.Node.Node): """A generic class for file system entries. This class is for when we don't know yet whether the entry being looked up is a file -- cgit v0.12 From e25264ce5094f6d288cdf780bb99e4bdb605c706 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 09:35:05 -0700 Subject: py2/3 fix mode='r' --- test/gettext/POTUpdate/UserExamples.py | 40 +++++++++++++++++----------------- test/gettext/POUpdate/UserExamples.py | 36 +++++++++++++++--------------- test/gettext/Translate/UserExamples.py | 28 ++++++++++++------------ 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/test/gettext/POTUpdate/UserExamples.py b/test/gettext/POTUpdate/UserExamples.py index 6269081..06203fa 100644 --- a/test/gettext/POTUpdate/UserExamples.py +++ b/test/gettext/POTUpdate/UserExamples.py @@ -62,19 +62,19 @@ test.must_not_exist( ['ex1', 'po', 'bar.pot'] ) test.run(arguments = 'foo.pot', chdir = path.join('ex1', 'po')) test.must_exist( ['ex1', 'po', 'foo.pot'] ) test.must_not_exist( ['ex1', 'po', 'bar.pot'] ) -test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from a.cpp" ) -test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from b.cpp" ) -test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from c.cpp" ) -test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from d.cpp" ) +test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from a.cpp", mode='r') +test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from b.cpp", mode='r') +test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from c.cpp", mode='r') +test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from d.cpp", mode='r') # scons 'pot-update' creates foo.pot and bar.pot test.run(arguments = 'pot-update', chdir = path.join('ex1', 'po')) test.must_exist( ['ex1', 'po', 'foo.pot'] ) test.must_exist( ['ex1', 'po', 'bar.pot'] ) -test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from a.cpp" ) -test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from b.cpp" ) -test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from c.cpp" ) -test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from d.cpp" ) +test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from a.cpp", mode='r') +test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from b.cpp", mode='r') +test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from c.cpp", mode='r') +test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from d.cpp", mode='r') # scons -c does not clean anything test.run(arguments = '-c', chdir = path.join('ex1', 'po')) @@ -101,16 +101,16 @@ test.write(['ex2', 'd.cpp'], """ gettext("Hello from d.cpp") """) test.run(arguments = 'pot-update', chdir = path.join('ex2')) test.must_exist( ['ex2', 'foo.pot']) -test.must_contain( ['ex2', 'foo.pot'], "Hello from a.cpp" ) -test.must_contain( ['ex2', 'foo.pot'], "Hello from b.cpp" ) -test.must_not_contain( ['ex2', 'foo.pot'], "Hello from c.cpp" ) -test.must_not_contain( ['ex2', 'foo.pot'], "Hello from d.cpp" ) +test.must_contain( ['ex2', 'foo.pot'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex2', 'foo.pot'], "Hello from b.cpp", mode='r' ) +test.must_not_contain( ['ex2', 'foo.pot'], "Hello from c.cpp", mode='r' ) +test.must_not_contain( ['ex2', 'foo.pot'], "Hello from d.cpp", mode='r' ) test.must_exist( ['ex2', 'bar.pot']) -test.must_not_contain( ['ex2', 'bar.pot'], "Hello from a.cpp" ) -test.must_not_contain( ['ex2', 'bar.pot'], "Hello from b.cpp" ) -test.must_contain( ['ex2', 'bar.pot'], "Hello from c.cpp" ) -test.must_contain( ['ex2', 'bar.pot'], "Hello from d.cpp" ) +test.must_not_contain( ['ex2', 'bar.pot'], "Hello from a.cpp", mode='r' ) +test.must_not_contain( ['ex2', 'bar.pot'], "Hello from b.cpp", mode='r' ) +test.must_contain( ['ex2', 'bar.pot'], "Hello from c.cpp", mode='r' ) +test.must_contain( ['ex2', 'bar.pot'], "Hello from d.cpp", mode='r' ) ############################################################################# @@ -192,9 +192,9 @@ test.write(['ex5', '0', '1', 'a.cpp'], """ gettext("Hello from ../a.cpp") """) test.run(arguments = 'pot-update', chdir = path.join('ex5', '0', '1', 'po')) test.must_exist( ['ex5', '0', '1', 'po', 'messages.pot']) test.must_contain( ['ex5', '0', '1', 'po', 'messages.pot'], - 'Hello from ../a.cpp' ) + 'Hello from ../a.cpp', mode='r' ) test.must_not_contain( ['ex5', '0', '1', 'po', 'messages.pot'], - 'Hello from ../../a.cpp' ) + 'Hello from ../../a.cpp', mode='r' ) test.write(['ex5', '0', '1', 'po', 'SConstruct'], """ @@ -204,9 +204,9 @@ env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH=['../../', '../']) """) test.run(arguments = 'pot-update', chdir = path.join('ex5', '0', '1', 'po')) test.must_contain( ['ex5', '0', '1', 'po', 'messages.pot'], - 'Hello from ../../a.cpp' ) + 'Hello from ../../a.cpp', mode='r' ) test.must_not_contain( ['ex5', '0', '1', 'po', 'messages.pot'], - 'Hello from ../a.cpp') + 'Hello from ../a.cpp', mode='r') test.pass_test() diff --git a/test/gettext/POUpdate/UserExamples.py b/test/gettext/POUpdate/UserExamples.py index 01d3706..5f3e6c7 100644 --- a/test/gettext/POUpdate/UserExamples.py +++ b/test/gettext/POUpdate/UserExamples.py @@ -182,8 +182,8 @@ test.write(['ex1', 'pl.po'], pl_po_contents) test.run(arguments = 'po-update', chdir = 'ex1', stderr = None) test.must_exist( ['ex1', 'en.po'] ) test.must_exist( ['ex1', 'pl.po'] ) -test.must_contain( ['ex1', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex1', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex1', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex1', 'pl.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 2 @@ -205,8 +205,8 @@ test.write(['ex2', 'pl.po'], pl_po_contents) test.run(arguments = 'po-update', chdir = 'ex2', stderr = None) test.must_exist( ['ex2', 'en.po'] ) test.must_exist( ['ex2', 'pl.po'] ) -test.must_contain( ['ex2', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex2', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex2', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex2', 'pl.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 3 @@ -228,8 +228,8 @@ test.write(['ex3', 'pl.po'], pl_po_contents) test.run(arguments = 'po-update', chdir = 'ex3', stderr = None) test.must_exist( ['ex3', 'en.po'] ) test.must_exist( ['ex3', 'pl.po'] ) -test.must_contain( ['ex3', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex3', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex3', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex3', 'pl.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 4 @@ -258,8 +258,8 @@ test.run(arguments = 'po-update', chdir = 'ex4', stderr = None) test.must_exist( ['ex4', 'messages.pot'] ) test.must_exist( ['ex4', 'en.po'] ) test.must_exist( ['ex4', 'pl.po'] ) -test.must_contain( ['ex4', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex4', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex4', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex4', 'pl.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 5 @@ -286,8 +286,8 @@ test.write(['ex5', 'pl.po'], pl_po_contents) test.run(arguments = 'po-update', chdir= 'ex5', stderr = None) test.must_exist( ['ex5', 'en.po'] ) test.must_exist( ['ex5', 'pl.po'] ) -test.must_contain( ['ex5', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex5', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex5', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex5', 'pl.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 6 @@ -317,10 +317,10 @@ test.must_exist( ['ex6', 'en.po'] ) test.must_exist( ['ex6', 'pl.po'] ) test.must_exist( ['ex6', 'de.po'] ) test.must_exist( ['ex6', 'fr.po'] ) -test.must_contain( ['ex6', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex6', 'pl.po'], "Hello from a.cpp" ) -test.must_contain( ['ex6', 'de.po'], "Hello from a.cpp" ) -test.must_contain( ['ex6', 'fr.po'], "Hello from a.cpp" ) +test.must_contain( ['ex6', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex6', 'pl.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex6', 'de.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex6', 'fr.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 7 @@ -351,8 +351,8 @@ test.write(['ex7', 'messages.pot'], pot_contents) test.run(arguments = 'po-update', chdir= 'ex7', stderr = None) test.must_exist( ['ex7', 'en.po'] ) test.must_exist( ['ex7', 'pl.po'] ) -test.must_contain( ['ex7', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex7', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex7', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex7', 'pl.po'], "Hello from a.cpp", mode='r' ) ############################################################################# # POUpdate: Example 8 @@ -389,8 +389,8 @@ test.run(arguments = 'po-update', chdir = 'ex8', stderr = None) test.must_exist( ['ex8', 'foo.pot'] ) test.must_exist( ['ex8', 'en.po'] ) test.must_exist( ['ex8', 'pl.po'] ) -test.must_contain( ['ex8', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex8', 'pl.po'], "Hello from a.cpp" ) +test.must_contain( ['ex8', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex8', 'pl.po'], "Hello from a.cpp", mode='r' ) test.pass_test() diff --git a/test/gettext/Translate/UserExamples.py b/test/gettext/Translate/UserExamples.py index 384b96d..d7220a3 100644 --- a/test/gettext/Translate/UserExamples.py +++ b/test/gettext/Translate/UserExamples.py @@ -65,10 +65,10 @@ test.write(['ex1', 'b.cpp'], """ gettext("Hello from b.cpp") """) test.run(arguments = 'po-update', chdir = path.join('ex1','po'), stderr = None) test.must_exist( ['ex1', 'po', 'en.po'] ) test.must_exist( ['ex1', 'po', 'pl.po'] ) -test.must_contain( ['ex1', 'po', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex1', 'po', 'en.po'], "Hello from b.cpp" ) -test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from a.cpp" ) -test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from b.cpp" ) +test.must_contain( ['ex1', 'po', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex1', 'po', 'en.po'], "Hello from b.cpp", mode='r' ) +test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from b.cpp", mode='r' ) ############################################################################# # Translate: Example 2 @@ -100,10 +100,10 @@ test.write(['ex2', 'b.cpp'], """ gettext("Hello from b.cpp") """) test.run(arguments = 'po-update', chdir = path.join('ex2','po'), stderr = None) test.must_exist( ['ex2', 'po', 'en.po'] ) test.must_exist( ['ex2', 'po', 'pl.po'] ) -test.must_contain( ['ex2', 'po', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex2', 'po', 'en.po'], "Hello from b.cpp" ) -test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from a.cpp" ) -test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from b.cpp" ) +test.must_contain( ['ex2', 'po', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex2', 'po', 'en.po'], "Hello from b.cpp", mode='r' ) +test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from b.cpp", mode='r' ) ############################################################################# # Translate: Example 3 @@ -157,12 +157,12 @@ test.must_not_exist( ['ex3', 'build', 'po', 'messages.pot'] ) test.must_not_exist( ['ex3', 'build', 'po', 'en.po'] ) test.must_not_exist( ['ex3', 'build', 'po', 'pl.po'] ) # -test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from a.cpp" ) -test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from b.cpp" ) -test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from a.cpp" ) -test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from b.cpp" ) -test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from a.cpp" ) -test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from b.cpp" ) +test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from b.cpp", mode='r' ) +test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from b.cpp", mode='r' ) +test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from a.cpp", mode='r' ) +test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from b.cpp", mode='r' ) test.run(arguments = '.', chdir = 'ex3', stderr = None) test.must_exist( ['ex3', 'build', 'po', 'en.mo'] ) -- cgit v0.12 From 8b4b7860340e1348ec00587a0c79007531e361d5 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 15:36:31 -0700 Subject: py2/3 don't try to force import threading failure on py3. threading is imported too many places and this form of checking for python being built with thread is no the best way. Use sysconfig.get_config_var('WITH_THREAD') instead --- test/option-j.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/option-j.py b/test/option-j.py index 3dbedc0..278fd30 100644 --- a/test/option-j.py +++ b/test/option-j.py @@ -122,7 +122,7 @@ test.fail_test(start2 < finish1) # succeeds. test.run(arguments='-j 2 out') -if sys.platform != 'win32': +if sys.platform != 'win32' and sys.version_info[0] == 2: # Test breaks on win32 when using real subprocess is not the only # package to import threading # -- cgit v0.12 From 9b49fabea61340c856b18151224603e3162c84d3 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 16:13:36 -0700 Subject: py2/3 fix test logic to handle bytes vs strings when matching --- QMTest/TestCmd.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py index 07a3905..3b745f8 100644 --- a/QMTest/TestCmd.py +++ b/QMTest/TestCmd.py @@ -453,13 +453,17 @@ def pass_test(self = None, condition = 1, function = None): sys.exit(0) -def match_exact(lines = None, matches = None): +def match_exact(lines = None, matches = None, newline = '\n'): """ """ + + if isinstance(lines, bytes) or bytes is str: + newline = to_bytes('\n') + if not is_List(lines): - lines = lines.split("\n") + lines = lines.split(newline) if not is_List(matches): - matches = matches.split("\n") + matches = matches.split(newline) if len(lines) != len(matches): return for i in range(len(lines)): -- cgit v0.12 From 2361be4acf8e9d2ac91a63ea3ba36a03527a726e Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 16:15:21 -0700 Subject: py2/3 swap to bytes for comparison --- test/Progress/spinner.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Progress/spinner.py b/test/Progress/spinner.py index 85ca32f..59c0a89 100644 --- a/test/Progress/spinner.py +++ b/test/Progress/spinner.py @@ -33,6 +33,7 @@ import os import TestSCons + test = TestSCons.TestSCons(universal_newlines=None) test.write('SConstruct', r""" @@ -50,12 +51,12 @@ test.write('S2.in', "S2.in\n") test.write('S3.in', "S3.in\n") test.write('S4.in', "S4.in\n") -expect = """\ +expect = bytearray("""\ \\\r|\rCopy("S1.out", "S1.in") /\r-\rCopy("S2.out", "S2.in") \\\r|\rCopy("S3.out", "S3.in") /\r-\rCopy("S4.out", "S4.in") -\\\r|\r""" +\\\r|\r""",'utf-8') if os.linesep != '\n': expect = expect.replace('\n', os.linesep) -- cgit v0.12 From 072369e0cf1c10f5b88ebd21487f169eb189cf25 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 16:15:36 -0700 Subject: py2/3 swap to bytes for comparison --- test/Progress/TARGET.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Progress/TARGET.py b/test/Progress/TARGET.py index d7ff3c9..9af5565 100644 --- a/test/Progress/TARGET.py +++ b/test/Progress/TARGET.py @@ -50,12 +50,12 @@ test.write('S2.in', "S2.in\n") test.write('S3.in', "S3.in\n") test.write('S4.in', "S4.in\n") -expect = """\ +expect = bytearray("""\ S1.in\r \rS1.out\rCopy("S1.out", "S1.in") \rS2.in\r \rS2.out\rCopy("S2.out", "S2.in") \rS3.in\r \rS3.out\rCopy("S3.out", "S3.in") \rS4.in\r \rS4.out\rCopy("S4.out", "S4.in") - \rSConstruct\r \r.\r""" + \rSConstruct\r \r.\r""",'utf-8') if os.linesep != '\n': expect = expect.replace('\n', os.linesep) -- cgit v0.12 From cce4024322a5433d441a0d9058c9a1950590ae0c Mon Sep 17 00:00:00 2001 From: William Deegan Date: Thu, 6 Apr 2017 16:16:05 -0700 Subject: py2/3 use sysconfig.get_config_var('WITH_THREAD') to determine if python has threads --- src/engine/SCons/Script/Main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index f9df813..b7ce466 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -47,6 +47,7 @@ import os import sys import time import traceback +import sysconfig import SCons.CacheDir import SCons.Debug @@ -1251,12 +1252,15 @@ def _build_targets(fs, options, targets, target_top): # various print_* settings, tree_printer list, etc. BuildTask.options = options + + python_has_threads = sysconfig.get_config_var('WITH_THREAD') + # to check if python configured with threads. global num_jobs num_jobs = options.num_jobs jobs = SCons.Job.Jobs(num_jobs, taskmaster) if num_jobs > 1: msg = None - if jobs.num_jobs == 1: + if jobs.num_jobs == 1 or not python_has_threads: msg = "parallel builds are unsupported by this version of Python;\n" + \ "\tignoring -j or num_jobs option.\n" elif sys.platform == 'win32': -- cgit v0.12 From ec5cfb99fa60afc33a52bf231f16d44d1f9a0074 Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Fri, 7 Apr 2017 13:39:33 +0530 Subject: py2/3 fixes for CPPDEFINES/append.py test case --- test/CPPDEFINES/append.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/CPPDEFINES/append.py b/test/CPPDEFINES/append.py index 14ea7b3..04a2d7b 100644 --- a/test/CPPDEFINES/append.py +++ b/test/CPPDEFINES/append.py @@ -52,12 +52,28 @@ env_2300_2 = Environment(CPPDEFINES = ['foo'], CPPDEFPREFIX='-D') # note the lis env_2300_2.Append(CPPDEFINES='bar') print(env_2300_2.subst('$_CPPDEFFLAGS')) + +# Python3 dicts dont preserve order. Hence we supply subclass of OrderedDict +# whose __str__ and __repr__ act like a normal dict. +from collections import OrderedDict +class OrderedPrintingDict(OrderedDict): + def __str__(self): + return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}' + + def __repr__(self): + return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}' + + def __semi_deepcopy__(self): + # Because a dict subclass is not deep copied directly when constructing + # Environment(CPPDEFINES = OrderedPrintingDict(...)) + return self.copy() + # http://scons.tigris.org/issues/show_bug.cgi?id=1152 # http://scons.tigris.org/issues/show_bug.cgi?id=2900 cases=[('string', 'FOO'), ('list', ['NAME1', 'NAME2']), ('list-of-2lists', [('NAME1','VAL1'), ['NAME2','VAL2']]), - ('dict', {'NAME1' : 'VAL1', 'NAME2' : 'VAL2', 'NAME3' : None}) + ('dict', OrderedPrintingDict([('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')])) ] for (t1, c1) in cases: @@ -180,7 +196,7 @@ AppendUnique: ==== Testing CPPDEFINES, appending a string to a dict orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = FOO Append: - result={'FOO': None, 'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'} + result={'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1', 'FOO': None} final=-DFOO -DNAME1=VAL1 -DNAME2=VAL2 -DNAME3 AppendUnique: result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1'), 'FOO'] -- cgit v0.12 From 16891265ea2e81e03b8bb3d6e30bbc2a2a642ebe Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Fri, 7 Apr 2017 13:52:06 +0530 Subject: Make __str__ and __repr__ same --- test/CPPDEFINES/append.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/CPPDEFINES/append.py b/test/CPPDEFINES/append.py index 04a2d7b..7973f22 100644 --- a/test/CPPDEFINES/append.py +++ b/test/CPPDEFINES/append.py @@ -52,24 +52,22 @@ env_2300_2 = Environment(CPPDEFINES = ['foo'], CPPDEFPREFIX='-D') # note the lis env_2300_2.Append(CPPDEFINES='bar') print(env_2300_2.subst('$_CPPDEFFLAGS')) - +# http://scons.tigris.org/issues/show_bug.cgi?id=1152 +# http://scons.tigris.org/issues/show_bug.cgi?id=2900 # Python3 dicts dont preserve order. Hence we supply subclass of OrderedDict # whose __str__ and __repr__ act like a normal dict. from collections import OrderedDict class OrderedPrintingDict(OrderedDict): - def __str__(self): - return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}' - def __repr__(self): return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}' + __str__ = __repr__ + + # Because dict-like objects (except dict and UserDict) are not deep copied + # directly when constructing Environment(CPPDEFINES = OrderedPrintingDict(...)) def __semi_deepcopy__(self): - # Because a dict subclass is not deep copied directly when constructing - # Environment(CPPDEFINES = OrderedPrintingDict(...)) return self.copy() -# http://scons.tigris.org/issues/show_bug.cgi?id=1152 -# http://scons.tigris.org/issues/show_bug.cgi?id=2900 cases=[('string', 'FOO'), ('list', ['NAME1', 'NAME2']), ('list-of-2lists', [('NAME1','VAL1'), ['NAME2','VAL2']]), -- cgit v0.12 From 8e6b5fc8645b39234367d95590fabf91329c248f Mon Sep 17 00:00:00 2001 From: William Deegan Date: Fri, 7 Apr 2017 09:20:41 -0700 Subject: fix breaking windows check for functional parallel builds --- src/engine/SCons/Script/Main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index b7ce466..c810634 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -1260,11 +1260,11 @@ def _build_targets(fs, options, targets, target_top): jobs = SCons.Job.Jobs(num_jobs, taskmaster) if num_jobs > 1: msg = None - if jobs.num_jobs == 1 or not python_has_threads: + if sys.platform == 'win32': + msg = fetch_win32_parallel_msg() + elif jobs.num_jobs == 1 or not python_has_threads: msg = "parallel builds are unsupported by this version of Python;\n" + \ "\tignoring -j or num_jobs option.\n" - elif sys.platform == 'win32': - msg = fetch_win32_parallel_msg() if msg: SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) -- cgit v0.12 From 77d00668798f7be8ea2355a64ba5cb1b667e20a5 Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Sat, 8 Apr 2017 14:06:30 +0530 Subject: py2/3 fixes for CPPDEFINES/pkg-config.py Use a dict which preserves its order so that output matches --- test/CPPDEFINES/pkg-config.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/CPPDEFINES/pkg-config.py b/test/CPPDEFINES/pkg-config.py index 4e81dec..42f38b6 100644 --- a/test/CPPDEFINES/pkg-config.py +++ b/test/CPPDEFINES/pkg-config.py @@ -56,6 +56,20 @@ int main(int argc, char *argv[]) """) test.write('SConstruct', """\ +# Python3 dicts dont preserve order. Hence we supply subclass of OrderedDict +# whose __str__ and __repr__ act like a normal dict. +from collections import OrderedDict +class OrderedPrintingDict(OrderedDict): + def __repr__(self): + return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}' + + __str__ = __repr__ + + # Because dict-like objects (except dict and UserDict) are not deep copied + # directly when constructing Environment(CPPDEFINES = OrderedPrintingDict(...)) + def __semi_deepcopy__(self): + return self.copy() +""" + """ # http://scons.tigris.org/issues/show_bug.cgi?id=2671 # Passing test cases env_1 = Environment(CPPDEFINES=[('DEBUG','1'), 'TEST']) @@ -67,11 +81,11 @@ env_2.MergeFlags('-DSOMETHING -DVARIABLE=2') print(env_2.subst('$_CPPDEFFLAGS')) # Failing test cases -env_3 = Environment(CPPDEFINES={'DEBUG':1, 'TEST':None}) +env_3 = Environment(CPPDEFINES=OrderedPrintingDict([('DEBUG', 1), ('TEST', None)])) env_3.ParseConfig('PKG_CONFIG_PATH=. %(pkg_config_path)s --cflags bug') print(env_3.subst('$_CPPDEFFLAGS')) -env_4 = Environment(CPPDEFINES={'DEBUG':1, 'TEST':None}) +env_4 = Environment(CPPDEFINES=OrderedPrintingDict([('DEBUG', 1), ('TEST', None)])) env_4.MergeFlags('-DSOMETHING -DVARIABLE=2') print(env_4.subst('$_CPPDEFFLAGS')) -- cgit v0.12 From 5a9dc6249678cc9987cb75dd9b26b9eddd895883 Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Sat, 8 Apr 2017 20:43:29 +0530 Subject: Fix the Copy-Action test case for py2/3 --- src/engine/SCons/Defaults.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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, -- cgit v0.12 From 841c3b0c2960822c4cc02235b104d5487316ac30 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:21:10 -0700 Subject: Fix issue where a blank line would lead to runtest.py dropping user into a python shell --- runtest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/runtest.py b/runtest.py index 0d9bbaf..18d4121 100755 --- a/runtest.py +++ b/runtest.py @@ -686,6 +686,7 @@ if testlistfile: tests = [x for x in tests if x[0] != '#'] tests = [x[:-1] for x in tests] tests = [x.strip() for x in tests] + tests = [x for x in tests if len(x) > 0] else: testpaths = [] -- cgit v0.12 From 1d60cfed5451fabf22ec48256248b6d3ad57b594 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:22:54 -0700 Subject: OSX: if user has SCONS_USE_MAC_PATHS environment variable set, then PATHOSX created from paths in /etc/paths and /etc/paths.d/* will be appended to the Environment's PATH. This allows tests (and builds) to work on (at least) on mac systems using macports --- src/engine/SCons/Platform/darwin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/SCons/Platform/darwin.py b/src/engine/SCons/Platform/darwin.py index 1cf4aeb..c85b75b 100644 --- a/src/engine/SCons/Platform/darwin.py +++ b/src/engine/SCons/Platform/darwin.py @@ -63,6 +63,10 @@ def generate(env): env.AppendENVPath('PATHOSX', line.strip('\n')) f.close() + # Not sure why this wasn't the case all along? + if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False): + env.AppendENVPath('PATH',env['ENV']['PATHOSX']) + # Local Variables: # tab-width:4 # indent-tabs-mode:nil -- cgit v0.12 From 937b081a09617398ceb0a8bcea6d09ccda3cbad4 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:23:41 -0700 Subject: OSX: for now don't run versioned lib tests on mac. The logic to generate the versioned libraries has the wrong format for osx/darwin --- test/LINK/VersionedLib-VariantDir.py | 10 +++++++++- test/LINK/VersionedLib-j2.py | 5 +++++ test/LINK/VersionedLib-subdir.py | 5 +++++ test/LINK/VersionedLib.py | 6 ++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/test/LINK/VersionedLib-VariantDir.py b/test/LINK/VersionedLib-VariantDir.py index 0a631b0..0350c6e 100644 --- a/test/LINK/VersionedLib-VariantDir.py +++ b/test/LINK/VersionedLib-VariantDir.py @@ -35,11 +35,19 @@ import sys import SCons.Platform import SCons.Defaults +test = TestSCons.TestSCons() + +import sys +if sys.platform == 'darwin': + # Skipping until logic is fixed for macosx + test.skip_test("Not working on darwin yet\n") + + env = SCons.Defaults.DefaultEnvironment() platform = SCons.Platform.platform_default() tool_list = SCons.Platform.DefaultToolList(platform, env) -test = TestSCons.TestSCons() + test.subdir(['src']) test.subdir(['src','lib']) diff --git a/test/LINK/VersionedLib-j2.py b/test/LINK/VersionedLib-j2.py index 249b54f..4646a37 100644 --- a/test/LINK/VersionedLib-j2.py +++ b/test/LINK/VersionedLib-j2.py @@ -39,6 +39,11 @@ import SCons.Defaults test = TestSCons.TestSCons() +if sys.platform == 'darwin': + # Skipping until logic is fixed for macosx + test.skip_test("Not working on darwin yet\n") + + test.write('foo.c', """ #if _WIN32 __declspec(dllexport) diff --git a/test/LINK/VersionedLib-subdir.py b/test/LINK/VersionedLib-subdir.py index a2e141b..91f3011 100644 --- a/test/LINK/VersionedLib-subdir.py +++ b/test/LINK/VersionedLib-subdir.py @@ -41,6 +41,11 @@ import SCons.Defaults test = TestSCons.TestSCons() +if sys.platform == 'darwin': + # Skipping until logic is fixed for macosx + test.skip_test("Not working on darwin yet\n") + + test.write('foo.c', """ #if _WIN32 __declspec(dllexport) diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py index 468e3e5..c05c159 100644 --- a/test/LINK/VersionedLib.py +++ b/test/LINK/VersionedLib.py @@ -33,6 +33,12 @@ import TestSCons import SCons.Platform import SCons.Defaults +import sys +if sys.platform == 'darwin': + # Skipping until logic is fixed for macosx + test = TestSCons.TestSCons() + test.skip_test("Not working on darwin yet\n") + env = SCons.Defaults.DefaultEnvironment() platform = SCons.Platform.platform_default() tool_list = SCons.Platform.DefaultToolList(platform, env) -- cgit v0.12 From b5c465f6f0874bd27a85891536ac157b6dcbadbe Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:23:56 -0700 Subject: add docstring --- src/engine/SCons/Tool/link.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index b7db947..07e9250 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -243,8 +243,10 @@ def _versioned_lib_callbacks(): 'VersionedLdModSoname' : _versioned_ldmod_soname, }.copy() -# Setup all variables required by the versioning machinery def _setup_versioned_lib_variables(env, **kw): + """ + Setup all variables required by the versioning machinery + """ tool = None try: tool = kw['tool'] -- cgit v0.12 From f24bc75523ba61b32c67ab6f5ad701b7a4023614 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:24:21 -0700 Subject: osx: add logic to enable versioned shared libraries on osx/darwin. For now it's commented out --- src/engine/SCons/Tool/applelink.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py index ba955a4..c5f4376 100644 --- a/src/engine/SCons/Tool/applelink.py +++ b/src/engine/SCons/Tool/applelink.py @@ -51,6 +51,14 @@ def generate(env): env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib') env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' + + # TODO: Work needed to generate versioned shared libraries + # Leaving this commented out, and also going to disable versioned library checking for now + # see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming + #link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname) + #env['LINKCALLBACKS'] = link._versioned_lib_callbacks() + + # override the default for loadable modules, which are different # on OS X than dynamic shared libs. echoing what XCode does for # pre/suffixes: -- cgit v0.12 From 8e6c6ad7f23cf988376d313cdbc510e4ad2c0f86 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:24:35 -0700 Subject: pep8 --- src/engine/SCons/Tool/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 99e0770..61b7788 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -761,6 +761,7 @@ def LibSymlinksStrFun(target, source, env, *args): LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) + def createSharedLibBuilder(env): """This is a utility function that creates the SharedLibrary Builder in an Environment if it is not there already. -- cgit v0.12 From c6281db8311345dbae895a498bd44b73600d4c0c Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 8 Apr 2017 18:26:06 -0700 Subject: osx: fix get_platform_python_info() to work on mac. --- QMTest/TestSCons.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py index 5a9d21f..9c89249 100644 --- a/QMTest/TestSCons.py +++ b/QMTest/TestSCons.py @@ -1246,7 +1246,10 @@ try: import distutils.sysconfig exec_prefix = distutils.sysconfig.EXEC_PREFIX print(distutils.sysconfig.get_python_inc()) - print(os.path.join(exec_prefix, 'libs')) + lib_path = os.path.join(exec_prefix, 'libs') + if not os.path.exists(lib_path): + lib_path = os.path.join(exec_prefix, 'lib') + print(lib_path) except: print(os.path.join(sys.prefix, 'include', py_ver)) print(os.path.join(sys.prefix, 'lib', py_ver, 'config')) -- cgit v0.12 From 35e2fb999be90a3d6619fc404910567822993e1f Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 9 Apr 2017 15:10:45 -0700 Subject: For docbook, stop looking after you find the first tool. It looks like saxon-xslt causes the tests to fail. Dirk? --- src/engine/SCons/Tool/docbook/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py index 8a7b2e7..89afe5d 100644 --- a/src/engine/SCons/Tool/docbook/__init__.py +++ b/src/engine/SCons/Tool/docbook/__init__.py @@ -179,6 +179,7 @@ def __detect_cl_tool(env, chainkey, cdict): env[chainkey] = clpath if not env[chainkey + 'COM']: env[chainkey + 'COM'] = cdict[cltool] + break def _detect(env): """ -- cgit v0.12 From 9001886a331f96450bad7c39a6b756ad62242b49 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 9 Apr 2017 18:13:02 -0700 Subject: py2/3 initial changes to try and get SCons build working with py3 --- SConstruct | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/SConstruct b/SConstruct index 08f7da5..57f2fc1 100644 --- a/SConstruct +++ b/SConstruct @@ -162,6 +162,15 @@ import distutils.command no_winpack_templates = not os.path.exists(os.path.join(os.path.split(distutils.command.__file__)[0],'wininst-9.0.exe')) skip_win_packages = ARGUMENTS.get('SKIP_WIN_PACKAGES',False) or no_winpack_templates + +if sys.version_info[0] > 2: + # TODO: Resolve this issue. Currently fails when run on windows with + # File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/distutils/command/bdist_wininst.py", line 262, in create_exe + # cfgdata = cfgdata.encode("mbcs") + # LookupError: unknown encoding: mbcs + print("Temporary PY3: Skipping windows package builds") + skip_win_packages = True + if skip_win_packages: print("Skipping the build of Windows packages...") @@ -327,17 +336,20 @@ try: def zipit(env, target, source): print("Zipping %s:" % str(target[0])) - def visit(arg, dirname, names): - for name in names: - path = os.path.join(dirname, name) + def visit(arg, dirname, filenames): + for filename in filenames: + path = os.path.join(dirname, filename) if os.path.isfile(path): arg.write(path) # default ZipFile compression is ZIP_STORED zf = zipfile.ZipFile(str(target[0]), 'w', compression=zipfile.ZIP_DEFLATED) olddir = os.getcwd() os.chdir(env['CD']) - try: os.path.walk(env['PSV'], visit, zf) - finally: os.chdir(olddir) + try: + for dirname, dirnames, filenames in os.walk(env['PSV']): + visit(zf, dirname, filenames) + finally: + os.chdir(olddir) zf.close() def unzipit(env, target, source): @@ -364,6 +376,7 @@ except ImportError: zipit = "cd $CD && $ZIP $ZIPFLAGS $( ${TARGET.abspath} $) $PSV" unzipit = "$UNZIP $UNZIPFLAGS $SOURCES" + def SCons_revision(target, source, env): """Interpolate specific values from the environment into a file. @@ -372,7 +385,7 @@ def SCons_revision(target, source, env): """ t = str(target[0]) s = source[0].rstr() - with open(s, 'rb') as fp: + with open(s, 'r') as fp: contents = fp.read() # Note: We construct the __*__ substitution strings here # so that they don't get replaced when this file gets @@ -387,9 +400,10 @@ def SCons_revision(target, source, env): contents = contents.replace('__REVISION' + '__', env['REVISION']) contents = contents.replace('__VERSION' + '__', env['VERSION']) contents = contents.replace('__NULL' + '__', '') - open(t, 'wb').write(contents) + open(t, 'w').write(contents) os.chmod(t, os.stat(s)[0]) + revaction = SCons_revision revbuilder = Builder(action = Action(SCons_revision, varlist=['COPYRIGHT', 'VERSION'])) @@ -819,6 +833,7 @@ for p in [ scons ]: s = p['filemap'].get(b, b) if not s[0] == '$' and not os.path.isabs(s): s = os.path.join(src, s) + builder = p['buildermap'].get(b, env.SCons_revision) x = builder(os.path.join(build, b), s) Local(x) @@ -835,7 +850,7 @@ for p in [ scons ]: def write_src_files(target, source, **kw): global src_files src_files.sort() - f = open(str(target[0]), 'wb') + f = open(str(target[0]), 'w') for file in src_files: f.write(file + "\n") f.close() @@ -1017,10 +1032,10 @@ for p in [ scons ]: list generated from our MANIFEST(s), so we don't have to maintain multiple lists. """ - c = open(str(source[0]), 'rb').read() + c = open(str(source[0]), 'r').read() c = c.replace('__VERSION' + '__', env['VERSION']) c = c.replace('__RPM_FILES' + '__', env['RPM_FILES']) - open(str(target[0]), 'wb').write(c) + open(str(target[0]), 'w').write(c) rpm_files.sort() rpm_files_str = "\n".join(rpm_files) + "\n" -- cgit v0.12 From a66460a28e7672071cbb5c003332cfdc96669563 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 10 Apr 2017 11:14:23 -0700 Subject: switch to os.system as in py3 os.popen() seemed to not have completed untar before the test checked for files --- test/packaging/use-builddir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/packaging/use-builddir.py b/test/packaging/use-builddir.py index 76b9737..9ad7aa4 100644 --- a/test/packaging/use-builddir.py +++ b/test/packaging/use-builddir.py @@ -85,7 +85,7 @@ test.run(stderr = None) test.must_exist( 'libfoo-1.2.3.tar.gz' ) -os.popen( 'tar -C temp -xzf %s'%test.workpath('libfoo-1.2.3.tar.gz') ) +os.system('tar -C temp -xzf %s'%test.workpath('libfoo-1.2.3.tar.gz') ) test.must_exist( 'temp/libfoo-1.2.3/src/main.c' ) test.must_exist( 'temp/libfoo-1.2.3/SConstruct' ) -- cgit v0.12 From 31383c850bc278c11c6020ce3f0704a402584a2d Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Tue, 11 Apr 2017 00:01:37 +0530 Subject: py2/3 fix for test/Value.py --- src/engine/SCons/Node/Python.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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() -- cgit v0.12 From 2c7b4f7cd5a2277208902c3b59c98b8530fd8698 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 10 Apr 2017 11:40:50 -0700 Subject: py2/3 change to read sconscripts as binary file. at least test/packaging/rpm/internationalization.py was failing because an open in py3 without specified encoding with LANG=C was trying to decode the file as ascii and it contained unicode characters and was failing. So far I haven't found any tests failing from this change --- src/engine/SCons/Script/SConscript.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 8609892..558e28f 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -179,10 +179,10 @@ def _SConscript(fs, *files, **kw): fs.chdir(top, change_os_dir=1) if f.rexists(): actual = f.rfile() - _file_ = open(actual.get_abspath(), "r") + _file_ = open(actual.get_abspath(), "rb") elif f.srcnode().rexists(): actual = f.srcnode().rfile() - _file_ = open(actual.get_abspath(), "r") + _file_ = open(actual.get_abspath(), "rb") elif f.has_src_builder(): # The SConscript file apparently exists in a source # code management system. Build it, but then clear @@ -192,7 +192,7 @@ def _SConscript(fs, *files, **kw): f.built() f.builder_set(None) if f.exists(): - _file_ = open(f.get_abspath(), "r") + _file_ = open(f.get_abspath(), "rb") if _file_: # Chdir to the SConscript directory. Use a path # name relative to the SConstruct file so that if @@ -248,6 +248,7 @@ def _SConscript(fs, *files, **kw): pass try: try: +# _file_ = SCons.Util.to_str(_file_) exec(compile(_file_.read(), _file_.name, 'exec'), call_stack[-1].globals) except SConscriptReturn: -- cgit v0.12 From 550fcc144495dfd8569831e2a0996b4e134549f8 Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Tue, 11 Apr 2017 00:36:39 +0530 Subject: Fix broken tests --- src/engine/SCons/Node/PythonTests.py | 6 +++--- src/engine/SCons/SConf.py | 8 ++++---- src/engine/SCons/SConfTests.py | 38 ++++++++++++++++++------------------ 3 files changed, 26 insertions(+), 26 deletions(-) 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 ") 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_') -- cgit v0.12 From 1cae9523c7cb5b241c1b14021e92d6eccceac7ca Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Fri, 14 Apr 2017 20:18:20 +0530 Subject: Dirty hack for failing test/sconsign/script/Configure.py --- src/script/sconsign.py | 5 +++++ 1 file changed, 5 insertions(+) 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): -- cgit v0.12 From e2644d7ee935b61f3307aafd376a9bca732f50bc Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 15 Apr 2017 17:27:47 -0700 Subject: remove deprecated module SCons.Sig --- src/CHANGES.txt | 1 + src/engine/SCons/Sig.py | 63 --------------------------------------------- test/Deprecated/Sig.py | 68 ------------------------------------------------- 3 files changed, 1 insertion(+), 131 deletions(-) delete mode 100644 src/engine/SCons/Sig.py delete mode 100644 test/Deprecated/Sig.py diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 5127c51..2b0c3cd 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -40,6 +40,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From William Deegan: - Removed deprecated tools CVS, Perforce, BitKeeper, RCS, SCCS, Subversion. + - Removed deprecated module SCons.Sig From Daniel Moody: - Fixed msvs.py for Visual Studio generated projects which were diff --git a/src/engine/SCons/Sig.py b/src/engine/SCons/Sig.py deleted file mode 100644 index 35fffc1..0000000 --- a/src/engine/SCons/Sig.py +++ /dev/null @@ -1,63 +0,0 @@ -# -# __COPYRIGHT__ -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# 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__" - -__doc__ = """Place-holder for the old SCons.Sig module hierarchy - -This is no longer used, but code out there (such as the NSIS module on -the SCons wiki) may try to import SCons.Sig. If so, we generate a warning -that points them to the line that caused the import, and don't die. - -If someone actually tried to use the sub-modules or functions within -the package (for example, SCons.Sig.MD5.signature()), then they'll still -get an AttributeError, but at least they'll know where to start looking. -""" - -import SCons.Util -import SCons.Warnings - -msg = 'The SCons.Sig module no longer exists.\n' \ - ' Remove the following "import SCons.Sig" line to eliminate this warning:' - -SCons.Warnings.warn(SCons.Warnings.DeprecatedSigModuleWarning, msg) - -default_calc = None -default_module = None - -class MD5Null(SCons.Util.Null): - def __repr__(self): - return "MD5Null()" - -class TimeStampNull(SCons.Util.Null): - def __repr__(self): - return "TimeStampNull()" - -MD5 = MD5Null() -TimeStamp = TimeStampNull() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/Deprecated/Sig.py b/test/Deprecated/Sig.py deleted file mode 100644 index 1ae118b..0000000 --- a/test/Deprecated/Sig.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# -# __COPYRIGHT__ -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# 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__" - -""" -Verify that we generate the proper warning, but don't die, when someone -tries to import the SCons.Sig module (which no longer exists) and -use the things we used to define therein. -""" - -import TestSCons - -test = TestSCons.TestSCons() - -SConstruct = test.workpath('SConstruct') - -test.write(SConstruct, """ -import SCons.Sig -x = SCons.Sig.default_calc -x = SCons.Sig.default_module -x = SCons.Sig.MD5.current() -x = SCons.Sig.MD5.collect() -x = SCons.Sig.MD5.signature() -x = SCons.Sig.MD5.to_string() -x = SCons.Sig.MD5.from_string() -x = SCons.Sig.TimeStamp.current() -x = SCons.Sig.TimeStamp.collect() -x = SCons.Sig.TimeStamp.signature() -x = SCons.Sig.TimeStamp.to_string() -x = SCons.Sig.TimeStamp.from_string() -""") - -expect = """ -scons: warning: The SCons.Sig module no longer exists. - Remove the following "import SCons.Sig" line to eliminate this warning: -""" + test.python_file_line(SConstruct, 2) - -test.run(arguments = '.', stderr=expect) - -test.pass_test() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: -- cgit v0.12 From 9ced8fe7b4e2f878df32ab3f606f851ac4cb6efc Mon Sep 17 00:00:00 2001 From: Gaurav Juvekar Date: Sun, 16 Apr 2017 19:46:47 +0530 Subject: Try to fix some more py2/3 tests becuase of str vs bytearray --- src/engine/SCons/Node/Python.py | 8 +++++++- src/engine/SCons/Tool/textfile.py | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py index 2a3ce98..8c47c97 100644 --- a/src/engine/SCons/Node/Python.py +++ b/src/engine/SCons/Node/Python.py @@ -137,7 +137,13 @@ class Value(SCons.Node.Node): return contents def get_contents(self): - return self.get_text_contents().encode() + text_contents = self.get_text_contents() + try: + return text_contents.encode() + except UnicodeDecodeError: + # Already encoded as python2 str are bytes + return text_contents + def changed_since_last_build(self, target, prev_ni): cur_csig = self.get_csig() diff --git a/src/engine/SCons/Tool/textfile.py b/src/engine/SCons/Tool/textfile.py index 0e4d943..42a79cd 100644 --- a/src/engine/SCons/Tool/textfile.py +++ b/src/engine/SCons/Tool/textfile.py @@ -71,7 +71,11 @@ def _do_subst(node, subs): contents = re.sub(k, v, contents) if 'b' in TEXTFILE_FILE_WRITE_MODE: - contents = bytearray(contents, 'utf-8') + try: + contents = bytearray(contents, 'utf-8') + except UnicodeDecodeError: + # contents is already utf-8 encoded python 2 str i.e. a byte array + contents = bytearray(contents) return contents -- cgit v0.12 From 99433738ce86c18b7622d547fa46cee71b06a818 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 17 Apr 2017 08:39:15 -0700 Subject: fix Manifest.in which was causing bootstrap.py to fail due to removal of Sig.py --- src/engine/MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in index c70466d..32f4965 100644 --- a/src/engine/MANIFEST.in +++ b/src/engine/MANIFEST.in @@ -47,7 +47,6 @@ SCons/Script/Interactive.py SCons/Script/Main.py SCons/Script/SConscript.py SCons/Script/SConsOptions.py -SCons/Sig.py SCons/Subst.py SCons/Taskmaster.py SCons/Tool/__init__.py -- cgit v0.12 From a7e0cf73de6da9a5da8acc0302b979e59c07330d Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 17 Apr 2017 15:34:30 -0700 Subject: set priority for finding xsltproc tools --- src/engine/SCons/Tool/docbook/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py index 89afe5d..e805253 100644 --- a/src/engine/SCons/Tool/docbook/__init__.py +++ b/src/engine/SCons/Tool/docbook/__init__.py @@ -157,6 +157,7 @@ def __create_output_dir(base_dir): # # Supported command line tools and their call "signature" # +xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan'] xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE', 'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS', 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS', @@ -166,14 +167,17 @@ fop_com = {'fop' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -fo $SOURCE -pdf $TARGET', 'xep' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -valid -fo $SOURCE -pdf $TARGET', 'jw' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -f docbook -b pdf $SOURCE -o $TARGET'} -def __detect_cl_tool(env, chainkey, cdict): +def __detect_cl_tool(env, chainkey, cdict, cpriority=None): """ Helper function, picks a command line tool from the list and initializes its environment variables. """ if env.get(chainkey,'') == '': clpath = '' - for cltool in cdict: + + if cpriority is None: + cpriority = cdict.keys() + for cltool in cpriority: clpath = env.WhereIs(cltool) if clpath: env[chainkey] = clpath @@ -193,7 +197,7 @@ def _detect(env): if ((not has_libxml2 and not has_lxml) or (prefer_xsltproc)): # Try to find the XSLT processors - __detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com) + __detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority) __detect_cl_tool(env, 'DOCBOOK_XMLLINT', xmllint_com) __detect_cl_tool(env, 'DOCBOOK_FOP', fop_com) -- cgit v0.12 From 066340f2d96ddc73e932f69f6f6df73b86eecde3 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 17 Apr 2017 21:29:36 -0700 Subject: add notes to xsltproc logic with future TODO's for future improvements --- src/engine/SCons/Tool/docbook/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py index e805253..d3ea8ae 100644 --- a/src/engine/SCons/Tool/docbook/__init__.py +++ b/src/engine/SCons/Tool/docbook/__init__.py @@ -158,6 +158,10 @@ def __create_output_dir(base_dir): # Supported command line tools and their call "signature" # xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan'] + +# TODO: Set minimum version of saxon-xslt to be 8.x (lower than this only supports xslt 1.0. +# see: http://saxon.sourceforge.net/saxon6.5.5/ +# see: http://saxon.sourceforge.net/ xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE', 'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS', 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS', -- cgit v0.12 From 03013f4884c9727cf022fb6299ded8bf6f59e79a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 17 Apr 2017 21:33:14 -0700 Subject: CHANGES for xsltproc choosing logic changes --- src/CHANGES.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 2b0c3cd..2f46d4f 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -41,6 +41,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From William Deegan: - Removed deprecated tools CVS, Perforce, BitKeeper, RCS, SCCS, Subversion. - Removed deprecated module SCons.Sig + - Added prioritized list of xsltproc tools to docbook. The order will now be as + follows: xsltproc, saxon, saxon-xslt, xalan (with first being highest priority, first + tool found is used) From Daniel Moody: - Fixed msvs.py for Visual Studio generated projects which were -- cgit v0.12 From a72dc1246c42d37e35fc7838c4bc22298a5a3c0a Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 17 Apr 2017 21:43:30 -0700 Subject: more removal of sccs and rcs builder logic --- src/engine/SCons/Node/FS.py | 78 ++-------------------------------------- src/engine/SCons/Node/FSTests.py | 33 ----------------- test/diskcheck.py | 24 ------------- 3 files changed, 2 insertions(+), 133 deletions(-) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 8f26777..64b2e3f 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -351,33 +351,6 @@ class _Null(object): _null = _Null() -DefaultSCCSBuilder = None -DefaultRCSBuilder = None - -def get_DefaultSCCSBuilder(): - global DefaultSCCSBuilder - if DefaultSCCSBuilder is None: - import SCons.Builder - # "env" will get filled in by Executor.get_build_env() - # calling SCons.Defaults.DefaultEnvironment() when necessary. - act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR') - DefaultSCCSBuilder = SCons.Builder.Builder(action = act, - env = None, - name = "DefaultSCCSBuilder") - return DefaultSCCSBuilder - -def get_DefaultRCSBuilder(): - global DefaultRCSBuilder - if DefaultRCSBuilder is None: - import SCons.Builder - # "env" will get filled in by Executor.get_build_env() - # calling SCons.Defaults.DefaultEnvironment() when necessary. - act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR') - DefaultRCSBuilder = SCons.Builder.Builder(action = act, - env = None, - name = "DefaultRCSBuilder") - return DefaultRCSBuilder - # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem. _is_cygwin = sys.platform == "cygwin" if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin: @@ -422,46 +395,12 @@ def do_diskcheck_match(node, predicate, errorfmt): def ignore_diskcheck_match(node, predicate, errorfmt): pass -def do_diskcheck_rcs(node, name): - try: - rcs_dir = node.rcs_dir - except AttributeError: - if node.entry_exists_on_disk('RCS'): - rcs_dir = node.Dir('RCS') - else: - rcs_dir = None - node.rcs_dir = rcs_dir - if rcs_dir: - return rcs_dir.entry_exists_on_disk(name+',v') - return None - -def ignore_diskcheck_rcs(node, name): - return None - -def do_diskcheck_sccs(node, name): - try: - sccs_dir = node.sccs_dir - except AttributeError: - if node.entry_exists_on_disk('SCCS'): - sccs_dir = node.Dir('SCCS') - else: - sccs_dir = None - node.sccs_dir = sccs_dir - if sccs_dir: - return sccs_dir.entry_exists_on_disk('s.'+name) - return None -def ignore_diskcheck_sccs(node, name): - return None diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match) -diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs) -diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs) diskcheckers = [ diskcheck_match, - diskcheck_rcs, - diskcheck_sccs, ] def set_diskcheck(list): @@ -982,8 +921,6 @@ class Entry(Base): 'root', 'dirname', 'on_disk_entries', - 'sccs_dir', - 'rcs_dir', 'released_target_info', 'contentsig'] @@ -1529,8 +1466,6 @@ class Dir(Base): 'root', 'dirname', 'on_disk_entries', - 'sccs_dir', - 'rcs_dir', 'released_target_info', 'contentsig'] @@ -2096,9 +2031,7 @@ class Dir(Base): return node def file_on_disk(self, name): - if self.entry_exists_on_disk(name) or \ - diskcheck_rcs(self, name) or \ - diskcheck_sccs(self, name): + if self.entry_exists_on_disk(name): try: return self.File(name) except TypeError: pass node = self.srcdir_duplicate(name) @@ -2595,8 +2528,6 @@ class File(Base): 'root', 'dirname', 'on_disk_entries', - 'sccs_dir', - 'rcs_dir', 'released_target_info', 'contentsig'] @@ -3037,12 +2968,7 @@ class File(Base): return None scb = self.dir.src_builder() if scb is _null: - if diskcheck_sccs(self.dir, self.name): - scb = get_DefaultSCCSBuilder() - elif diskcheck_rcs(self.dir, self.name): - scb = get_DefaultRCSBuilder() - else: - scb = None + scb = None if scb is not None: try: b = self.builder diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 7366b7b..306f1a2 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -3269,18 +3269,11 @@ class has_src_builderTestCase(unittest.TestCase): fs = SCons.Node.FS.FS(test.workpath('')) os.chdir(test.workpath('')) test.subdir('sub1') - test.subdir('sub2', ['sub2', 'SCCS'], ['sub2', 'RCS']) sub1 = fs.Dir('sub1', '.') f1 = fs.File('f1', sub1) f2 = fs.File('f2', sub1) f3 = fs.File('f3', sub1) - sub2 = fs.Dir('sub2', '.') - f4 = fs.File('f4', sub2) - f5 = fs.File('f5', sub2) - f6 = fs.File('f6', sub2) - f7 = fs.File('f7', sub2) - f8 = fs.File('f8', sub2) h = f1.has_src_builder() assert not h, h @@ -3305,32 +3298,6 @@ class has_src_builderTestCase(unittest.TestCase): assert h, h assert f3.builder is b1, f3.builder - f7.set_src_builder(b1) - f8.builder_set(b1) - - test.write(['sub2', 'SCCS', 's.f5'], "sub2/SCCS/s.f5\n") - test.write(['sub2', 'RCS', 'f6,v'], "sub2/RCS/f6,v\n") - h = f4.has_src_builder() - assert not h, h - h = f4.has_builder() - assert not h, h - h = f5.has_src_builder() - assert h, h - h = f5.has_builder() - assert h, h - h = f6.has_src_builder() - assert h, h - h = f6.has_builder() - assert h, h - h = f7.has_src_builder() - assert h, h - h = f7.has_builder() - assert h, h - h = f8.has_src_builder() - assert not h, h - h = f8.has_builder() - assert h, h - class prepareTestCase(unittest.TestCase): def runTest(self): """Test the prepare() method""" diff --git a/test/diskcheck.py b/test/diskcheck.py index adbeea1..36cfa4e 100644 --- a/test/diskcheck.py +++ b/test/diskcheck.py @@ -52,30 +52,6 @@ test.must_contain_all_lines(test.stderr(), ["found where file expected"]) -test.write('SConstruct', """ -SetOption('diskcheck', ['rcs', 'sccs']) -Dir('file') -""") - -test.run() - -test.run(arguments='--diskcheck=match', status=2, stderr=None) -test.must_contain_all_lines(test.stderr(), ["found where directory expected"]) - - - -test.write('SConstruct', """ -SetOption('diskcheck', 'rcs,sccs') -Dir('file/subdir') -""") - -test.run() - -test.run(arguments='--diskcheck=match', status=2, stderr=None) -test.must_contain_all_lines(test.stderr(), ["found where directory expected"]) - - - test.pass_test() # Local Variables: -- cgit v0.12 From 05fbc42f3380435f378864b5d7d2b69083d7cd8e Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 10:01:47 -0700 Subject: fix test to not run on OSX --- test/leaky-handles.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/leaky-handles.py b/test/leaky-handles.py index 9502d1b..3787ee2 100644 --- a/test/leaky-handles.py +++ b/test/leaky-handles.py @@ -29,12 +29,13 @@ Verify that file handles aren't leaked to child processes """ import os +import sys import TestSCons test = TestSCons.TestSCons() -if os.name != 'posix': +if os.name != 'posix' or sys.platform == 'darwin': msg = "Skipping fork leak test on non-posix platform '%s'\n" % os.name test.skip_test(msg) -- cgit v0.12 From 764801ecaf19fd73e75a90ba26452dd7c86a5138 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 10:26:34 -0700 Subject: fix test for osx (with macports only at this point) --- test/SWIG/recursive-includes-cpp.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/SWIG/recursive-includes-cpp.py b/test/SWIG/recursive-includes-cpp.py index 364bd73..dbcac6d 100644 --- a/test/SWIG/recursive-includes-cpp.py +++ b/test/SWIG/recursive-includes-cpp.py @@ -64,6 +64,7 @@ test.write("mod.i", """\ test.write('SConstruct', """\ import distutils.sysconfig +import sys DefaultEnvironment( tools = [ 'swig' ] ) @@ -77,6 +78,9 @@ env = Environment( SHLIBPREFIX = "" ) +if sys.platform == 'darwin': + env['LIBS']=['python%d.%d'%(sys.version_info[0],sys.version_info[1])] + env.SharedLibrary( 'mod.so', [ -- cgit v0.12 From 0a59346b5443a5b93fa8ada59519de0ccf95081e Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 10:50:03 -0700 Subject: osx: disable mixedDandC test until a good way to specify correct gcc is found --- test/D/MixedDAndC/sconstest-dmd.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/D/MixedDAndC/sconstest-dmd.py b/test/D/MixedDAndC/sconstest-dmd.py index df66255..d96c5c3 100644 --- a/test/D/MixedDAndC/sconstest-dmd.py +++ b/test/D/MixedDAndC/sconstest-dmd.py @@ -27,6 +27,16 @@ Test compiling and executing a project with a C module. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +import sys +if sys.platform == 'darwin': + import TestSCons + test = TestSCons.TestSCons() + + msg = "Skipping Mixed dmd test until a good way to ensure proper gcc is called." + "Calling default(system /usr/bin/gcc) gcc yields a surplus of linking errors\n" + test.skip_test(msg) + + from Common.common import testForTool testForTool('dmd') -- cgit v0.12 From 67cbcb1fabc677b2fcbac4187992d43c51cf3874 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 21:11:17 -0700 Subject: py2/3 - syntax for wrong number of arguments to functions changes for py3, added to valid output --- test/Subst/TypeError.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/Subst/TypeError.py b/test/Subst/TypeError.py index 371ceff..628db2f 100644 --- a/test/Subst/TypeError.py +++ b/test/Subst/TypeError.py @@ -58,9 +58,7 @@ expect = expect_build % (r' \[foo\.bar\]', r'\$\{NONE\[0\]\}') test.run(status=2, stderr=expect) - - -expect_build = r"""scons: \*\*\*%s TypeError `(not enough arguments; expected 3, got 1|func\(\) takes exactly 3 arguments \(1 given\))' trying to evaluate `%s' +expect_build = r"""scons: \*\*\*%s TypeError `(not enough arguments; expected 3, got 1|func\(\) takes exactly 3 arguments \(1 given\)|func\(\) missing 2 required positional arguments: 'b' and 'c')' trying to evaluate `%s' """ expect_read = "\n" + expect_build + TestSCons.file_expr -- cgit v0.12 From aae1dc7ebafa24cc9ac6fef7db00dbc6ec7633a1 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 21:16:46 -0700 Subject: py2/3 no auto stringification for None in py3 --- test/GetBuildFailures/parallel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/GetBuildFailures/parallel.py b/test/GetBuildFailures/parallel.py index ee0e831..f9503e0 100644 --- a/test/GetBuildFailures/parallel.py +++ b/test/GetBuildFailures/parallel.py @@ -80,7 +80,7 @@ Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE') def print_build_failures(): from SCons.Script import GetBuildFailures - for bf in sorted(GetBuildFailures(), key=lambda t: t.filename): + for bf in sorted(GetBuildFailures(), key=lambda t: t.filename or 'None'): print("%%s failed: %%s" %% (bf.node, bf.errstr)) import atexit -- cgit v0.12 From d13cd11ef106fd6fbdbf007257b1da2dacf71d0e Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 21:17:38 -0700 Subject: py2/3 no auto stringification for None in py3 --- test/GetBuildFailures/option-k.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/GetBuildFailures/option-k.py b/test/GetBuildFailures/option-k.py index 0ff22e6..12ae07b 100644 --- a/test/GetBuildFailures/option-k.py +++ b/test/GetBuildFailures/option-k.py @@ -64,7 +64,7 @@ Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE') def print_build_failures(): from SCons.Script import GetBuildFailures - for bf in sorted(GetBuildFailures(), key=lambda a: a.filename): + for bf in sorted(GetBuildFailures(), key=lambda a: a.filename or 'None'): print("%%s failed: %%s" %% (bf.node, bf.errstr)) import atexit -- cgit v0.12 From d624a087a4ed7768052f0ab1c614ea6864179dd5 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 18 Apr 2017 21:27:50 -0700 Subject: py2/3 swap to use test.must_match with mode='r' --- test/option--max-drift.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/option--max-drift.py b/test/option--max-drift.py index 08fafd1..4e063c9 100644 --- a/test/option--max-drift.py +++ b/test/option--max-drift.py @@ -109,14 +109,14 @@ atime = os.path.getatime(test.workpath('foo.in')) mtime = os.path.getmtime(test.workpath('foo.in')) test.run() -test.fail_test(test.read('foo.out') != 'foo.in\n') +test.must_match('foo.out', 'foo.in\n', mode='r') test.write('foo.in', 'foo.in delta\n') os.utime(test.workpath('foo.in'), (atime,mtime)) test.run() -test.fail_test(test.read('foo.out') != 'foo.in\n') +test.must_match('foo.out', 'foo.in\n', mode='r') test.pass_test() -- cgit v0.12 From 03eb2e5498807786834933b54703b3b9f127e282 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 19 Apr 2017 08:42:09 -0700 Subject: py2/3 handle differences between py2 and 3 on reading/writing binary data to stdin/stdout --- test/redirection.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/redirection.py b/test/redirection.py index ffc76b5..ba35ed0 100644 --- a/test/redirection.py +++ b/test/redirection.py @@ -32,11 +32,22 @@ test = TestSCons.TestSCons() test.write('cat.py', r""" import sys +PY3K = sys.version_info >= (3, 0) + try: - input = open(sys.argv[1], 'r').read() + input = open(sys.argv[1], 'rb').read() except IndexError: - input = sys.stdin.read() -sys.stdout.write(input) + if PY3K: + source = sys.stdin.buffer + else: + source = sys.stdin + input = source.read() + +if PY3K: + sys.stdout.buffer.write(input) +else: + sys.stdout.write(input) + sys.exit(0) """) -- cgit v0.12 From 6d8d3b89fbcb22ca064a9d24f31f9a0b37e1826d Mon Sep 17 00:00:00 2001 From: William Deegan Date: Wed, 19 Apr 2017 09:02:36 -0700 Subject: py2/3 fix logic for reraising exceptions. A taskmaster test was failing because the passed exception value wasn't an exception and thus couldn't be reraised as is. Added logic to create an exception with the value and raise that --- src/engine/SCons/Taskmaster.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index cf924e7..9bd9597 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -546,7 +546,13 @@ class Task(object): if sys.version_info[0] == 2: exec("raise exc_type, exc_value, exc_traceback") else: # sys.version_info[0] == 3: - exec("raise exc_value.with_traceback(exc_traceback)") + if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'): + # If exc_value is an exception, then just reraise + exec("raise exc_value.with_traceback(exc_traceback)") + else: + # else we'll create an exception using the value and raise that + exec("raise exc_type(exc_value).with_traceback(exc_traceback)") + # raise e.__class__, e.__class__(e), sys.exc_info()[2] # exec("raise exc_type(exc_value).with_traceback(exc_traceback)") -- cgit v0.12 From dd4c5225dd12538a58faa2480548eac87d06a9cd Mon Sep 17 00:00:00 2001 From: William Deegan Date: Fri, 21 Apr 2017 09:27:45 -0700 Subject: Fix bug #2979 Example code for MSVSProject had syntax errors. http://scons.tigris.org/issues/show_bug.cgi?id=2979 --- src/CHANGES.txt | 1 + src/engine/SCons/Tool/msvs.xml | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 2f46d4f..0bcf92e 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -44,6 +44,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Added prioritized list of xsltproc tools to docbook. The order will now be as follows: xsltproc, saxon, saxon-xslt, xalan (with first being highest priority, first tool found is used) + - Fixed MSVSProject example code (http://scons.tigris.org/issues/show_bug.cgi?id=2979) From Daniel Moody: - Fixed msvs.py for Visual Studio generated projects which were diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml index e85b27c..b367e84 100644 --- a/src/engine/SCons/Tool/msvs.xml +++ b/src/engine/SCons/Tool/msvs.xml @@ -127,8 +127,10 @@ compilation error messages displayed in the Visual Studio console output window. This can be remedied by adding the Visual C/C++ /FC compiler option to the &cv-link-CCFLAGS; variable so that the compiler will print the full path name of any files that cause compilation errors. - Example usage: barsrcs = ['bar.cpp'], -barincs = ['bar.h'], + Example usage: + +barsrcs = ['bar.cpp'] +barincs = ['bar.h'] barlocalincs = ['StdAfx.h'] barresources = ['bar.rc','resource.h'] barmisc = ['bar_readme.txt'] -- cgit v0.12 From f67ce4d87c9531675c2e26715e005234fda4386c Mon Sep 17 00:00:00 2001 From: William Deegan Date: Fri, 21 Apr 2017 09:33:08 -0700 Subject: Part 2 of fix for bug # 2979. Fix target to be the .dll target node output from env.SharedLibrary() --- src/engine/SCons/Tool/msvs.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml index b367e84..c4701e1 100644 --- a/src/engine/SCons/Tool/msvs.xml +++ b/src/engine/SCons/Tool/msvs.xml @@ -137,14 +137,14 @@ barmisc = ['bar_readme.txt'] dll = env.SharedLibrary(target = 'bar.dll', source = barsrcs) - +buildtarget = [s for s in dll if str(s).endswith('dll')] env.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'], srcs = barsrcs, incs = barincs, localincs = barlocalincs, resources = barresources, misc = barmisc, - buildtarget = dll, + buildtarget = buildtarget, variant = 'Release') Starting with version 2.4 of -- cgit v0.12 From d9cc4fd395a610f3eaaee77ae81eb98d2792e3fa Mon Sep 17 00:00:00 2001 From: Jane Doe Date: Fri, 21 Apr 2017 16:31:02 -0700 Subject: kick buildbot --- SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SConstruct b/SConstruct index 57f2fc1..d871eda 100644 --- a/SConstruct +++ b/SConstruct @@ -1406,3 +1406,5 @@ for pf, help_text in packaging_flavors: os.path.join(build_dir, 'runtest.py'), ]) + +# test -- cgit v0.12 From bb04d9ccdacdc5f4d7e35d096889dfc23748631e Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 23 Apr 2017 15:26:25 -0400 Subject: Test is failing on Windows 7 and Linux when PRESERVE is used. dirlist is saved as unicode, so printing it must also be unicode. Tested with py2 and py3. --- QMTest/TestCmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py index 3b745f8..20f1f14 100644 --- a/QMTest/TestCmd.py +++ b/QMTest/TestCmd.py @@ -987,7 +987,7 @@ class TestCmd(object): condition = self.condition if self._preserve[condition]: for dir in self._dirlist: - print("Preserved directory " + dir + "\n") + print(u"Preserved directory " + dir + "\n") else: list = self._dirlist[:] list.reverse() -- cgit v0.12 From 26ed93ab719b54ec8fcf1bf31c307d3a34c0e403 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 23 Apr 2017 15:32:01 -0400 Subject: Updates CHANGES.txt with changes. --- src/CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 0bcf92e..5ec4cd5 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 Daniel Moody: + - Updated the src/engine/SCons/SConfTest.py so when using the + preserve option, it will be able to print unicode directories. + 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) -- cgit v0.12 From 151cbcd4868c42fc8fc102ca17110f424208cdf1 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 23 Apr 2017 16:00:43 -0400 Subject: This test is not account for PRESERVE being set. When preserve is set the rm command does not happen, so this output will fail. Tested py2 and py3. --- test/scons-time/run/option/verbose.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/scons-time/run/option/verbose.py b/test/scons-time/run/option/verbose.py index 5fc6d64..0ef2a6c 100644 --- a/test/scons-time/run/option/verbose.py +++ b/test/scons-time/run/option/verbose.py @@ -30,7 +30,7 @@ Verify that the run -v and --verbose options display command output. import sys import re - +import os import TestSCons_time _python_ = re.escape('"' + sys.executable + '"') @@ -112,7 +112,9 @@ scons-time%(time_re)s: %(_python_)s %(scons_py)s %(scons_flags)s --profile=%(pro SCONS_LIB_DIR = %(src_engine)s SConstruct file directory: %(tmp_scons_time_foo)s scons-time%(time_re)s: cd .* -scons-time%(time_re)s: rm -rf %(tmp_scons_time)s +""" +if 'PRESERVE' not in os.environ or not os.environ['PRESERVE']: + expect += """scons-time%(time_re)s: rm -rf %(tmp_scons_time)s """ foo_tar_gz = re.escape(foo_tar_gz) -- cgit v0.12 From f8899e92a97177e794aecadcd1f7fcce88b547d0 Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 23 Apr 2017 16:02:57 -0400 Subject: Updated CHANGES.txt with some more info because it was related, adn should be in the same pull request. --- src/CHANGES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 5ec4cd5..766c7d0 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -16,6 +16,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From Daniel Moody: - Updated the src/engine/SCons/SConfTest.py so when using the preserve option, it will be able to print unicode directories. + - Also updated a few test that were not taking into account PRESERVE From Gaurav Juvekar: - Fix issue #2910: Make --tree=all handle Unicode. (PR #427) -- cgit v0.12 From 0c775f3836a7d9a20956004834c8576defbf532f Mon Sep 17 00:00:00 2001 From: Daniel Moody Date: Sun, 23 Apr 2017 16:07:43 -0400 Subject: updated CHANGES.txt so it was more clear --- src/CHANGES.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 766c7d0..9e6151a 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -14,9 +14,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER RELEASE VERSION/DATE TO BE FILLED IN LATER From Daniel Moody: - - Updated the src/engine/SCons/SConfTest.py so when using the + - Updated the QMTest/TestCmd.py so when using the preserve option, it will be able to print unicode directories. - - Also updated a few test that were not taking into account PRESERVE + - Also updated test/scons-time/run/option/verbose.py that was + not taking into account the output when PRESERVE was enabled From Gaurav Juvekar: - Fix issue #2910: Make --tree=all handle Unicode. (PR #427) -- cgit v0.12 From 8bf16ddea63ef3405bf00ba1fb26da0cd60b7b08 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 23 Apr 2017 17:01:16 -0700 Subject: py2/3 Allow SConfTests.py to function when pywin32 is not installed. --- src/engine/SCons/SConfTests.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py index 0daf31c..f4c6f89 100644 --- a/src/engine/SCons/SConfTests.py +++ b/src/engine/SCons/SConfTests.py @@ -102,8 +102,11 @@ class SConfTestCase(unittest.TestCase): import SCons.Platform.win32 - file = SCons.Platform.win32._builtin_file - open = SCons.Platform.win32._builtin_open + try: + file = SCons.Platform.win32._builtin_file + open = SCons.Platform.win32._builtin_open + except AttributeError: + pass def _baseTryXXX(self, TryFunc): # TryCompile and TryLink are much the same, so we can test them -- cgit v0.12 From c03e43ea38fc2fe24fc40bbf4b45d4d19997c22d Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 23 Apr 2017 20:01:44 -0700 Subject: test --- SConstruct | 1 - 1 file changed, 1 deletion(-) diff --git a/SConstruct b/SConstruct index d871eda..bd43f19 100644 --- a/SConstruct +++ b/SConstruct @@ -1407,4 +1407,3 @@ for pf, help_text in packaging_flavors: ]) -# test -- cgit v0.12 From 6b86f7db0794b07ad5023fa96b041590a89a8d77 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 24 Apr 2017 09:09:38 -0700 Subject: py2/3 use dbm.ndbm on py3 and plain dbm doesn't create .sconsign.db, but rather .sconsign and causes test to fail. Continue to use dbm on py2 as dbm.ndbm doesn't exist there --- test/SConsignFile/use-dbm.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/SConsignFile/use-dbm.py b/test/SConsignFile/use-dbm.py index 90983b3..129d5b6 100644 --- a/test/SConsignFile/use-dbm.py +++ b/test/SConsignFile/use-dbm.py @@ -34,10 +34,16 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() + try: import dbm.ndbm + use_db = 'dbm.ndbm' except ImportError: - test.skip_test('No dbm in this version of Python; skipping test.\n') + try: + import dbm + use_db = 'dbm' + except ImportError: + test.skip_test('No dbm.ndbm in this version of Python; skipping test.\n') test.subdir('subdir') @@ -53,8 +59,8 @@ sys.exit(0) # test.write('SConstruct', """ import sys -import dbm -SConsignFile('.sconsign', dbm) +import %(use_db)s +SConsignFile('.sconsign', %(use_db)s) B = Builder(action = '%(_python_)s build.py $TARGETS $SOURCES') env = Environment(BUILDERS = { 'B' : B }) env.B(target = 'f1.out', source = 'f1.in') -- cgit v0.12