diff options
222 files changed, 3514 insertions, 3327 deletions
diff --git a/QMTest/SConscript b/QMTest/SConscript index 33fe9030..5469d298 100644 --- a/QMTest/SConscript +++ b/QMTest/SConscript @@ -44,12 +44,12 @@ files = [ def copy(target, source, env): t = str(target[0]) s = str(source[0]) - c = open(s, 'rb').read() + c = open(s, 'r').read() # Note: We construct the __ VERSION __ substitution string at # run-time so it doesn't get replaced when this file gets copied # into the tree for packaging. c = c.replace('__' + 'VERSION' + '__', env['VERSION']) - open(t, 'wb').write(c) + open(t, 'w').write(c) for file in files: # Guarantee that real copies of these files always exist in diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py index b51d90f1..55c198fd 100644 --- a/QMTest/TestCmd.py +++ b/QMTest/TestCmd.py @@ -285,7 +285,9 @@ version. # PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, # AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -from __future__ import division +from __future__ import division, print_function + +from six import PY3 __author__ = "Steven Knight <knight at baldmt dot com>" __revision__ = "TestCmd.py 1.3.D001 2010/06/03 12:58:27 knight" @@ -490,17 +492,17 @@ def match_re(lines = None, res = None): if not is_List(res): res = res.split("\n") if len(lines) != len(res): - print "match_re: expected %d lines, found %d"%(len(res), len(lines)) + print("match_re: expected %d lines, found %d"%(len(res), len(lines))) return for i in range(len(lines)): s = "^" + res[i] + "$" try: expr = re.compile(s) - except re.error, e: + except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) if not expr.search(lines[i]): - print "match_re: mismatch at line %d:\n search re='%s'\n line='%s'"%(i,s,lines[i]) + print("match_re: mismatch at line %d:\n search re='%s'\n line='%s'"%(i,s,lines[i])) return return 1 @@ -514,7 +516,7 @@ def match_re_dotall(lines = None, res = None): s = "^" + res + "$" try: expr = re.compile(s, re.DOTALL) - except re.error, e: + except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) return expr.match(lines) @@ -564,7 +566,7 @@ def diff_re(a, b, fromfile='', tofile='', s = "^" + aline + "$" try: expr = re.compile(s) - except re.error, e: + except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) if not expr.search(bline): @@ -640,7 +642,7 @@ else: st = os.stat(f) except OSError: continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return f return None @@ -743,7 +745,7 @@ class Popen(subprocess.Popen): (errCode, written) = WriteFile(x, input) except ValueError: return self._close('stdin') - except (subprocess.pywintypes.error, Exception), why: + except (subprocess.pywintypes.error, Exception) as why: if why.args[0] in (109, errno.ESHUTDOWN): return self._close('stdin') raise @@ -764,7 +766,7 @@ class Popen(subprocess.Popen): (errCode, read) = ReadFile(x, nAvail, None) except ValueError: return self._close(which) - except (subprocess.pywintypes.error, Exception), why: + except (subprocess.pywintypes.error, Exception) as why: if why.args[0] in (109, errno.ESHUTDOWN): return self._close(which) raise @@ -783,7 +785,7 @@ class Popen(subprocess.Popen): try: written = os.write(self.stdin.fileno(), input) - except OSError, why: + except OSError as why: if why.args[0] == errno.EPIPE: #broken pipe return self._close('stdin') raise @@ -977,7 +979,7 @@ class TestCmd(object): condition = self.condition if self._preserve[condition]: for dir in self._dirlist: - print unicode("Preserved directory " + dir + "\n"), + print("Preserved directory " + dir + "\n") else: list = self._dirlist[:] list.reverse() @@ -1043,10 +1045,10 @@ class TestCmd(object): if diff_function is None: diff_function = self.simple_diff if name is not None: - print self.banner(name) + print(self.banner(name)) args = (a.splitlines(), b.splitlines()) + args for line in diff_function(*args, **kw): - print line + print(line) def diff_stderr(self, a, b, *args, **kw): """Compare actual and expected file contents. @@ -1672,12 +1674,12 @@ class TestCmd(object): def do_chmod(fname): try: st = os.stat(fname) except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200)) + else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0o200)) else: def do_chmod(fname): try: st = os.stat(fname) except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200)) + else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0o200)) if os.path.isfile(top): do_chmod(top) @@ -1732,7 +1734,7 @@ class TestCmd(object): do_chmod(os.path.join(dirpath, name)) do_chmod(top) - def write(self, file, content, mode = 'wb'): + def write(self, file, content, mode = 'w'): """Writes the specified content text (second argument) to the specified file name (first argument). The file name may be a list, in which case the elements are concatenated with the @@ -1741,6 +1743,8 @@ class TestCmd(object): exist. The I/O mode for the file may be specified; it must begin with a 'w'. The default is 'wb' (binary write). """ + if PY3: + content = re.sub(r'print (.+)', r'print(\1)', content) file = self.canonicalize(file) if mode[0] != 'w': raise ValueError("mode must begin with 'w'") diff --git a/QMTest/TestCmdTests.py b/QMTest/TestCmdTests.py index 1044ed1e..66115907 100644 --- a/QMTest/TestCmdTests.py +++ b/QMTest/TestCmdTests.py @@ -19,6 +19,8 @@ AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. """ +from six import PY3 + __author__ = "Steven Knight <knight at baldmt dot com>" __revision__ = "TestCmdTests.py 1.3.D001 2010/06/03 12:58:27 knight" @@ -26,13 +28,20 @@ import os import shutil import signal import stat -import StringIO +if PY3: + from io import StringIO +else: + from StringIO import StringIO import sys import tempfile import time import types import unittest -import UserList +if PY3: + from collections import UserList +else: + from UserList import UserList + # Strip the current directory so we get the right TestCmd.py module. sys.path = sys.path[1:] @@ -131,11 +140,11 @@ class TestCmdTestCase(unittest.TestCase): run_env.write(t.scriptout_path, textout) run_env.write(t.scripterr_path, texterr) - os.chmod(t.script_path, 0644) # XXX UNIX-specific - os.chmod(t.scriptx_path, 0755) # XXX UNIX-specific - os.chmod(t.script1_path, 0644) # XXX UNIX-specific - os.chmod(t.scriptout_path, 0644) # XXX UNIX-specific - os.chmod(t.scripterr_path, 0644) # XXX UNIX-specific + os.chmod(t.script_path, 0o644) # XXX UNIX-specific + os.chmod(t.scriptx_path, 0o755) # XXX UNIX-specific + os.chmod(t.script1_path, 0o644) # XXX UNIX-specific + os.chmod(t.scriptout_path, 0o644) # XXX UNIX-specific + os.chmod(t.scripterr_path, 0o644) # XXX UNIX-specific t.orig_cwd = os.getcwd() @@ -220,8 +229,8 @@ class cleanup_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(workdir = '') wdir = test.workdir test.write('file2', "Test file #2\n") - os.chmod(test.workpath('file2'), 0400) - os.chmod(wdir, 0500) + os.chmod(test.workpath('file2'), 0o400) + os.chmod(wdir, 0o500) test.cleanup() assert not os.path.exists(wdir) @@ -286,35 +295,35 @@ class chmod_TestCase(TestCmdTestCase): test.chmod(['sub', 'file2'], stat.S_IWRITE) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0444, '0%o' % file1_mode + assert file1_mode == 0o444, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0666, '0%o' % file2_mode + assert file2_mode == 0o666, '0%o' % file2_mode test.chmod('file1', stat.S_IWRITE) test.chmod(wdir_sub_file2, stat.S_IREAD) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0666, '0%o' % file1_mode + assert file1_mode == 0o666, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0444, '0%o' % file2_mode + assert file2_mode == 0o444, '0%o' % file2_mode else: - test.chmod(wdir_file1, 0700) - test.chmod(['sub', 'file2'], 0760) + test.chmod(wdir_file1, 0o700) + test.chmod(['sub', 'file2'], 0o760) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0700, '0%o' % file1_mode + assert file1_mode == 0o700, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0760, '0%o' % file2_mode + assert file2_mode == 0o760, '0%o' % file2_mode - test.chmod('file1', 0765) - test.chmod(wdir_sub_file2, 0567) + test.chmod('file1', 0o765) + test.chmod(wdir_sub_file2, 0o567) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0765, '0%o' % file1_mode + assert file1_mode == 0o765, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0567, '0%o' % file2_mode + assert file2_mode == 0o567, '0%o' % file2_mode @@ -1032,14 +1041,14 @@ class match_exact_TestCase(TestCmdTestCase): assert test.match_exact("abcde\n", "abcde\n") assert not test.match_exact(["12345\n", "abcde\n"], ["1[0-9]*5\n", "a.*e\n"]) assert test.match_exact(["12345\n", "abcde\n"], ["12345\n", "abcde\n"]) - assert not test.match_exact(UserList.UserList(["12345\n", "abcde\n"]), + assert not test.match_exact(UserList(["12345\n", "abcde\n"]), ["1[0-9]*5\n", "a.*e\n"]) - assert test.match_exact(UserList.UserList(["12345\n", "abcde\n"]), + assert test.match_exact(UserList(["12345\n", "abcde\n"]), ["12345\n", "abcde\n"]) assert not test.match_exact(["12345\n", "abcde\n"], - UserList.UserList(["1[0-9]*5\n", "a.*e\n"])) + UserList(["1[0-9]*5\n", "a.*e\n"])) assert test.match_exact(["12345\n", "abcde\n"], - UserList.UserList(["12345\n", "abcde\n"])) + UserList(["12345\n", "abcde\n"])) assert not test.match_exact("12345\nabcde\n", "1[0-9]*5\na.*e\n") assert test.match_exact("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] @@ -1098,28 +1107,28 @@ sys.exit(0) ["1.*j\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], ["12345\n", "abcde\n", "fghij\n"]) - assert test.match_re_dotall(UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"]), + assert test.match_re_dotall(UserList(["12345\n", + "abcde\n", + "fghij\n"]), ["1[0-9]*5\n", "a.*e\n", "f.*j\n"]) - assert test.match_re_dotall(UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"]), + assert test.match_re_dotall(UserList(["12345\n", + "abcde\n", + "fghij\n"]), ["1.*j\n"]) - assert test.match_re_dotall(UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"]), + assert test.match_re_dotall(UserList(["12345\n", + "abcde\n", + "fghij\n"]), ["12345\n", "abcde\n", "fghij\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList.UserList(["1[0-9]*5\n", - "a.*e\n", - "f.*j\n"])) + UserList(["1[0-9]*5\n", + "a.*e\n", + "f.*j\n"])) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList.UserList(["1.*j\n"])) + UserList(["1.*j\n"])) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"])) + UserList(["12345\n", + "abcde\n", + "fghij\n"])) assert test.match_re_dotall("12345\nabcde\nfghij\n", "1[0-9]*5\na.*e\nf.*j\n") assert test.match_re_dotall("12345\nabcde\nfghij\n", "1.*j\n") @@ -1176,14 +1185,14 @@ sys.exit(0) assert test.match_re("abcde\n", "abcde\n") assert test.match_re(["12345\n", "abcde\n"], ["1[0-9]*5\n", "a.*e\n"]) assert test.match_re(["12345\n", "abcde\n"], ["12345\n", "abcde\n"]) - assert test.match_re(UserList.UserList(["12345\n", "abcde\n"]), + assert test.match_re(UserList(["12345\n", "abcde\n"]), ["1[0-9]*5\n", "a.*e\n"]) - assert test.match_re(UserList.UserList(["12345\n", "abcde\n"]), + assert test.match_re(UserList(["12345\n", "abcde\n"]), ["12345\n", "abcde\n"]) assert test.match_re(["12345\n", "abcde\n"], - UserList.UserList(["1[0-9]*5\n", "a.*e\n"])) + UserList(["1[0-9]*5\n", "a.*e\n"])) assert test.match_re(["12345\n", "abcde\n"], - UserList.UserList(["12345\n", "abcde\n"])) + UserList(["12345\n", "abcde\n"])) assert test.match_re("12345\nabcde\n", "1[0-9]*5\na.*e\n") assert test.match_re("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] @@ -1463,7 +1472,7 @@ class preserve_TestCase(TestCmdTestCase): def test_preserve(self): """Test preserve()""" def cleanup_test(test, cond=None, stdout=""): - io = StringIO.StringIO() + io = StringIO() save = sys.stdout sys.stdout = io try: @@ -1603,7 +1612,7 @@ class read_TestCase(TestCmdTestCase): _file_matches(wdir_foo_file3, test.read(['foo', 'file3']), "Test\nfile\n#3.\n") _file_matches(wdir_foo_file3, - test.read(UserList.UserList(['foo', 'file3'])), + test.read(UserList(['foo', 'file3'])), "Test\nfile\n#3.\n") _file_matches(wdir_file4, test.read('file4', mode = 'r'), "Test\nfile\n#4.\n") @@ -1862,8 +1871,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 1) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() test.run(arguments = ['arg1 arg2']) o = sys.stdout.getvalue() @@ -1876,8 +1885,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 1) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() testx.run(arguments = ['arg1 arg2']) expect = '"%s" "arg1 arg2"\n' % t.scriptx_path @@ -1913,8 +1922,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 2) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() test.run(arguments = ['arg1 arg2']) @@ -1934,8 +1943,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 2) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() testx.run(arguments = ['arg1 arg2']) @@ -1958,8 +1967,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 2) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() test.run(arguments = ['arg1 arg2']) @@ -1978,8 +1987,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 3) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() test.run(arguments = ['arg1 arg2']) @@ -2002,8 +2011,8 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '') - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() test.run(arguments = ['arg1 arg2']) @@ -2022,8 +2031,8 @@ class run_verbose_TestCase(TestCmdTestCase): testx = TestCmd.TestCmd(program = t.scriptx, workdir = '') - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() testx.run(arguments = ['arg1 arg2']) @@ -2048,8 +2057,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 1) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() test.run(arguments = ['arg1 arg2']) o = sys.stdout.getvalue() @@ -2062,8 +2071,8 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 1) - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() + sys.stdout = StringIO() + sys.stderr = StringIO() testx.run(arguments = ['arg1 arg2']) expect = '"%s" "arg1 arg2"\n' % t.scriptx_path @@ -2347,7 +2356,7 @@ while 1: logfp.close() """ % t.recv_out_path t.run_env.write(t.recv_script_path, text) - os.chmod(t.recv_script_path, 0644) # XXX UNIX-specific + os.chmod(t.recv_script_path, 0o644) # XXX UNIX-specific return t def test_start(self): @@ -2765,11 +2774,11 @@ class subdir_TestCase(TestCmdTestCase): assert test.subdir('bar') == 1 assert test.subdir(['foo', 'succeed']) == 1 if os.name != "nt": - os.chmod(test.workpath('foo'), 0500) + os.chmod(test.workpath('foo'), 0o500) assert test.subdir(['foo', 'fail']) == 0 assert test.subdir(['sub', 'dir', 'ectory'], 'sub') == 1 assert test.subdir('one', - UserList.UserList(['one', 'two']), + UserList(['one', 'two']), ['one', 'two', 'three']) == 3 assert os.path.isdir(test.workpath('foo')) assert os.path.isdir(test.workpath('bar')) @@ -2962,7 +2971,7 @@ class unlink_TestCase(TestCmdTestCase): test.unlink(['foo', 'file3a']) assert not os.path.exists(wdir_foo_file3a) - test.unlink(UserList.UserList(['foo', 'file3b'])) + test.unlink(UserList(['foo', 'file3b'])) assert not os.path.exists(wdir_foo_file3b) test.unlink([test.workdir, 'foo', 'file4']) @@ -2971,8 +2980,8 @@ class unlink_TestCase(TestCmdTestCase): # Make it so we can't unlink file5. # For UNIX, remove write permission from the dir and the file. # For Windows, open the file. - os.chmod(test.workdir, 0500) - os.chmod(wdir_file5, 0400) + os.chmod(test.workdir, 0o500) + os.chmod(wdir_file5, 0o400) f = open(wdir_file5, 'r') try: @@ -2983,8 +2992,8 @@ class unlink_TestCase(TestCmdTestCase): except: raise finally: - os.chmod(test.workdir, 0700) - os.chmod(wdir_file5, 0600) + os.chmod(test.workdir, 0o700) + os.chmod(wdir_file5, 0o600) f.close() @@ -3208,11 +3217,11 @@ class executable_TestCase(TestCmdTestCase): def make_executable(fname): st = os.stat(fname) - os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0100)) + os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0o100)) def make_non_executable(fname): st = os.stat(fname) - os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0100)) + os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0o100)) test.executable(test.workdir, 0) # XXX skip these tests if euid == 0? @@ -3282,7 +3291,7 @@ class write_TestCase(TestCmdTestCase): test.write('file9', "Test file #9.\r\n", mode = 'wb') if os.name != "nt": - os.chmod(test.workdir, 0500) + os.chmod(test.workdir, 0o500) try: test.write('file10', "Test file #10 (should not get created).\n") except IOError: # expect "Permission denied" diff --git a/QMTest/TestCommon.py b/QMTest/TestCommon.py index 4e90e168..f1a7407a 100644 --- a/QMTest/TestCommon.py +++ b/QMTest/TestCommon.py @@ -90,6 +90,7 @@ The TestCommon module also provides the following variables # PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, # AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +from __future__ import print_function __author__ = "Steven Knight <knight at baldmt dot com>" __revision__ = "TestCommon.py 1.3.D001 2010/06/03 12:58:27 knight" @@ -281,9 +282,9 @@ class TestCommon(TestCmd): existing, missing = separate_files(files) unwritable = [x for x in existing if not is_writable(x)] if missing: - print "Missing files: `%s'" % "', `".join(missing) + print("Missing files: `%s'" % "', `".join(missing)) if unwritable: - print "Unwritable files: `%s'" % "', `".join(unwritable) + print("Unwritable files: `%s'" % "', `".join(unwritable)) self.fail_test(missing + unwritable) def must_contain(self, file, required, mode = 'rb', find = None): @@ -298,11 +299,11 @@ class TestCommon(TestCmd): return None contains = find(file_contents, required) if not contains: - print "File `%s' does not contain required string." % file - print self.banner('Required string ') - print required - print self.banner('%s contents ' % file) - print file_contents + print("File `%s' does not contain required string." % file) + print(self.banner('Required string ')) + print(required) + print(self.banner('%s contents ' % file)) + print(file_contents) self.fail_test(not contains) def must_contain_all_lines(self, output, lines, title=None, find=None): @@ -437,7 +438,7 @@ class TestCommon(TestCmd): files = [is_List(x) and os.path.join(*x) or x for x in files] missing = [x for x in files if not os.path.exists(x) and not os.path.islink(x) ] if missing: - print "Missing files: `%s'" % "', `".join(missing) + print("Missing files: `%s'" % "', `".join(missing)) self.fail_test(missing) def must_exist_one_of(self, files): @@ -457,7 +458,7 @@ class TestCommon(TestCmd): if glob.glob(xpath): return missing.append(xpath) - print "Missing one of: `%s'" % "', `".join(missing) + print("Missing one of: `%s'" % "', `".join(missing)) self.fail_test(missing) def must_match(self, file, expect, mode = 'rb', match=None): @@ -474,7 +475,7 @@ class TestCommon(TestCmd): except KeyboardInterrupt: raise except: - print "Unexpected contents of `%s'" % file + print("Unexpected contents of `%s'" % file) self.diff(expect, file_contents, 'contents ') raise @@ -490,11 +491,11 @@ class TestCommon(TestCmd): return None contains = find(file_contents, banned) if contains: - print "File `%s' contains banned string." % file - print self.banner('Banned string ') - print banned - print self.banner('%s contents ' % file) - print file_contents + print("File `%s' contains banned string." % file) + print(self.banner('Banned string ')) + print(banned) + print(self.banner('%s contents ' % file)) + print(file_contents) self.fail_test(contains) def must_not_contain_any_line(self, output, lines, title=None, find=None): @@ -541,7 +542,7 @@ class TestCommon(TestCmd): files = [is_List(x) and os.path.join(*x) or x for x in files] existing = [x for x in files if os.path.exists(x) or os.path.islink(x)] if existing: - print "Unexpected files exist: `%s'" % "', `".join(existing) + print("Unexpected files exist: `%s'" % "', `".join(existing)) self.fail_test(existing) def must_not_exist_any_of(self, files): @@ -561,7 +562,7 @@ class TestCommon(TestCmd): if glob.glob(xpath): existing.append(xpath) if existing: - print "Unexpected files exist: `%s'" % "', `".join(existing) + print("Unexpected files exist: `%s'" % "', `".join(existing)) self.fail_test(existing) def must_not_be_writable(self, *files): @@ -575,9 +576,9 @@ class TestCommon(TestCmd): existing, missing = separate_files(files) writable = list(filter(is_writable, existing)) if missing: - print "Missing files: `%s'" % "', `".join(missing) + print("Missing files: `%s'" % "', `".join(missing)) if writable: - print "Writable files: `%s'" % "', `".join(writable) + print("Writable files: `%s'" % "', `".join(writable)) self.fail_test(missing + writable) def _complete(self, actual_stdout, expected_stdout, @@ -590,23 +591,23 @@ class TestCommon(TestCmd): expect = '' if status != 0: expect = " (expected %s)" % str(status) - print "%s returned %s%s" % (self.program, _status(self), expect) - print self.banner('STDOUT ') - print actual_stdout - print self.banner('STDERR ') - print actual_stderr + print("%s returned %s%s" % (self.program, _status(self), expect)) + print(self.banner('STDOUT ')) + print(actual_stdout) + print(self.banner('STDERR ')) + print(actual_stderr) self.fail_test() if (expected_stdout is not None and not match(actual_stdout, expected_stdout)): self.diff(expected_stdout, actual_stdout, 'STDOUT ') if actual_stderr: - print self.banner('STDERR ') - print actual_stderr + print(self.banner('STDERR ')) + print(actual_stderr) self.fail_test() if (expected_stderr is not None and not match(actual_stderr, expected_stderr)): - print self.banner('STDOUT ') - print actual_stdout + print(self.banner('STDOUT ')) + print(actual_stdout) self.diff(expected_stderr, actual_stderr, 'STDERR ') self.fail_test() @@ -626,15 +627,15 @@ class TestCommon(TestCmd): universal_newlines, **kw) except KeyboardInterrupt: raise - except Exception, e: - print self.banner('STDOUT ') + except Exception as e: + print(self.banner('STDOUT ')) try: - print self.stdout() + print(self.stdout()) except IndexError: pass - print self.banner('STDERR ') + print(self.banner('STDERR ')) try: - print self.stderr() + print(self.stderr()) except IndexError: pass cmd_args = self.command_args(program, interpreter, arguments) diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py index 57b97f99..ce20ec53 100644 --- a/QMTest/TestSCons.py +++ b/QMTest/TestSCons.py @@ -13,7 +13,7 @@ attributes defined in this subclass. """ # __COPYRIGHT__ -from __future__ import division +from __future__ import division, print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -354,7 +354,7 @@ class TestSCons(TestCommon): # raised so as to not mask possibly serious disk or # network issues. continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return os.path.normpath(f) else: import SCons.Environment @@ -501,9 +501,9 @@ class TestSCons(TestCommon): self.pass_test() else: # test failed; have to do this by hand... - print self.banner('STDOUT ') - print self.stdout() - print self.diff(warning, stderr, 'STDERR ') + print(self.banner('STDOUT ')) + print(self.stdout()) + print(self.diff(warning, stderr, 'STDERR ')) self.fail_test() return warning @@ -572,7 +572,7 @@ class TestSCons(TestCommon): We stick the requested file name and line number in the right places, abstracting out the version difference. """ - exec 'import traceback; x = traceback.format_stack()[-1]' + exec('import traceback; x = traceback.format_stack()[-1]') x = x.lstrip() x = x.replace('<string>', file) x = x.replace('line 1,', 'line %s,' % line) @@ -1011,7 +1011,7 @@ SConscript( sconscript ) raise NoMatch(lastEnd) return m.end() + lastEnd try: - #print len(os.linesep) + #print(len(os.linesep)) ls = os.linesep nols = "(" for i in range(len(ls)): @@ -1085,27 +1085,27 @@ SConscript( sconscript ) if doCheckLog and lastEnd != len(logfile): raise NoMatch(lastEnd) - except NoMatch, m: - print "Cannot match log file against log regexp." - print "log file: " - print "------------------------------------------------------" - print logfile[m.pos:] - print "------------------------------------------------------" - print "log regexp: " - print "------------------------------------------------------" - print log - print "------------------------------------------------------" + except NoMatch as m: + print("Cannot match log file against log regexp.") + print("log file: ") + print("------------------------------------------------------") + print(logfile[m.pos:]) + print("------------------------------------------------------") + print("log regexp: ") + print("------------------------------------------------------") + print(log) + print("------------------------------------------------------") self.fail_test() if doCheckStdout: exp_stdout = self.wrap_stdout(".*", rdstr) if not self.match_re_dotall(self.stdout(), exp_stdout): - print "Unexpected stdout: " - print "-----------------------------------------------------" - print repr(self.stdout()) - print "-----------------------------------------------------" - print repr(exp_stdout) - print "-----------------------------------------------------" + print("Unexpected stdout: ") + print("-----------------------------------------------------") + print(repr(self.stdout())) + print("-----------------------------------------------------") + print(repr(exp_stdout)) + print("-----------------------------------------------------") self.fail_test() def get_python_version(self): diff --git a/QMTest/TestSConsMSVS.py b/QMTest/TestSConsMSVS.py index c78b4523..478438ad 100644 --- a/QMTest/TestSConsMSVS.py +++ b/QMTest/TestSConsMSVS.py @@ -1039,7 +1039,7 @@ print "self._msvs_versions =", str(SCons.Tool.MSCommon.query_versions()) try: host = _ARCH_TO_CANONICAL[host_platform] - except KeyError, e: + except KeyError as e: # Default to x86 for all other platforms host = 'x86' diff --git a/QMTest/TestSCons_time.py b/QMTest/TestSCons_time.py index abe8ccf1..ba7fbd8d 100644 --- a/QMTest/TestSCons_time.py +++ b/QMTest/TestSCons_time.py @@ -225,7 +225,7 @@ class TestSCons_time(TestCommon): def write_fake_aegis_py(self, name): name = self.workpath(name) self.write(name, aegis_py) - os.chmod(name, 0755) + os.chmod(name, 0o755) return name def write_fake_scons_py(self): @@ -235,7 +235,7 @@ class TestSCons_time(TestCommon): def write_fake_svn_py(self, name): name = self.workpath(name) self.write(name, svn_py) - os.chmod(name, 0755) + os.chmod(name, 0o755) return name def write_sample_directory(self, archive, dir, files): diff --git a/QMTest/TestSConsign.py b/QMTest/TestSConsign.py index 700c242c..a48b6484 100644 --- a/QMTest/TestSConsign.py +++ b/QMTest/TestSConsign.py @@ -1,4 +1,5 @@ # __COPYRIGHT__ +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -68,7 +69,7 @@ class TestSConsign(TestSCons): elif os.path.exists(self.script_path('sconsign')): sconsign = 'sconsign' else: - print "Can find neither 'sconsign.py' nor 'sconsign' scripts." + print("Can find neither 'sconsign.py' nor 'sconsign' scripts.") self.no_result() self.set_sconsign(sconsign) diff --git a/QMTest/scons_tdb.py b/QMTest/scons_tdb.py index 6be4696b..76c7fe10 100644 --- a/QMTest/scons_tdb.py +++ b/QMTest/scons_tdb.py @@ -20,7 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import division +from __future__ import division, print_function """ QMTest classes to support SCons' testing and Aegis-inspired workflow. @@ -337,14 +337,14 @@ class AegisChangeStream(AegisStream): # We'd like to use the _FormatStatistics() method to do # this, but it's wrapped around the list in Result.outcomes, # so it's simpler to just do it ourselves. - print " %6d tests total\n" % self._num_tests + print(" %6d tests total\n" % self._num_tests) for outcome in AegisTest.aegis_outcomes: if self._outcome_counts[outcome] != 0: - print " %6d (%3.0f%%) tests %s" % ( + print(" %6d (%3.0f%%) tests %s" % ( self._outcome_counts[outcome], self._percent(outcome), outcome - ) + )) class AegisBaselineStream(AegisStream): def WriteResult(self, result): @@ -368,19 +368,19 @@ class AegisBaselineStream(AegisStream): # this, but it's wrapped around the list in Result.outcomes, # so it's simpler to just do it ourselves. if self._outcome_counts[AegisTest.FAIL]: - print " %6d (%3.0f%%) tests as expected" % ( + print(" %6d (%3.0f%%) tests as expected" % ( self._outcome_counts[AegisTest.FAIL], self._percent(AegisTest.FAIL), - ) + )) non_fail_outcomes = list(AegisTest.aegis_outcomes[:]) non_fail_outcomes.remove(AegisTest.FAIL) for outcome in non_fail_outcomes: if self._outcome_counts[outcome] != 0: - print " %6d (%3.0f%%) tests unexpected %s" % ( + print(" %6d (%3.0f%%) tests unexpected %s" % ( self._outcome_counts[outcome], self._percent(outcome), outcome, - ) + )) class AegisBatchStream(FileResultStream): def __init__(self, arguments): @@ -2,6 +2,7 @@ # SConstruct file to build scons packages during development. # # See the README.rst file for an overview of how SCons is built and tested. +from __future__ import print_function copyright_years = '2001 - 2014' @@ -67,7 +68,7 @@ def whereis(file): st = os.stat(f_ext) except: continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return f_ext return None @@ -325,7 +326,7 @@ try: import zipfile def zipit(env, target, source): - print "Zipping %s:" % str(target[0]) + print("Zipping %s:" % str(target[0])) def visit(arg, dirname, names): for name in names: path = os.path.join(dirname, name) @@ -339,7 +340,7 @@ try: zf.close() def unzipit(env, target, source): - print "Unzipping %s:" % str(source[0]) + print("Unzipping %s:" % str(source[0])) zf = zipfile.ZipFile(str(source[0]), 'r') for name in zf.namelist(): dest = os.path.join(env['UNPACK_ZIP_DIR'], name) @@ -348,7 +349,7 @@ try: os.makedirs(dir) except: pass - print dest,name + print(dest,name) # if the file exists, then delete it before writing # to it so that we don't end up trying to write to a symlink: if os.path.isfile(dest) or os.path.islink(dest): @@ -369,7 +370,7 @@ def SCons_revision(target, source, env): """ t = str(target[0]) s = source[0].rstr() - contents = open(s, 'rb').read() + contents = open(s, 'r').read() # Note: We construct the __*__ substitution strings here # so that they don't get replaced when this file gets # copied into the tree for packaging. @@ -383,7 +384,7 @@ 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 @@ -556,7 +557,7 @@ else: i = install_egg_info(dist) i.finalize_options() import os.path - print os.path.split(i.outputs[0])[1] + print(os.path.split(i.outputs[0])[1]) """ % version try: @@ -848,10 +849,10 @@ for p in [ scons ]: dist_distutils_targets = env.Install('$DISTDIR', distutils_targets) Local(dist_distutils_targets) - AddPostAction(dist_distutils_targets, Chmod(dist_distutils_targets, 0644)) + AddPostAction(dist_distutils_targets, Chmod(dist_distutils_targets, 0o644)) if not gzip: - print "gzip not found in %s; skipping .tar.gz package for %s." % (os.environ['PATH'], pkg) + print("gzip not found in %s; skipping .tar.gz package for %s." % (os.environ['PATH'], pkg)) else: distutils_formats.append('gztar') @@ -863,8 +864,8 @@ for p in [ scons ]: dist_tar_gz = env.Install('$DISTDIR', tar_gz) dist_platform_tar_gz = env.Install('$DISTDIR', platform_tar_gz) Local(dist_tar_gz, dist_platform_tar_gz) - AddPostAction(dist_tar_gz, Chmod(dist_tar_gz, 0644)) - AddPostAction(dist_platform_tar_gz, Chmod(dist_platform_tar_gz, 0644)) + AddPostAction(dist_tar_gz, Chmod(dist_tar_gz, 0o644)) + AddPostAction(dist_platform_tar_gz, Chmod(dist_platform_tar_gz, 0o644)) # # Unpack the tar.gz archive created by the distutils into @@ -926,7 +927,7 @@ for p in [ scons ]: env.Command(digest, tar_gz, Digestify) if not zipit: - print "zip not found; skipping .zip package for %s." % pkg + print("zip not found; skipping .zip package for %s." % pkg) else: distutils_formats.append('zip') @@ -938,8 +939,8 @@ for p in [ scons ]: dist_zip = env.Install('$DISTDIR', zip) dist_platform_zip = env.Install('$DISTDIR', platform_zip) Local(dist_zip, dist_platform_zip) - AddPostAction(dist_zip, Chmod(dist_zip, 0644)) - AddPostAction(dist_platform_zip, Chmod(dist_platform_zip, 0644)) + AddPostAction(dist_zip, Chmod(dist_zip, 0o644)) + AddPostAction(dist_platform_zip, Chmod(dist_platform_zip, 0o644)) # # Unpack the zip archive created by the distutils into @@ -1026,8 +1027,8 @@ for p in [ scons ]: dist_noarch_rpm = env.Install('$DISTDIR', noarch_rpm) dist_src_rpm = env.Install('$DISTDIR', src_rpm) Local(dist_noarch_rpm, dist_src_rpm) - AddPostAction(dist_noarch_rpm, Chmod(dist_noarch_rpm, 0644)) - AddPostAction(dist_src_rpm, Chmod(dist_src_rpm, 0644)) + AddPostAction(dist_noarch_rpm, Chmod(dist_noarch_rpm, 0o644)) + AddPostAction(dist_src_rpm, Chmod(dist_src_rpm, 0o644)) dfiles = [os.path.join(test_rpm_dir, 'usr', x) for x in dst_files] env.Command(dfiles, @@ -1097,8 +1098,8 @@ for p in [ scons ]: dist_local_tar_gz = os.path.join("$DISTDIR/%s.tar.gz" % s_l_v) dist_local_zip = os.path.join("$DISTDIR/%s.zip" % s_l_v) - AddPostAction(dist_local_tar_gz, Chmod(dist_local_tar_gz, 0644)) - AddPostAction(dist_local_zip, Chmod(dist_local_zip, 0644)) + AddPostAction(dist_local_tar_gz, Chmod(dist_local_tar_gz, 0o644)) + AddPostAction(dist_local_zip, Chmod(dist_local_zip, 0o644)) commands = [ Delete(build_dir_local), @@ -1212,7 +1213,7 @@ elif svn_status_lines: sentries = [l.split()[-1] for l in slines] sfiles = list(filter(os.path.isfile, sentries)) else: - print "Not building in a Mercurial or Subversion tree; skipping building src package." + print("Not building in a Mercurial or Subversion tree; skipping building src package.") if sfiles: remove_patterns = [ diff --git a/bench/bench.py b/bench/bench.py index 74dbf121..f1d18c61 100644 --- a/bench/bench.py +++ b/bench/bench.py @@ -23,7 +23,7 @@ # # This will allow (as much as possible) us to time just the code itself, # not Python function call overhead. -from __future__ import division +from __future__ import division, print_function import getopt import sys @@ -113,12 +113,12 @@ def display(label, results): total = 0.0 for r in results: total += r - print " %8.3f" % ((total * 1e6) / len(results)), ':', label + print(" %8.3f" % ((total * 1e6) / len(results)), ':', label) for func in FunctionList: if func.__doc__: d = ' (' + func.__doc__ + ')' else: d = '' - print func.__name__ + d + ':' + print(func.__name__ + d + ':') for label, args, kw in Data: r = timer(func, *args, **kw) diff --git a/bench/env.__setitem__.py b/bench/env.__setitem__.py index b17b59e4..9c27b6d5 100644 --- a/bench/env.__setitem__.py +++ b/bench/env.__setitem__.py @@ -38,10 +38,10 @@ def times(num=1000000, init='', title='Results:', **statements): t.timeit() timings.append(t) - print - print title + print() + print(title) for i in sorted([(i.getResult(),i.name) for i in timings]): - print " %9.3f s %s" % i + print(" %9.3f s %s" % i) # Import the necessary local SCons.* modules used by some of our # alternative implementations below, first manipulating sys.path so @@ -339,9 +339,9 @@ def run_it(title, init): s['init'] = init times(**s) -print 'Environment __setitem__ benchmark using', -print 'Python', sys.version.split()[0], -print 'on', sys.platform, os.name +print('Environment __setitem__ benchmark using', end=' ') +print('Python', sys.version.split()[0], end=' ') +print('on', sys.platform, os.name) run_it('Results for re-adding an existing variable name 100 times:', common_imports + """ diff --git a/bench/timeit.py b/bench/timeit.py index c5fef126..7db0dd4f 100644 --- a/bench/timeit.py +++ b/bench/timeit.py @@ -46,7 +46,7 @@ be aware of it. The baseline overhead can be measured by invoking the program without arguments. The baseline overhead differs between Python versions! """ -from __future__ import division +from __future__ import division, print_function try: import gc @@ -122,7 +122,7 @@ class Timer(object): self.src = src # Save for traceback display code = compile(src, dummy_src_name, "exec") ns = {} - exec code in globals(), ns + exec(code, globals(), ns) self.inner = ns["inner"] def print_exc(self, file=None): @@ -216,9 +216,9 @@ def main(args=None): opts, args = getopt.getopt(args, "n:s:r:tcvh", ["number=", "setup=", "repeat=", "time", "clock", "verbose", "help"]) - except getopt.error, err: - print err - print "use -h/--help for command line help" + except getopt.error as err: + print(err) + print("use -h/--help for command line help") return 2 timer = default_timer stmt = "\n".join(args) or "pass" @@ -245,7 +245,7 @@ def main(args=None): precision = precision + 1 verbose = precision + 1 if o in ("-h", "--help"): - print __doc__, + print(__doc__) return 0 setup = "\n".join(setup) or "pass" # Include the current directory, so that local imports work (sys.path @@ -264,7 +264,7 @@ def main(args=None): t.print_exc() return 1 if verbose: - print "%d loops -> %.*g secs" % (number, precision, x) + print("%d loops -> %.*g secs" % (number, precision, x)) if x >= 0.2: break try: @@ -274,18 +274,18 @@ def main(args=None): return 1 best = min(r) if verbose: - print "raw times:", ' '.join(["%.*g" % (precision, x) for x in r]) - print "%d loops," % number, + print("raw times:", ' '.join(["%.*g" % (precision, x) for x in r])) + print("%d loops," % number, end=' ') usec = best * 1e6 / number if usec < 1000: - print "best of %d: %.*g usec per loop" % (repeat, precision, usec) + print("best of %d: %.*g usec per loop" % (repeat, precision, usec)) else: msec = usec / 1000 if msec < 1000: - print "best of %d: %.*g msec per loop" % (repeat, precision, msec) + print("best of %d: %.*g msec per loop" % (repeat, precision, msec)) else: sec = msec / 1000 - print "best of %d: %.*g sec per loop" % (repeat, precision, sec) + print("best of %d: %.*g sec per loop" % (repeat, precision, sec)) return None if __name__ == "__main__": diff --git a/bin/Command.py b/bin/Command.py index 8702f51d..dadd7a9e 100644 --- a/bin/Command.py +++ b/bin/Command.py @@ -4,6 +4,7 @@ # # XXX Describe what the script does here. # +from __future__ import print_function import getopt import os @@ -109,18 +110,18 @@ Usage: script-template.py [-hnq] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: if o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): Command.execute = Command.do_not_execute elif o in ('-q', '--quiet'): Command.display = Command.do_not_display - except Usage, err: + except Usage as err: sys.stderr.write(err.msg) sys.stderr.write('use -h to get help') return 2 diff --git a/bin/SConsDoc.py b/bin/SConsDoc.py index e1c2b0bb..0d74a36e 100644 --- a/bin/SConsDoc.py +++ b/bin/SConsDoc.py @@ -24,6 +24,7 @@ # # Module for handling SCons documentation processing. # +from __future__ import print_function __doc__ = """ This module parses home-brew XML files that document various things @@ -51,7 +52,7 @@ Builder example: to indicate a new paragraph. <example> - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") </example> </summary> </builder> @@ -71,7 +72,7 @@ Function example: &f-FUNCTION; element. It need not be on a line by itself.</para> <example> - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") </example> </summary> </scons_function> @@ -88,7 +89,7 @@ Construction variable example: &t-VARIABLE; element. It need not be on a line by itself.</para> <example> - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") </example> </summary> </cvar> @@ -105,7 +106,7 @@ Tool example: &t-TOOL; element. It need not be on a line by itself.</para> <example> - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") </example> </summary> </tool> @@ -210,12 +211,12 @@ class Libxml2ValidityHandler: def error(self, msg, data): if data != ARG: - raise Exception, "Error handler did not receive correct argument" + raise Exception("Error handler did not receive correct argument") self.errors.append(msg) def warning(self, msg, data): if data != ARG: - raise Exception, "Warning handler did not receive correct argument" + raise Exception("Warning handler did not receive correct argument") self.warnings.append(msg) @@ -332,16 +333,16 @@ if not has_libxml2: xmlschema = etree.XMLSchema(xmlschema_context) try: doc = etree.parse(fpath) - except Exception, e: - print "ERROR: %s fails to parse:"%fpath - print e + except Exception as e: + print("ERROR: %s fails to parse:"%fpath) + print(e) return False doc.xinclude() try: xmlschema.assertValid(doc) - except Exception, e: - print "ERROR: %s fails to validate:" % fpath - print e + except Exception as e: + print("ERROR: %s fails to validate:" % fpath) + print(e) return False return True @@ -477,8 +478,8 @@ else: if err or eh.errors: for e in eh.errors: - print e.rstrip("\n") - print "%s fails to validate" % fpath + print(e.rstrip("\n")) + print("%s fails to validate" % fpath) return False return True @@ -599,7 +600,7 @@ class SConsDocTree: # Create xpath context self.xpath_context = self.doc.xpathNewContext() # Register namespaces - for key, val in self.nsmap.iteritems(): + for key, val in self.nsmap.items(): self.xpath_context.xpathRegisterNs(key, val) def __del__(self): @@ -637,8 +638,8 @@ def validate_all_xml(dpaths, xsdfile=default_xsd): fails = [] for idx, fp in enumerate(fpaths): fpath = os.path.join(path, fp) - print "%.2f%s (%d/%d) %s" % (float(idx+1)*100.0/float(len(fpaths)), - perc, idx+1, len(fpaths),fp) + print("%.2f%s (%d/%d) %s" % (float(idx+1)*100.0/float(len(fpaths)), + perc, idx+1, len(fpaths),fp)) if not tf.validateXml(fp, xmlschema_context): fails.append(fp) @@ -667,8 +668,10 @@ class Item(object): if name[0] == '_': name = name[1:] return name.lower() - def __cmp__(self, other): - return cmp(self.sort_name, other.sort_name) + def __eq__(self, other): + return self.sort_name == other.sort_name + def __lt__(self, other): + return self.sort_name < other.sort_name class Builder(Item): pass @@ -810,7 +813,7 @@ def importfile(path): file = open(path, 'r') try: module = imp.load_module(name, file, path, (ext, 'r', kind)) - except ImportError, e: + except ImportError as e: sys.stderr.write("Could not import %s: %s\n" % (path, e)) return None file.close() diff --git a/bin/SConsExamples.py b/bin/SConsExamples.py index 9823a052..e3a7502a 100644 --- a/bin/SConsExamples.py +++ b/bin/SConsExamples.py @@ -265,7 +265,7 @@ def ensureExampleOutputsExist(dpath): os.mkdir(generated_examples) examples = readAllExampleInfos(dpath) - for key, value in examples.iteritems(): + for key, value in examples.items(): # Process all scons_output tags for o in value.outputs: cpath = os.path.join(generated_examples, @@ -303,10 +303,10 @@ def createAllExampleOutputs(dpath): examples = readAllExampleInfos(dpath) total = len(examples) idx = 0 - for key, value in examples.iteritems(): + for key, value in examples.items(): # Process all scons_output tags - print "%.2f%s (%d/%d) %s" % (float(idx + 1) * 100.0 / float(total), - perc, idx + 1, total, key) + print("%.2f%s (%d/%d) %s" % (float(idx + 1) * 100.0 / float(total), + perc, idx + 1, total, key)) create_scons_output(value) # Process all scons_example_file tags @@ -344,7 +344,7 @@ def collectSConsExampleNames(fpath): if n not in suffixes: suffixes[n] = [] else: - print "Error: Example in file '%s' is missing a name!" % fpath + print("Error: Example in file '%s' is missing a name!" % fpath) failed_suffixes = True for o in stf.findAll(t.root, "scons_output", SConsDoc.dbxid, @@ -353,11 +353,11 @@ def collectSConsExampleNames(fpath): if stf.hasAttribute(o, 'example'): n = stf.getAttribute(o, 'example') else: - print "Error: scons_output in file '%s' is missing an example name!" % fpath + print("Error: scons_output in file '%s' is missing an example name!" % fpath) failed_suffixes = True if n not in suffixes: - print "Error: scons_output in file '%s' is referencing non-existent example '%s'!" % (fpath, n) + print("Error: scons_output in file '%s' is referencing non-existent example '%s'!" % (fpath, n)) failed_suffixes = True continue @@ -365,13 +365,13 @@ def collectSConsExampleNames(fpath): if stf.hasAttribute(o, 'suffix'): s = stf.getAttribute(o, 'suffix') else: - print "Error: scons_output in file '%s' (example '%s') is missing a suffix!" % (fpath, n) + print("Error: scons_output in file '%s' (example '%s') is missing a suffix!" % (fpath, n)) failed_suffixes = True if s not in suffixes[n]: suffixes[n].append(s) else: - print "Error: scons_output in file '%s' (example '%s') is using a duplicate suffix '%s'!" % (fpath, n, s) + print("Error: scons_output in file '%s' (example '%s') is using a duplicate suffix '%s'!" % (fpath, n, s)) failed_suffixes = True return names, failed_suffixes @@ -392,7 +392,7 @@ def exampleNamesAreUnique(dpath): unique = False i = allnames.intersection(names) if i: - print "Not unique in %s are: %s" % (fpath, ', '.join(i)) + print("Not unique in %s are: %s" % (fpath, ', '.join(i))) unique = False allnames |= names diff --git a/bin/calibrate.py b/bin/calibrate.py index 8ed2ecea..3f9104e1 100644 --- a/bin/calibrate.py +++ b/bin/calibrate.py @@ -20,7 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import division +from __future__ import division, print_function import optparse import os @@ -48,7 +48,7 @@ def main(argv=None): for arg in args: if len(args) > 1: - print arg + ':' + print(arg + ':') command = [sys.executable, 'runtest.py'] if opts.package: @@ -67,9 +67,9 @@ def main(argv=None): try: elapsed = float(em.group(1)) except AttributeError: - print output + print(output) raise - print "run %3d: %7.3f: %s" % (run, elapsed, ' '.join(vm.groups())) + print("run %3d: %7.3f: %s" % (run, elapsed, ' '.join(vm.groups()))) if opts.min < elapsed and elapsed < opts.max: good += 1 else: diff --git a/bin/caller-tree.py b/bin/caller-tree.py index 03c1616a..21cda4ba 100644 --- a/bin/caller-tree.py +++ b/bin/caller-tree.py @@ -39,6 +39,7 @@ # function at the same time, for example, their counts will intermix. # So use this to get a *general* idea of who's calling what, not for # fine-grained performance tuning. +from __future__ import print_function import sys @@ -74,17 +75,17 @@ for line in sys.stdin.readlines(): stack = [] def print_entry(e, level, calls): - print '%-72s%6s' % ((' '*2*level) + e.file_line_func, calls) + print('%-72s%6s' % ((' '*2*level) + e.file_line_func, calls)) if e in stack: - print (' '*2*(level+1))+'RECURSION' - print + print((' '*2*(level+1))+'RECURSION') + print() elif e.called_by: stack.append(e) for c in e.called_by: print_entry(c[0], level+1, c[1]) stack.pop() else: - print + print() for e in [ e for e in AllCalls.values() if not e.calls ]: print_entry(e, 0, '') diff --git a/bin/docs-create-example-outputs.py b/bin/docs-create-example-outputs.py index 30dc0eef..64dcf2e2 100644 --- a/bin/docs-create-example-outputs.py +++ b/bin/docs-create-example-outputs.py @@ -3,17 +3,18 @@ # Searches through the whole doc/user tree and creates # all output files for the single examples. # +from __future__ import print_function import os import sys import SConsExamples if __name__ == "__main__": - print "Checking whether all example names are unique..." + print("Checking whether all example names are unique...") if SConsExamples.exampleNamesAreUnique(os.path.join('doc','user')): - print "OK" + print("OK") else: - print "Not all example names and suffixes are unique! Please correct the errors listed above and try again." + print("Not all example names and suffixes are unique! Please correct the errors listed above and try again.") sys.exit(0) SConsExamples.createAllExampleOutputs(os.path.join('doc','user')) diff --git a/bin/docs-update-generated.py b/bin/docs-update-generated.py index 66b22c0b..d22cc32e 100644 --- a/bin/docs-update-generated.py +++ b/bin/docs-update-generated.py @@ -6,6 +6,7 @@ # as well as the entity declarations for them. # Uses scons-proc.py under the hood... # +from __future__ import print_function import os import SConsDoc @@ -38,7 +39,7 @@ def generate_all(): try: os.makedirs(gen_folder) except: - print "Couldn't create destination folder %s! Exiting..." % gen_folder + print("Couldn't create destination folder %s! Exiting..." % gen_folder) return # Call scons-proc.py os.system('python %s -b %s -f %s -t %s -v %s %s' % diff --git a/bin/docs-validate.py b/bin/docs-validate.py index c445c3f9..e53a89de 100644 --- a/bin/docs-validate.py +++ b/bin/docs-validate.py @@ -3,6 +3,7 @@ # Searches through the whole source tree and validates all # documentation files against our own XSD in docs/xsd. # +from __future__ import print_function import sys,os import SConsDoc @@ -10,9 +11,9 @@ import SConsDoc if __name__ == "__main__": if len(sys.argv)>1: if SConsDoc.validate_all_xml((sys.argv[1],)): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." + print("Validation failed! Please correct the errors above and try again.") else: if SConsDoc.validate_all_xml(['src', os.path.join('doc','design'), @@ -22,6 +23,6 @@ if __name__ == "__main__": os.path.join('doc','reference'), os.path.join('doc','user') ]): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." + print("Validation failed! Please correct the errors above and try again.") diff --git a/bin/install_python.py b/bin/install_python.py index 86807af6..5c947ac8 100644 --- a/bin/install_python.py +++ b/bin/install_python.py @@ -6,6 +6,7 @@ # This was written for a Linux system (specifically Ubuntu) but should # be reasonably generic to any POSIX-style system with a /usr/local # hierarchy. +from __future__ import print_function import getopt import os @@ -48,7 +49,7 @@ Usage: install_python.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: @@ -57,7 +58,7 @@ Usage: install_python.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] elif o in ('-d', '--downloads'): downloads_dir = a elif o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): CommandRunner.execute = CommandRunner.do_not_execute @@ -65,7 +66,7 @@ Usage: install_python.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] prefix = a elif o in ('-q', '--quiet'): CommandRunner.display = CommandRunner.do_not_display - except Usage, err: + except Usage as err: sys.stderr.write(str(err.msg) + '\n') sys.stderr.write('use -h to get help\n') return 2 diff --git a/bin/install_scons.py b/bin/install_scons.py index 00129f65..afd0789c 100644 --- a/bin/install_scons.py +++ b/bin/install_scons.py @@ -17,13 +17,19 @@ # This was written for a Linux system (specifically Ubuntu) but should # be reasonably generic to any POSIX-style system with a /usr/local # hierarchy. +from __future__ import print_function + +from six import PY3 import getopt import os import shutil import sys import tarfile -import urllib +if PY3: + from urllib.request import urlretrieve +else: + from urllib import urlretrieve from Command import CommandRunner, Usage @@ -129,7 +135,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: @@ -138,7 +144,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] elif o in ('-d', '--downloads'): downloads_dir = a elif o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): CommandRunner.execute = CommandRunner.do_not_execute @@ -146,7 +152,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] prefix = a elif o in ('-q', '--quiet'): CommandRunner.display = CommandRunner.do_not_display - except Usage, err: + except Usage as err: sys.stderr.write(str(err.msg) + '\n') sys.stderr.write('use -h to get help\n') return 2 @@ -171,7 +177,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] if not os.path.exists(tar_gz): if not os.path.exists(downloads_dir): cmd.run('mkdir %(downloads_dir)s') - cmd.run((urllib.urlretrieve, tar_gz_url, tar_gz), + cmd.run((urlretrieve, tar_gz_url, tar_gz), 'wget -O %(tar_gz)s %(tar_gz_url)s') def extract(tar_gz): diff --git a/bin/linecount.py b/bin/linecount.py index 6f49dcad..897f1e8f 100644 --- a/bin/linecount.py +++ b/bin/linecount.py @@ -21,7 +21,7 @@ # in each category, the number of non-blank lines, and the number of # non-comment lines. The last figure (non-comment) lines is the most # interesting one for most purposes. -from __future__ import division +from __future__ import division, print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -98,23 +98,23 @@ all_tests = Collection('all tests', src_tests.files + test_tests.files) def ratio(over, under): return "%.2f" % (float(len(over)) / float(len(under))) -print fmt % ('', '', '', '', '', 'non-blank') -print fmt % ('', 'files', 'lines', 'non-blank', 'non-comment', 'non-comment') -print -print fmt % src_Tests_py_tests.printables() -print fmt % src_test_tests.printables() -print -print fmt % src_tests.printables() -print fmt % test_tests.printables() -print -print fmt % all_tests.printables() -print fmt % sources.printables() -print -print fmt % ('ratio:', +print(fmt % ('', '', '', '', '', 'non-blank')) +print(fmt % ('', 'files', 'lines', 'non-blank', 'non-comment', 'non-comment')) +print() +print(fmt % src_Tests_py_tests.printables()) +print(fmt % src_test_tests.printables()) +print() +print(fmt % src_tests.printables()) +print(fmt % test_tests.printables()) +print() +print(fmt % all_tests.printables()) +print(fmt % sources.printables()) +print() +print(fmt % ('ratio:', ratio(all_tests, sources), ratio(all_tests.lines(), sources.lines()), ratio(all_tests.non_blank(), sources.non_blank()), ratio(all_tests.non_comment(), sources.non_comment()), ratio(all_tests.non_blank_non_comment(), sources.non_blank_non_comment()) - ) + )) diff --git a/bin/memlogs.py b/bin/memlogs.py index 9d957c9f..6e68ce07 100644 --- a/bin/memlogs.py +++ b/bin/memlogs.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from future import print_function import getopt import sys @@ -27,20 +28,20 @@ import sys filenames = sys.argv[1:] if not filenames: - print """Usage: memlogs.py file [...] + print("""Usage: memlogs.py file [...] Summarizes the --debug=memory numbers from one or more build logs. -""" +""") sys.exit(0) fmt = "%12s %12s %12s %12s %s" -print fmt % ("pre-read", "post-read", "pre-build", "post-build", "") +print(fmt % ("pre-read", "post-read", "pre-build", "post-build", "")) for fname in sys.argv[1:]: lines = [l for l in open(fname).readlines() if l[:7] == 'Memory '] t = tuple([l.split()[-1] for l in lines]) + (fname,) - print fmt % t + print(fmt % t) # Local Variables: # tab-width:4 diff --git a/bin/memoicmp.py b/bin/memoicmp.py index 812af665..1106ac3c 100644 --- a/bin/memoicmp.py +++ b/bin/memoicmp.py @@ -2,6 +2,7 @@ # # A script to compare the --debug=memoizer output found in # two different files. +from future import print_function import sys @@ -23,8 +24,8 @@ def memoize_cmp(filea, fileb): ma = memoize_output(filea) mb = memoize_output(fileb) - print 'All output: %s / %s [delta]'%(filea, fileb) - print '----------HITS---------- ---------MISSES---------' + print('All output: %s / %s [delta]'%(filea, fileb)) + print('----------HITS---------- ---------MISSES---------') cfmt='%7d/%-7d [%d]' ma_o = [] mb_o = [] @@ -49,26 +50,26 @@ def memoize_cmp(filea, fileb): for k in mab: hits = cfmt%(ma[k][0], mb[k][0], mb[k][0]-ma[k][0]) miss = cfmt%(ma[k][1], mb[k][1], mb[k][1]-ma[k][1]) - print '%-24s %-24s %s'%(hits, miss, k) + print('%-24s %-24s %s'%(hits, miss, k)) for k in ma_o: hits = '%7d/ --'%(ma[k][0]) miss = '%7d/ --'%(ma[k][1]) - print '%-24s %-24s %s'%(hits, miss, k) + print('%-24s %-24s %s'%(hits, miss, k)) for k in mb_o: hits = ' -- /%-7d'%(mb[k][0]) miss = ' -- /%-7d'%(mb[k][1]) - print '%-24s %-24s %s'%(hits, miss, k) + print('%-24s %-24s %s'%(hits, miss, k)) - print '-'*(24+24+1+20) + print('-'*(24+24+1+20)) if __name__ == "__main__": if len(sys.argv) != 3: - print """Usage: %s file1 file2 + print("""Usage: %s file1 file2 -Compares --debug=memomize output from file1 against file2."""%sys.argv[0] +Compares --debug=memomize output from file1 against file2."""%sys.argv[0]) sys.exit(1) memoize_cmp(sys.argv[1], sys.argv[2]) diff --git a/bin/objcounts.py b/bin/objcounts.py index 06620126..2bd89236 100644 --- a/bin/objcounts.py +++ b/bin/objcounts.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function import re import sys @@ -27,10 +28,10 @@ import sys filenames = sys.argv[1:] if len(sys.argv) != 3: - print """Usage: objcounts.py file1 file2 + print("""Usage: objcounts.py file1 file2 Compare the --debug=object counts from two build logs. -""" +""") sys.exit(0) def fetch_counts(fname): @@ -81,10 +82,9 @@ def diffstr(c1, c2): return " %5s/%-5s %-8s" % (c1, c2, d) def printline(c1, c2, classname): - print \ - diffstr(c1[2], c2[2]) + \ + print(diffstr(c1[2], c2[2]) + \ diffstr(c1[3], c2[3]) + \ - ' ' + classname + ' ' + classname) for k in sorted(common.keys()): c = common[k] diff --git a/bin/scons-diff.py b/bin/scons-diff.py index 52bd51b1..85975011 100644 --- a/bin/scons-diff.py +++ b/bin/scons-diff.py @@ -8,6 +8,7 @@ # etc. so that you can diff trees without having to ignore changes in # version lines. # +from __future__ import print_function import difflib import getopt @@ -43,7 +44,7 @@ def diff_line(left, right): opts = ' ' + ' '.join(diff_options) else: opts = '' - print 'diff%s %s %s' % (opts, left, right) + print('diff%s %s %s' % (opts, left, right)) for o, a in opts: if o in ('-c', '-u'): @@ -51,7 +52,7 @@ for o, a in opts: context = int(a) diff_options.append(o) elif o in ('-h', '--help'): - print Usage + print(Usage) sys.exit(0) elif o in ('-n'): diff_options.append(o) @@ -161,9 +162,9 @@ def diff_file(left, right): else: if text: diff_line(left, right) - print text, + print(text) elif report_same: - print 'Files %s and %s are identical' % (left, right) + print('Files %s and %s are identical' % (left, right)) def diff_dir(left, right): llist = os.listdir(left) @@ -180,9 +181,9 @@ def diff_dir(left, right): os.path.join(right, x), recursive) else: - print 'Only in %s: %s' % (left, x) + print('Only in %s: %s' % (left, x)) else: - print 'Only in %s: %s' % (right, x) + print('Only in %s: %s' % (right, x)) do_diff(left, right, True) diff --git a/bin/scons-proc.py b/bin/scons-proc.py index 9567db8c..138cff74 100644 --- a/bin/scons-proc.py +++ b/bin/scons-proc.py @@ -9,6 +9,8 @@ # DocBook-formatted generated XML files containing the summary text # and/or .mod files containing the ENTITY definitions for each item. # +from __future__ import print_function + import getopt import os import re @@ -229,10 +231,15 @@ class Proxy(object): """Retrieve the entire wrapped object""" return self.__subject - def __cmp__(self, other): + def __eq__(self, other): if issubclass(other.__class__, self.__subject.__class__): - return cmp(self.__subject, other) - return cmp(self.__dict__, other.__dict__) + return self.__subject == other + return self.__dict__ == other.__dict__ + + ## def __lt__(self, other): + ## if issubclass(other.__class__, self.__subject.__class__): + ## return self.__subject < other + ## return self.__dict__ < other.__dict__ class SConsThing(Proxy): def idfunc(self): @@ -344,25 +351,25 @@ def write_output_files(h, buildersfiles, functionsfiles, processor_class = SCons_XML # Step 1: Creating entity files for builders, functions,... -print "Generating entity files..." +print("Generating entity files...") h = parse_docs(args, False) write_output_files(h, buildersfiles, functionsfiles, toolsfiles, variablesfiles, SCons_XML.write_mod) # Step 2: Validating all input files -print "Validating files against SCons XSD..." +print("Validating files against SCons XSD...") if SConsDoc.validate_all_xml(['src']): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." + print("Validation failed! Please correct the errors above and try again.") # Step 3: Creating actual documentation snippets, using the # fully resolved and updated entities from the *.mod files. -print "Updating documentation for builders, tools and functions..." +print("Updating documentation for builders, tools and functions...") h = parse_docs(args, True) write_output_files(h, buildersfiles, functionsfiles, toolsfiles, variablesfiles, SCons_XML.write) -print "Done" +print("Done") # Local Variables: # tab-width:4 diff --git a/bin/scons-test.py b/bin/scons-test.py index 046cf4b0..dd54dd14 100644 --- a/bin/scons-test.py +++ b/bin/scons-test.py @@ -14,6 +14,7 @@ # relevant information about the system, the Python version, etc., # so that problems on different platforms can be identified sooner. # +from __future__ import print_function import atexit import getopt @@ -60,7 +61,7 @@ for o, a in opts: outdir = a elif o == '-v' or o == '--verbose': def printname(x): - print x + print(x) elif o == '--xml': format = o @@ -148,34 +149,34 @@ else: if format == '--xml': - print "<scons_test_run>" - print " <sys>" + print("<scons_test_run>") + print(" <sys>") sys_keys = ['byteorder', 'exec_prefix', 'executable', 'maxint', 'maxunicode', 'platform', 'prefix', 'version', 'version_info'] for k in sys_keys: - print " <%s>%s</%s>" % (k, sys.__dict__[k], k) - print " </sys>" + print(" <%s>%s</%s>" % (k, sys.__dict__[k], k)) + print(" </sys>") fmt = '%a %b %d %H:%M:%S %Y' - print " <time>" - print " <gmtime>%s</gmtime>" % time.strftime(fmt, time.gmtime()) - print " <localtime>%s</localtime>" % time.strftime(fmt, time.localtime()) - print " </time>" + print(" <time>") + print(" <gmtime>%s</gmtime>" % time.strftime(fmt, time.gmtime())) + print(" <localtime>%s</localtime>" % time.strftime(fmt, time.localtime())) + print(" </time>") - print " <tempdir>%s</tempdir>" % tempdir + print(" <tempdir>%s</tempdir>" % tempdir) def print_version_info(tag, module): - print " <%s>" % tag - print " <version>%s</version>" % module.__version__ - print " <build>%s</build>" % module.__build__ - print " <buildsys>%s</buildsys>" % module.__buildsys__ - print " <date>%s</date>" % module.__date__ - print " <developer>%s</developer>" % module.__developer__ - print " </%s>" % tag - - print " <scons>" + print(" <%s>" % tag) + print(" <version>%s</version>" % module.__version__) + print(" <build>%s</build>" % module.__build__) + print(" <buildsys>%s</buildsys>" % module.__buildsys__) + print(" <date>%s</date>" % module.__date__) + print(" <developer>%s</developer>" % module.__developer__) + print(" </%s>" % tag) + + print(" <scons>") print_version_info("script", scons) print_version_info("engine", SCons) - print " </scons>" + print(" </scons>") environ_keys = [ 'PATH', @@ -213,37 +214,37 @@ if format == '--xml': 'USER', ] - print " <environment>" + print(" <environment>") for key in sorted(environ_keys): value = os.environ.get(key) if value: - print " <variable>" - print " <name>%s</name>" % key - print " <value>%s</value>" % value - print " </variable>" - print " </environment>" + print(" <variable>") + print(" <name>%s</name>" % key) + print(" <value>%s</value>" % value) + print(" </variable>") + print(" </environment>") command = '"%s" runtest.py -q -o - --xml %s' % (sys.executable, runtest_args) - #print command + #print(command) os.system(command) - print "</scons_test_run>" + print("</scons_test_run>") else: def print_version_info(tag, module): - print "\t%s: v%s.%s, %s, by %s on %s" % (tag, + print("\t%s: v%s.%s, %s, by %s on %s" % (tag, module.__version__, module.__build__, module.__date__, module.__developer__, - module.__buildsys__) + module.__buildsys__)) - print "SCons by Steven Knight et al.:" + print("SCons by Steven Knight et al.:") print_version_info("script", scons) print_version_info("engine", SCons) command = '"%s" runtest.py %s' % (sys.executable, runtest_args) - #print command + #print(command) os.system(command) # Local Variables: diff --git a/bin/scons-unzip.py b/bin/scons-unzip.py index d4ec4bff..a64179fc 100644 --- a/bin/scons-unzip.py +++ b/bin/scons-unzip.py @@ -7,6 +7,7 @@ # I'm using this to make it more convenient to manage working on multiple # changes on Windows, where I don't have access to my Aegis tools. # +from __future__ import print_function import getopt import os.path @@ -32,7 +33,7 @@ for o, a in opts: outdir = a elif o == '-v' or o == '--verbose': def printname(x): - print x + print(x) if len(args) != 1: sys.stderr.write("scons-unzip.py: \n") diff --git a/bin/scons_dev_master.py b/bin/scons_dev_master.py index 3c41ac06..a8862ea8 100644 --- a/bin/scons_dev_master.py +++ b/bin/scons_dev_master.py @@ -3,6 +3,7 @@ # A script for turning a generic Ubuntu system into a master for # SCons development. +from __future__ import print_function import getopt import sys @@ -131,12 +132,12 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: if o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): CommandRunner.execute = CommandRunner.do_not_execute @@ -148,7 +149,7 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] username = a elif o in ('-y', '--yes', '--assume-yes'): yesflag = o - except Usage, err: + except Usage as err: sys.stderr.write(str(err.msg) + '\n') sys.stderr.write('use -h to get help\n') return 2 @@ -22,6 +22,7 @@ # # https://sourceforge.net/projects/sitedocs/ # +from __future__ import print_function import xml.sax import xml.sax.saxutils @@ -121,9 +122,9 @@ if __name__ == '__main__': # generalized once we figure out other things for this script to do. bugs = [x for x in Artifacts['Bugs'] if x.status == 'Open'] - print list(Artifacts.keys()) + print(list(Artifacts.keys())) - print "%d open bugs" % len(bugs) + print("%d open bugs" % len(bugs)) # Sort them into a separate list for each assignee. Assigned = {} @@ -141,7 +142,7 @@ if __name__ == '__main__': except KeyError: pass else: - print " %s" % a - b.sort(lambda x, y: cmp(x.artifact_id, y.artifact_id)) + print(" %s" % a) + b.sort(key=lambda x, y: (x.artifact_id, y.artifact_id)) for bug in b: - print " %-6s %s" % (bug.artifact_id, bug.summary) + print(" %-6s %s" % (bug.artifact_id, bug.summary)) diff --git a/bin/svn-bisect.py b/bin/svn-bisect.py index 77bda58f..dbf8dd97 100755 --- a/bin/svn-bisect.py +++ b/bin/svn-bisect.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- Python -*- -from __future__ import division +from __future__ import division, print_function import sys from math import log, ceil @@ -28,22 +28,22 @@ script = script_args[2:] # print an error message and quit def error(s): - print >>sys.stderr, "******", s, "******" + print("******", s, "******", file=sys.stderr) sys.exit(1) # update to the specified version and run test def testfail(revision): "Return true if test fails" - print "Updating to revision", revision + print("Updating to revision", revision) if subprocess.call(["svn","up","-qr",str(revision)]) != 0: m = "SVN did not update properly to revision %d" raise RuntimeError(m % revision) return subprocess.call(script,shell=False) != 0 # confirm that the endpoints are different -print "****** Checking upper bracket", upper +print("****** Checking upper bracket", upper) upperfails = testfail(upper) -print "****** Checking lower bracket", lower +print("****** Checking lower bracket", lower) lowerfails = testfail(lower) if upperfails == lowerfails: error("Upper and lower revisions must bracket the failure") @@ -51,7 +51,7 @@ if upperfails == lowerfails: # binary search for transition msg = "****** max %d revisions to test (bug bracketed by [%d,%d])" while upper-lower > 1: - print msg % (ceil(log(upper-lower,2)), lower, upper) + print(msg % (ceil(log(upper-lower,2)), lower, upper)) mid = (lower + upper)//2 midfails = testfail(mid) @@ -64,7 +64,7 @@ while upper-lower > 1: # show which revision was first to fail if upperfails != lowerfails: lower = upper -print "The error was caused by revision", lower +print("The error was caused by revision", lower) # Local Variables: # tab-width:4 diff --git a/bin/update-release-info.py b/bin/update-release-info.py index 59b3e848..4a677db4 100644 --- a/bin/update-release-info.py +++ b/bin/update-release-info.py @@ -56,6 +56,7 @@ In 'post' mode, files are prepared for the next release cycle: # 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. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -73,14 +74,14 @@ if len(sys.argv) < 2: else: mode = sys.argv[1] if mode not in ['develop', 'release', 'post']: - print("""ERROR: `%s' as a parameter is invalid; it must be one of -\tdevelop, release, or post. The default is develop.""" % mode) + print(("""ERROR: `%s' as a parameter is invalid; it must be one of +\tdevelop, release, or post. The default is develop.""" % mode)) sys.exit(1) # Get configuration information config = dict() -exec open('ReleaseConfig').read() in globals(), config +exec(open('ReleaseConfig').read(), globals(), config) try: version_tuple = config['version_tuple'] @@ -90,9 +91,9 @@ except KeyError: print('''ERROR: Config file must contain at least version_tuple, \tunsupported_python_version, and deprecated_python_version.''') sys.exit(1) -if DEBUG: print 'version tuple', version_tuple -if DEBUG: print 'unsupported Python version', unsupported_version -if DEBUG: print 'deprecated Python version', deprecated_version +if DEBUG: print('version tuple', version_tuple) +if DEBUG: print('unsupported Python version', unsupported_version) +if DEBUG: print('deprecated Python version', deprecated_version) try: release_date = config['release_date'] @@ -102,9 +103,9 @@ else: if len(release_date) == 3: release_date = release_date + time.localtime()[3:6] if len(release_date) != 6: - print '''ERROR: Invalid release date''', release_date + print('''ERROR: Invalid release date''', release_date) sys.exit(1) -if DEBUG: print 'release date', release_date +if DEBUG: print('release date', release_date) if mode == 'develop' and version_tuple[3] != 'alpha': version_tuple == version_tuple[:3] + ('alpha', 0) @@ -119,11 +120,11 @@ if len(version_tuple) > 3: version_type = version_tuple[3] else: version_type = 'final' -if DEBUG: print 'version string', version_string +if DEBUG: print('version string', version_string) if version_type not in ['alpha', 'beta', 'candidate', 'final']: - print("""ERROR: `%s' is not a valid release type in version tuple; -\tit must be one of alpha, beta, candidate, or final""" % version_type) + print(("""ERROR: `%s' is not a valid release type in version tuple; +\tit must be one of alpha, beta, candidate, or final""" % version_type)) sys.exit(1) try: @@ -133,13 +134,13 @@ except KeyError: month_year = 'MONTH YEAR' else: month_year = time.strftime('%B %Y', release_date + (0,0,0)) -if DEBUG: print 'month year', month_year +if DEBUG: print('month year', month_year) try: copyright_years = config['copyright_years'] except KeyError: copyright_years = '2001 - %d'%(release_date[0] + 1) -if DEBUG: print 'copyright years', copyright_years +if DEBUG: print('copyright years', copyright_years) class UpdateFile(object): """ @@ -218,7 +219,7 @@ class UpdateFile(object): XXX ''' if self.file is not None and self.content != self.orig: - print 'Updating ' + self.file + '...' + print('Updating ' + self.file + '...') open(self.file, 'w').write(self.content) if mode == 'post': diff --git a/bin/xmlagenda.py b/bin/xmlagenda.py index b3cd5205..fcfe53e2 100755 --- a/bin/xmlagenda.py +++ b/bin/xmlagenda.py @@ -18,6 +18,7 @@ # Grab the sort bar on the far left (just above the "1" for row one) # and move it down one row. (Row one becomes a floating header) # Voila! +from __future__ import print_function # The team members # FIXME: These names really should be external to this script @@ -89,7 +90,7 @@ for issue in issues: writer.writerow(['','','','','','','']) for member in team: writer.writerow(['','',member,'','','','']) -print "Exported %d issues to editlist.csv. Ready to upload to Google."%len(issues) +print("Exported %d issues to editlist.csv. Ready to upload to Google."%len(issues)) # Local Variables: # tab-width:4 diff --git a/doc/SConscript b/doc/SConscript index d5cd01c9..386aec71 100644 --- a/doc/SConscript +++ b/doc/SConscript @@ -23,6 +23,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function import os.path import re @@ -86,19 +87,19 @@ except: try: import lxml except: - print "doc: Neither libxml2 nor lxml Python bindings found!" - print " Please install one of the packages python-libxml2 or python-lxml." + print("doc: Neither libxml2 nor lxml Python bindings found!") + print(" Please install one of the packages python-libxml2 or python-lxml.") skip_doc = True if not fop and not xep: - print "doc: No PDF renderer found (fop|xep)!" + print("doc: No PDF renderer found (fop|xep)!") skip_doc = True if skip_doc: - print "doc: ...skipping building User Guide." + print("doc: ...skipping building User Guide.") else: if not lynx: - print "doc: Warning, lynx is not installed...created release packages won't be complete!" + print("doc: Warning, lynx is not installed...created release packages won't be complete!") # # Always create a version.xml file containing the version information @@ -172,18 +173,18 @@ else: # Ensure that all XML files are valid against our XSD, and # that all example names and example output suffixes are unique # - print "Validating files against SCons XSD..." + print("Validating files against SCons XSD...") if SConsDoc.validate_all_xml(['src'], xsdfile='xsd/scons.xsd'): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." + print("Validation failed! Please correct the errors above and try again.") sys.exit(0) - print "Checking whether all example names are unique..." + print("Checking whether all example names are unique...") if SConsExamples.exampleNamesAreUnique(os.path.join('doc','user')): - print "OK" + print("OK") else: - print "Not all example names and suffixes are unique! Please correct the errors listed above and try again." + print("Not all example names and suffixes are unique! Please correct the errors listed above and try again.") sys.exit(0) # List of prerequisite files in the build/doc folder @@ -509,7 +510,7 @@ else: # epydoc_cli is found if not epydoc_cli and not epydoc: - print "doc: epydoc not found, skipping building API documentation." + print("doc: epydoc not found, skipping building API documentation.") else: # XXX Should be in common with reading the same thing in # the SConstruct file. @@ -531,7 +532,7 @@ else: tar_list.append(htmldir) if not epydoc_cli: - print "doc: command line epydoc is not found, skipping PDF/PS/Tex output" + print("doc: command line epydoc is not found, skipping PDF/PS/Tex output") else: # PDF and PostScript and TeX are built from the # same invocation. @@ -564,7 +565,7 @@ if tar_deps: tar_list = ' '.join([x.replace(build+'/', '') for x in tar_list]) t = env.Command(dist_doc_tar_gz, tar_deps, "tar cf${TAR_HFLAG} - -C %s %s | gzip > $TARGET" % (build, tar_list)) - AddPostAction(dist_doc_tar_gz, Chmod(dist_doc_tar_gz, 0644)) + AddPostAction(dist_doc_tar_gz, Chmod(dist_doc_tar_gz, 0o644)) Local(t) Alias('doc', t) else: @@ -1,1805 +1,1835 @@ -#!/usr/bin/env python
-#
-# Copyright 2007 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Tool for uploading diffs from a version control system to the codereview app.
-
-Usage summary: upload.py [options] [-- diff_options] [path...]
-
-Diff options are passed to the diff command of the underlying system.
-
-Supported version control systems:
- Git
- Mercurial
- Subversion
-
-It is important for Git/Mercurial users to specify a tree/node/branch to diff
-against by using the '--rev' option.
-"""
-# This code is derived from appcfg.py in the App Engine SDK (open source),
-# and from ASPN recipe #146306.
-
-import ConfigParser
-import cookielib
-import fnmatch
-import getpass
-import logging
-import mimetypes
-import optparse
-import os
-import re
-import socket
-import subprocess
-import sys
-import urllib
-import urllib2
-import urlparse
-
-# The md5 module was deprecated in Python 2.5.
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
-
-try:
- import readline
-except ImportError:
- pass
-
-try:
- import keyring
-except ImportError:
- keyring = None
-
-# The logging verbosity:
-# 0: Errors only.
-# 1: Status messages.
-# 2: Info logs.
-# 3: Debug logs.
-verbosity = 1
-
-# The account type used for authentication.
-# This line could be changed by the review server (see handler for
-# upload.py).
-AUTH_ACCOUNT_TYPE = "GOOGLE"
-
-# URL of the default review server. As for AUTH_ACCOUNT_TYPE, this line could be
-# changed by the review server (see handler for upload.py).
-DEFAULT_REVIEW_SERVER = "codereview.appspot.com"
-
-# Max size of patch or base file.
-MAX_UPLOAD_SIZE = 900 * 1024
-
-# Constants for version control names. Used by GuessVCSName.
-VCS_GIT = "Git"
-VCS_MERCURIAL = "Mercurial"
-VCS_SUBVERSION = "Subversion"
-VCS_UNKNOWN = "Unknown"
-
-# whitelist for non-binary filetypes which do not start with "text/"
-# .mm (Objective-C) shows up as application/x-freemind on my Linux box.
-TEXT_MIMETYPES = ['application/javascript', 'application/x-javascript',
- 'application/xml', 'application/x-freemind',
- 'application/x-sh']
-
-VCS_ABBREVIATIONS = {
- VCS_MERCURIAL.lower(): VCS_MERCURIAL,
- "hg": VCS_MERCURIAL,
- VCS_SUBVERSION.lower(): VCS_SUBVERSION,
- "svn": VCS_SUBVERSION,
- VCS_GIT.lower(): VCS_GIT,
-}
-
-# The result of parsing Subversion's [auto-props] setting.
-svn_auto_props_map = None
-
-def GetEmail(prompt):
- """Prompts the user for their email address and returns it.
-
- The last used email address is saved to a file and offered up as a suggestion
- to the user. If the user presses enter without typing in anything the last
- used email address is used. If the user enters a new address, it is saved
- for next time we prompt.
-
- """
- last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
- last_email = ""
- if os.path.exists(last_email_file_name):
- try:
- last_email_file = open(last_email_file_name, "r")
- last_email = last_email_file.readline().strip("\n")
- last_email_file.close()
- prompt += " [%s]" % last_email
- except IOError, e:
- pass
- email = raw_input(prompt + ": ").strip()
- if email:
- try:
- last_email_file = open(last_email_file_name, "w")
- last_email_file.write(email)
- last_email_file.close()
- except IOError, e:
- pass
- else:
- email = last_email
- return email
-
-
-def StatusUpdate(msg):
- """Print a status message to stdout.
-
- If 'verbosity' is greater than 0, print the message.
-
- Args:
- msg: The string to print.
- """
- if verbosity > 0:
- print msg
-
-
-def ErrorExit(msg):
- """Print an error message to stderr and exit."""
- print >>sys.stderr, msg
- sys.exit(1)
-
-
-class ClientLoginError(urllib2.HTTPError):
- """Raised to indicate there was an error authenticating with ClientLogin."""
-
- def __init__(self, url, code, msg, headers, args):
- urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
- self.args = args
- self.reason = args["Error"]
- self.info = args.get("Info", None)
-
-
-class AbstractRpcServer(object):
- """Provides a common interface for a simple RPC server."""
-
- def __init__(self, host, auth_function, host_override=None, extra_headers={},
- save_cookies=False, account_type=AUTH_ACCOUNT_TYPE):
- """Creates a new HttpRpcServer.
-
- Args:
- host: The host to send requests to.
- auth_function: A function that takes no arguments and returns an
- (email, password) tuple when called. Will be called if authentication
- is required.
- host_override: The host header to send to the server (defaults to host).
- extra_headers: A dict of extra headers to append to every request.
- save_cookies: If True, save the authentication cookies to local disk.
- If False, use an in-memory cookiejar instead. Subclasses must
- implement this functionality. Defaults to False.
- account_type: Account type used for authentication. Defaults to
- AUTH_ACCOUNT_TYPE.
- """
- self.host = host
- if (not self.host.startswith("http://") and
- not self.host.startswith("https://")):
- self.host = "http://" + self.host
- self.host_override = host_override
- self.auth_function = auth_function
- self.authenticated = False
- self.extra_headers = extra_headers
- self.save_cookies = save_cookies
- self.account_type = account_type
- self.opener = self._GetOpener()
- if self.host_override:
- logging.info("Server: %s; Host: %s", self.host, self.host_override)
- else:
- logging.info("Server: %s", self.host)
-
- def _GetOpener(self):
- """Returns an OpenerDirector for making HTTP requests.
-
- Returns:
- A urllib2.OpenerDirector object.
- """
- raise NotImplementedError()
-
- def _CreateRequest(self, url, data=None):
- """Creates a new urllib request."""
- logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
- req = urllib2.Request(url, data=data)
- if self.host_override:
- req.add_header("Host", self.host_override)
- for key, value in self.extra_headers.iteritems():
- req.add_header(key, value)
- return req
-
- def _GetAuthToken(self, email, password):
- """Uses ClientLogin to authenticate the user, returning an auth token.
-
- Args:
- email: The user's email address
- password: The user's password
-
- Raises:
- ClientLoginError: If there was an error authenticating with ClientLogin.
- HTTPError: If there was some other form of HTTP error.
-
- Returns:
- The authentication token returned by ClientLogin.
- """
- account_type = self.account_type
- if self.host.endswith(".google.com"):
- # Needed for use inside Google.
- account_type = "HOSTED"
- req = self._CreateRequest(
- url="https://www.google.com/accounts/ClientLogin",
- data=urllib.urlencode({
- "Email": email,
- "Passwd": password,
- "service": "ah",
- "source": "rietveld-codereview-upload",
- "accountType": account_type,
- }),
- )
- try:
- response = self.opener.open(req)
- response_body = response.read()
- response_dict = dict(x.split("=")
- for x in response_body.split("\n") if x)
- return response_dict["Auth"]
- except urllib2.HTTPError, e:
- if e.code == 403:
- body = e.read()
- response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
- raise ClientLoginError(req.get_full_url(), e.code, e.msg,
- e.headers, response_dict)
- else:
- raise
-
- def _GetAuthCookie(self, auth_token):
- """Fetches authentication cookies for an authentication token.
-
- Args:
- auth_token: The authentication token returned by ClientLogin.
-
- Raises:
- HTTPError: If there was an error fetching the authentication cookies.
- """
- # This is a dummy value to allow us to identify when we're successful.
- continue_location = "http://localhost/"
- args = {"continue": continue_location, "auth": auth_token}
- req = self._CreateRequest("%s/_ah/login?%s" %
- (self.host, urllib.urlencode(args)))
- try:
- response = self.opener.open(req)
- except urllib2.HTTPError, e:
- response = e
- if (response.code != 302 or
- response.info()["location"] != continue_location):
- raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
- response.headers, response.fp)
- self.authenticated = True
-
- def _Authenticate(self):
- """Authenticates the user.
-
- The authentication process works as follows:
- 1) We get a username and password from the user
- 2) We use ClientLogin to obtain an AUTH token for the user
- (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
- 3) We pass the auth token to /_ah/login on the server to obtain an
- authentication cookie. If login was successful, it tries to redirect
- us to the URL we provided.
-
- If we attempt to access the upload API without first obtaining an
- authentication cookie, it returns a 401 response (or a 302) and
- directs us to authenticate ourselves with ClientLogin.
- """
- for i in range(3):
- credentials = self.auth_function()
- try:
- auth_token = self._GetAuthToken(credentials[0], credentials[1])
- except ClientLoginError, e:
- print >>sys.stderr, ''
- if e.reason == "BadAuthentication":
- if e.info == "InvalidSecondFactor":
- print >>sys.stderr, (
- "Use an application-specific password instead "
- "of your regular account password.\n"
- "See http://www.google.com/"
- "support/accounts/bin/answer.py?answer=185833")
- else:
- print >>sys.stderr, "Invalid username or password."
- elif e.reason == "CaptchaRequired":
- print >>sys.stderr, (
- "Please go to\n"
- "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
- "and verify you are a human. Then try again.\n"
- "If you are using a Google Apps account the URL is:\n"
- "https://www.google.com/a/yourdomain.com/UnlockCaptcha")
- elif e.reason == "NotVerified":
- print >>sys.stderr, "Account not verified."
- elif e.reason == "TermsNotAgreed":
- print >>sys.stderr, "User has not agreed to TOS."
- elif e.reason == "AccountDeleted":
- print >>sys.stderr, "The user account has been deleted."
- elif e.reason == "AccountDisabled":
- print >>sys.stderr, "The user account has been disabled."
- break
- elif e.reason == "ServiceDisabled":
- print >>sys.stderr, ("The user's access to the service has been "
- "disabled.")
- elif e.reason == "ServiceUnavailable":
- print >>sys.stderr, "The service is not available; try again later."
- else:
- # Unknown error.
- raise
- print >>sys.stderr, ''
- continue
- self._GetAuthCookie(auth_token)
- return
-
- def Send(self, request_path, payload=None,
- content_type="application/octet-stream",
- timeout=None,
- extra_headers=None,
- **kwargs):
- """Sends an RPC and returns the response.
-
- Args:
- request_path: The path to send the request to, eg /api/appversion/create.
- payload: The body of the request, or None to send an empty request.
- content_type: The Content-Type header to use.
- timeout: timeout in seconds; default None i.e. no timeout.
- (Note: for large requests on OS X, the timeout doesn't work right.)
- extra_headers: Dict containing additional HTTP headers that should be
- included in the request (string header names mapped to their values),
- or None to not include any additional headers.
- kwargs: Any keyword arguments are converted into query string parameters.
-
- Returns:
- The response body, as a string.
- """
- # TODO: Don't require authentication. Let the server say
- # whether it is necessary.
- if not self.authenticated:
- self._Authenticate()
-
- old_timeout = socket.getdefaulttimeout()
- socket.setdefaulttimeout(timeout)
- try:
- tries = 0
- while True:
- tries += 1
- args = dict(kwargs)
- url = "%s%s" % (self.host, request_path)
- if args:
- url += "?" + urllib.urlencode(args)
- req = self._CreateRequest(url=url, data=payload)
- req.add_header("Content-Type", content_type)
- if extra_headers:
- for header, value in extra_headers.items():
- req.add_header(header, value)
- try:
- f = self.opener.open(req)
- response = f.read()
- f.close()
- return response
- except urllib2.HTTPError, e:
- if tries > 3:
- raise
- elif e.code == 401 or e.code == 302:
- self._Authenticate()
-## elif e.code >= 500 and e.code < 600:
-## # Server Error - try again.
-## continue
- elif e.code == 301:
- # Handle permanent redirect manually.
- url = e.info()["location"]
- url_loc = urlparse.urlparse(url)
- self.host = '%s://%s' % (url_loc[0], url_loc[1])
- else:
- raise
- finally:
- socket.setdefaulttimeout(old_timeout)
-
-
-class HttpRpcServer(AbstractRpcServer):
- """Provides a simplified RPC-style interface for HTTP requests."""
-
- def _Authenticate(self):
- """Save the cookie jar after authentication."""
- super(HttpRpcServer, self)._Authenticate()
- if self.save_cookies:
- StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
- self.cookie_jar.save()
-
- def _GetOpener(self):
- """Returns an OpenerDirector that supports cookies and ignores redirects.
-
- Returns:
- A urllib2.OpenerDirector object.
- """
- opener = urllib2.OpenerDirector()
- opener.add_handler(urllib2.ProxyHandler())
- opener.add_handler(urllib2.UnknownHandler())
- opener.add_handler(urllib2.HTTPHandler())
- opener.add_handler(urllib2.HTTPDefaultErrorHandler())
- opener.add_handler(urllib2.HTTPSHandler())
- opener.add_handler(urllib2.HTTPErrorProcessor())
- if self.save_cookies:
- self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
- self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
- if os.path.exists(self.cookie_file):
- try:
- self.cookie_jar.load()
- self.authenticated = True
- StatusUpdate("Loaded authentication cookies from %s" %
- self.cookie_file)
- except (cookielib.LoadError, IOError):
- # Failed to load cookies - just ignore them.
- pass
- else:
- # Create an empty cookie file with mode 600
- fd = os.open(self.cookie_file, os.O_CREAT, 0600)
- os.close(fd)
- # Always chmod the cookie file
- os.chmod(self.cookie_file, 0600)
- else:
- # Don't save cookies across runs of update.py.
- self.cookie_jar = cookielib.CookieJar()
- opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
- return opener
-
-
-parser = optparse.OptionParser(
- usage="%prog [options] [-- diff_options] [path...]")
-parser.add_option("-y", "--assume_yes", action="store_true",
- dest="assume_yes", default=False,
- help="Assume that the answer to yes/no questions is 'yes'.")
-# Logging
-group = parser.add_option_group("Logging options")
-group.add_option("-q", "--quiet", action="store_const", const=0,
- dest="verbose", help="Print errors only.")
-group.add_option("-v", "--verbose", action="store_const", const=2,
- dest="verbose", default=1,
- help="Print info level logs.")
-group.add_option("--noisy", action="store_const", const=3,
- dest="verbose", help="Print all logs.")
-# Review server
-group = parser.add_option_group("Review server options")
-group.add_option("-s", "--server", action="store", dest="server",
- default=DEFAULT_REVIEW_SERVER,
- metavar="SERVER",
- help=("The server to upload to. The format is host[:port]. "
- "Defaults to '%default'."))
-group.add_option("-e", "--email", action="store", dest="email",
- metavar="EMAIL", default=None,
- help="The username to use. Will prompt if omitted.")
-group.add_option("-H", "--host", action="store", dest="host",
- metavar="HOST", default=None,
- help="Overrides the Host header sent with all RPCs.")
-group.add_option("--no_cookies", action="store_false",
- dest="save_cookies", default=True,
- help="Do not save authentication cookies to local disk.")
-group.add_option("--account_type", action="store", dest="account_type",
- metavar="TYPE", default=AUTH_ACCOUNT_TYPE,
- choices=["GOOGLE", "HOSTED"],
- help=("Override the default account type "
- "(defaults to '%default', "
- "valid choices are 'GOOGLE' and 'HOSTED')."))
-# Issue
-group = parser.add_option_group("Issue options")
-group.add_option("-d", "--description", action="store", dest="description",
- metavar="DESCRIPTION", default=None,
- help="Optional description when creating an issue.")
-group.add_option("-f", "--description_file", action="store",
- dest="description_file", metavar="DESCRIPTION_FILE",
- default=None,
- help="Optional path of a file that contains "
- "the description when creating an issue.")
-group.add_option("-r", "--reviewers", action="store", dest="reviewers",
- metavar="REVIEWERS", default=None,
- help="Add reviewers (comma separated email addresses).")
-group.add_option("--cc", action="store", dest="cc",
- metavar="CC", default="dev@scons.tigris.org",
- help="Add CC (comma separated email addresses).")
-group.add_option("--private", action="store_true", dest="private",
- default=False,
- help="Make the issue restricted to reviewers and those CCed")
-# Upload options
-group = parser.add_option_group("Patch options")
-group.add_option("-m", "--message", action="store", dest="message",
- metavar="MESSAGE", default=None,
- help="A message to identify the patch. "
- "Will prompt if omitted.")
-group.add_option("-i", "--issue", type="int", action="store",
- metavar="ISSUE", default=None,
- help="Issue number to which to add. Defaults to new issue.")
-group.add_option("--base_url", action="store", dest="base_url", default=None,
- help="Base repository URL (listed as \"Base URL\" when "
- "viewing issue). If omitted, will be guessed automatically "
- "for SVN repos and left blank for others.")
-group.add_option("--download_base", action="store_true",
- dest="download_base", default=False,
- help="Base files will be downloaded by the server "
- "(side-by-side diffs may not work on files with CRs).")
-group.add_option("--rev", action="store", dest="revision",
- metavar="REV", default=None,
- help="Base revision/branch/tree to diff against. Use "
- "rev1:rev2 range to review already committed changeset.")
-group.add_option("--send_mail", action="store_true",
- dest="send_mail", default=True,
- help="Send notification email to reviewers.")
-group.add_option("--vcs", action="store", dest="vcs",
- metavar="VCS", default="svn",
- help=("Version control system (optional, usually upload.py "
- "already guesses the right VCS)."))
-group.add_option("--emulate_svn_auto_props", action="store_true",
- dest="emulate_svn_auto_props", default=False,
- help=("Emulate Subversion's auto properties feature."))
-
-
-def GetRpcServer(server, email=None, host_override=None, save_cookies=True,
- account_type=AUTH_ACCOUNT_TYPE):
- """Returns an instance of an AbstractRpcServer.
-
- Args:
- server: String containing the review server URL.
- email: String containing user's email address.
- host_override: If not None, string containing an alternate hostname to use
- in the host header.
- save_cookies: Whether authentication cookies should be saved to disk.
- account_type: Account type for authentication, either 'GOOGLE'
- or 'HOSTED'. Defaults to AUTH_ACCOUNT_TYPE.
-
- Returns:
- A new AbstractRpcServer, on which RPC calls can be made.
- """
-
- rpc_server_class = HttpRpcServer
-
- # If this is the dev_appserver, use fake authentication.
- host = (host_override or server).lower()
- if re.match(r'(http://)?localhost([:/]|$)', host):
- if email is None:
- email = "test@example.com"
- logging.info("Using debug user %s. Override with --email" % email)
- server = rpc_server_class(
- server,
- lambda: (email, "password"),
- host_override=host_override,
- extra_headers={"Cookie":
- 'dev_appserver_login="%s:False"' % email},
- save_cookies=save_cookies,
- account_type=account_type)
- # Don't try to talk to ClientLogin.
- server.authenticated = True
- return server
-
- def GetUserCredentials():
- """Prompts the user for a username and password."""
- # Create a local alias to the email variable to avoid Python's crazy
- # scoping rules.
- local_email = email
- if local_email is None:
- local_email = GetEmail("Email (login for uploading to %s)" % server)
- password = None
- if keyring:
- password = keyring.get_password(host, local_email)
- if password is not None:
- print "Using password from system keyring."
- else:
- password = getpass.getpass("Password for %s: " % local_email)
- if keyring:
- answer = raw_input("Store password in system keyring?(y/N) ").strip()
- if answer == "y":
- keyring.set_password(host, local_email, password)
- return (local_email, password)
-
- return rpc_server_class(server,
- GetUserCredentials,
- host_override=host_override,
- save_cookies=save_cookies)
-
-
-def EncodeMultipartFormData(fields, files):
- """Encode form fields for multipart/form-data.
-
- Args:
- fields: A sequence of (name, value) elements for regular form fields.
- files: A sequence of (name, filename, value) elements for data to be
- uploaded as files.
- Returns:
- (content_type, body) ready for httplib.HTTP instance.
-
- Source:
- http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
- """
- BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
- CRLF = '\r\n'
- lines = []
- for (key, value) in fields:
- lines.append('--' + BOUNDARY)
- lines.append('Content-Disposition: form-data; name="%s"' % key)
- lines.append('')
- if isinstance(value, unicode):
- value = value.encode('utf-8')
- lines.append(value)
- for (key, filename, value) in files:
- lines.append('--' + BOUNDARY)
- lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
- (key, filename))
- lines.append('Content-Type: %s' % GetContentType(filename))
- lines.append('')
- if isinstance(value, unicode):
- value = value.encode('utf-8')
- lines.append(value)
- lines.append('--' + BOUNDARY + '--')
- lines.append('')
- body = CRLF.join(lines)
- content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
- return content_type, body
-
-
-def GetContentType(filename):
- """Helper to guess the content-type from the filename."""
- return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
-
-
-# Use a shell for subcommands on Windows to get a PATH search.
-use_shell = sys.platform.startswith("win")
-
-def RunShellWithReturnCodeAndStderr(command, print_output=False,
- universal_newlines=True,
- env=os.environ):
- """Executes a command and returns the output from stdout, stderr and the return code.
-
- Args:
- command: Command to execute.
- print_output: If True, the output is printed to stdout.
- If False, both stdout and stderr are ignored.
- universal_newlines: Use universal_newlines flag (default: True).
-
- Returns:
- Tuple (stdout, stderr, return code)
- """
- logging.info("Running %s", command)
- env = env.copy()
- env['LC_MESSAGES'] = 'C'
- p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- shell=use_shell, universal_newlines=universal_newlines,
- env=env)
- if print_output:
- output_array = []
- while True:
- line = p.stdout.readline()
- if not line:
- break
- print line.strip("\n")
- output_array.append(line)
- output = "".join(output_array)
- else:
- output = p.stdout.read()
- p.wait()
- errout = p.stderr.read()
- if print_output and errout:
- print >>sys.stderr, errout
- p.stdout.close()
- p.stderr.close()
- return output, errout, p.returncode
-
-def RunShellWithReturnCode(command, print_output=False,
- universal_newlines=True,
- env=os.environ):
- """Executes a command and returns the output from stdout and the return code."""
- out, err, retcode = RunShellWithReturnCodeAndStderr(command, print_output,
- universal_newlines, env)
- return out, retcode
-
-def RunShell(command, silent_ok=False, universal_newlines=True,
- print_output=False, env=os.environ):
- data, retcode = RunShellWithReturnCode(command, print_output,
- universal_newlines, env)
- if retcode:
- ErrorExit("Got error status from %s:\n%s" % (command, data))
- if not silent_ok and not data:
- ErrorExit("No output from %s" % command)
- return data
-
-
-class VersionControlSystem(object):
- """Abstract base class providing an interface to the VCS."""
-
- def __init__(self, options):
- """Constructor.
-
- Args:
- options: Command line options.
- """
- self.options = options
-
- def PostProcessDiff(self, diff):
- """Return the diff with any special post processing this VCS needs, e.g.
- to include an svn-style "Index:"."""
- return diff
-
- def GenerateDiff(self, args):
- """Return the current diff as a string.
-
- Args:
- args: Extra arguments to pass to the diff command.
- """
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
- def GetUnknownFiles(self):
- """Return a list of files unknown to the VCS."""
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
- def CheckForUnknownFiles(self):
- """Show an "are you sure?" prompt if there are unknown files."""
- unknown_files = self.GetUnknownFiles()
- if unknown_files:
- print "The following files are not added to version control:"
- for line in unknown_files:
- print line
- prompt = "Are you sure to continue?(y/N) "
- answer = raw_input(prompt).strip()
- if answer != "y":
- ErrorExit("User aborted")
-
- def GetBaseFile(self, filename):
- """Get the content of the upstream version of a file.
-
- Returns:
- A tuple (base_content, new_content, is_binary, status)
- base_content: The contents of the base file.
- new_content: For text files, this is empty. For binary files, this is
- the contents of the new file, since the diff output won't contain
- information to reconstruct the current file.
- is_binary: True iff the file is binary.
- status: The status of the file.
- """
-
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
-
- def GetBaseFiles(self, diff):
- """Helper that calls GetBase file for each file in the patch.
-
- Returns:
- A dictionary that maps from filename to GetBaseFile's tuple. Filenames
- are retrieved based on lines that start with "Index:" or
- "Property changes on:".
- """
- files = {}
- for line in diff.splitlines(True):
- if line.startswith('Index:') or line.startswith('Property changes on:'):
- unused, filename = line.split(':', 1)
- # On Windows if a file has property changes its filename uses '\'
- # instead of '/'.
- filename = filename.strip().replace('\\', '/')
- files[filename] = self.GetBaseFile(filename)
- return files
-
-
- def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
- files):
- """Uploads the base files (and if necessary, the current ones as well)."""
-
- def UploadFile(filename, file_id, content, is_binary, status, is_base):
- """Uploads a file to the server."""
- file_too_large = False
- if is_base:
- type = "base"
- else:
- type = "current"
- if len(content) > MAX_UPLOAD_SIZE:
- print ("Not uploading the %s file for %s because it's too large." %
- (type, filename))
- file_too_large = True
- content = ""
- checksum = md5(content).hexdigest()
- if options.verbose > 0 and not file_too_large:
- print "Uploading %s file for %s" % (type, filename)
- url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
- form_fields = [("filename", filename),
- ("status", status),
- ("checksum", checksum),
- ("is_binary", str(is_binary)),
- ("is_current", str(not is_base)),
- ]
- if file_too_large:
- form_fields.append(("file_too_large", "1"))
- if options.email:
- form_fields.append(("user", options.email))
- ctype, body = EncodeMultipartFormData(form_fields,
- [("data", filename, content)])
- response_body = rpc_server.Send(url, body,
- content_type=ctype)
- if not response_body.startswith("OK"):
- StatusUpdate(" --> %s" % response_body)
- sys.exit(1)
-
- patches = dict()
- [patches.setdefault(v, k) for k, v in patch_list]
- for filename in patches.keys():
- base_content, new_content, is_binary, status = files[filename]
- file_id_str = patches.get(filename)
- if file_id_str.find("nobase") != -1:
- base_content = None
- file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
- file_id = int(file_id_str)
- if base_content != None:
- UploadFile(filename, file_id, base_content, is_binary, status, True)
- if new_content != None:
- UploadFile(filename, file_id, new_content, is_binary, status, False)
-
- def IsImage(self, filename):
- """Returns true if the filename has an image extension."""
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype:
- return False
- return mimetype.startswith("image/")
-
- def IsBinary(self, filename):
- """Returns true if the guessed mimetyped isnt't in text group."""
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype:
- return False # e.g. README, "real" binaries usually have an extension
- # special case for text files which don't start with text/
- if mimetype in TEXT_MIMETYPES:
- return False
- return not mimetype.startswith("text/")
-
-
-class SubversionVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Subversion."""
-
- def __init__(self, options):
- super(SubversionVCS, self).__init__(options)
- if self.options.revision:
- match = re.match(r"(\d+)(:(\d+))?", self.options.revision)
- if not match:
- ErrorExit("Invalid Subversion revision %s." % self.options.revision)
- self.rev_start = match.group(1)
- self.rev_end = match.group(3)
- else:
- self.rev_start = self.rev_end = None
- # Cache output from "svn list -r REVNO dirname".
- # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
- self.svnls_cache = {}
- # Base URL is required to fetch files deleted in an older revision.
- # Result is cached to not guess it over and over again in GetBaseFile().
- required = self.options.download_base or self.options.revision is not None
- self.svn_base = self._GuessBase(required)
-
- def GuessBase(self, required):
- """Wrapper for _GuessBase."""
- return self.svn_base
-
- def _GuessBase(self, required):
- """Returns base URL for current diff.
-
- Args:
- required: If true, exits if the url can't be guessed, otherwise None is
- returned.
- """
- info = RunShell(["svn", "info"])
- for line in info.splitlines():
- if line.startswith("URL: "):
- url = line.split()[1]
- scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
- guess = ""
- if netloc == "svn.python.org" and scheme == "svn+ssh":
- path = "projects" + path
- scheme = "http"
- guess = "Python "
- elif netloc.endswith(".googlecode.com"):
- scheme = "http"
- guess = "Google Code "
- path = path + "/"
- base = urlparse.urlunparse((scheme, netloc, path, params,
- query, fragment))
- logging.info("Guessed %sbase = %s", guess, base)
- return base
- if required:
- ErrorExit("Can't find URL in output from svn info")
- return None
-
- def GenerateDiff(self, args):
- cmd = ["svn", "diff"]
- if self.options.revision:
- cmd += ["-r", self.options.revision]
- cmd.extend(args)
- data = RunShell(cmd)
- count = 0
- for line in data.splitlines():
- if line.startswith("Index:") or line.startswith("Property changes on:"):
- count += 1
- logging.info(line)
- if not count:
- ErrorExit("No valid patches found in output from svn diff")
- return data
-
- def _CollapseKeywords(self, content, keyword_str):
- """Collapses SVN keywords."""
- # svn cat translates keywords but svn diff doesn't. As a result of this
- # behavior patching.PatchChunks() fails with a chunk mismatch error.
- # This part was originally written by the Review Board development team
- # who had the same problem (http://reviews.review-board.org/r/276/).
- # Mapping of keywords to known aliases
- svn_keywords = {
- # Standard keywords
- 'Date': ['Date', 'LastChangedDate'],
- 'Revision': ['Revision', 'LastChangedRevision', 'Rev'],
- 'Author': ['Author', 'LastChangedBy'],
- 'HeadURL': ['HeadURL', 'URL'],
- 'Id': ['Id'],
-
- # Aliases
- 'LastChangedDate': ['LastChangedDate', 'Date'],
- 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'],
- 'LastChangedBy': ['LastChangedBy', 'Author'],
- 'URL': ['URL', 'HeadURL'],
- }
-
- def repl(m):
- if m.group(2):
- return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
- return "$%s$" % m.group(1)
- keywords = [keyword
- for name in keyword_str.split(" ")
- for keyword in svn_keywords.get(name, [])]
- return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content)
-
- def GetUnknownFiles(self):
- status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True)
- unknown_files = []
- for line in status.split("\n"):
- if line and line[0] == "?":
- unknown_files.append(line)
- return unknown_files
-
- def ReadFile(self, filename):
- """Returns the contents of a file."""
- file = open(filename, 'rb')
- result = ""
- try:
- result = file.read()
- finally:
- file.close()
- return result
-
- def GetStatus(self, filename):
- """Returns the status of a file."""
- if not self.options.revision:
- status = RunShell(["svn", "status", "--ignore-externals", filename])
- if not status:
- ErrorExit("svn status returned no output for %s" % filename)
- status_lines = status.splitlines()
- # If file is in a cl, the output will begin with
- # "\n--- Changelist 'cl_name':\n". See
- # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
- if (len(status_lines) == 3 and
- not status_lines[0] and
- status_lines[1].startswith("--- Changelist")):
- status = status_lines[2]
- else:
- status = status_lines[0]
- # If we have a revision to diff against we need to run "svn list"
- # for the old and the new revision and compare the results to get
- # the correct status for a file.
- else:
- dirname, relfilename = os.path.split(filename)
- if dirname not in self.svnls_cache:
- cmd = ["svn", "list", "-r", self.rev_start, dirname or "."]
- out, err, returncode = RunShellWithReturnCodeAndStderr(cmd)
- if returncode:
- # Directory might not yet exist at start revison
- # svn: Unable to find repository location for 'abc' in revision nnn
- if re.match('^svn: Unable to find repository location for .+ in revision \d+', err):
- old_files = ()
- else:
- ErrorExit("Failed to get status for %s:\n%s" % (filename, err))
- else:
- old_files = out.splitlines()
- args = ["svn", "list"]
- if self.rev_end:
- args += ["-r", self.rev_end]
- cmd = args + [dirname or "."]
- out, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- ErrorExit("Failed to run command %s" % cmd)
- self.svnls_cache[dirname] = (old_files, out.splitlines())
- old_files, new_files = self.svnls_cache[dirname]
- if relfilename in old_files and relfilename not in new_files:
- status = "D "
- elif relfilename in old_files and relfilename in new_files:
- status = "M "
- else:
- status = "A "
- return status
-
- def GetBaseFile(self, filename):
- status = self.GetStatus(filename)
- base_content = None
- new_content = None
-
- # If a file is copied its status will be "A +", which signifies
- # "addition-with-history". See "svn st" for more information. We need to
- # upload the original file or else diff parsing will fail if the file was
- # edited.
- if status[0] == "A" and status[3] != "+":
- # We'll need to upload the new content if we're adding a binary file
- # since diff's output won't contain it.
- mimetype = RunShell(["svn", "propget", "svn:mime-type", filename],
- silent_ok=True)
- base_content = ""
- is_binary = bool(mimetype) and not mimetype.startswith("text/")
- if is_binary and self.IsImage(filename):
- new_content = self.ReadFile(filename)
- elif (status[0] in ("M", "D", "R") or
- (status[0] == "A" and status[3] == "+") or # Copied file.
- (status[0] == " " and status[1] == "M")): # Property change.
- args = []
- if self.options.revision:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- else:
- # Don't change filename, it's needed later.
- url = filename
- args += ["-r", "BASE"]
- cmd = ["svn"] + args + ["propget", "svn:mime-type", url]
- mimetype, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- # File does not exist in the requested revision.
- # Reset mimetype, it contains an error message.
- mimetype = ""
- else:
- mimetype = mimetype.strip()
- get_base = False
- is_binary = (bool(mimetype) and
- not mimetype.startswith("text/") and
- not mimetype in TEXT_MIMETYPES)
- if status[0] == " ":
- # Empty base content just to force an upload.
- base_content = ""
- elif is_binary:
- if self.IsImage(filename):
- get_base = True
- if status[0] == "M":
- if not self.rev_end:
- new_content = self.ReadFile(filename)
- else:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end)
- new_content = RunShell(["svn", "cat", url],
- universal_newlines=True, silent_ok=True)
- else:
- base_content = ""
- else:
- get_base = True
-
- if get_base:
- if is_binary:
- universal_newlines = False
- else:
- universal_newlines = True
- if self.rev_start:
- # "svn cat -r REV delete_file.txt" doesn't work. cat requires
- # the full URL with "@REV" appended instead of using "-r" option.
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- base_content = RunShell(["svn", "cat", url],
- universal_newlines=universal_newlines,
- silent_ok=True)
- else:
- base_content, ret_code = RunShellWithReturnCode(
- ["svn", "cat", filename], universal_newlines=universal_newlines)
- if ret_code and status[0] == "R":
- # It's a replaced file without local history (see issue208).
- # The base file needs to be fetched from the server.
- url = "%s/%s" % (self.svn_base, filename)
- base_content = RunShell(["svn", "cat", url],
- universal_newlines=universal_newlines,
- silent_ok=True)
- elif ret_code:
- ErrorExit("Got error status from 'svn cat %s'" % filename)
- if not is_binary:
- args = []
- if self.rev_start:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- else:
- url = filename
- args += ["-r", "BASE"]
- cmd = ["svn"] + args + ["propget", "svn:keywords", url]
- keywords, returncode = RunShellWithReturnCode(cmd)
- if keywords and not returncode:
- base_content = self._CollapseKeywords(base_content, keywords)
- else:
- StatusUpdate("svn status returned unexpected output: %s" % status)
- sys.exit(1)
- return base_content, new_content, is_binary, status[0:5]
-
-
-class GitVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Git."""
-
- def __init__(self, options):
- super(GitVCS, self).__init__(options)
- # Map of filename -> (hash before, hash after) of base file.
- # Hashes for "no such file" are represented as None.
- self.hashes = {}
- # Map of new filename -> old filename for renames.
- self.renames = {}
-
- def PostProcessDiff(self, gitdiff):
- """Converts the diff output to include an svn-style "Index:" line as well
- as record the hashes of the files, so we can upload them along with our
- diff."""
- # Special used by git to indicate "no such content".
- NULL_HASH = "0"*40
-
- def IsFileNew(filename):
- return filename in self.hashes and self.hashes[filename][0] is None
-
- def AddSubversionPropertyChange(filename):
- """Add svn's property change information into the patch if given file is
- new file.
-
- We use Subversion's auto-props setting to retrieve its property.
- See http://svnbook.red-bean.com/en/1.1/ch07.html#svn-ch-7-sect-1.3.2 for
- Subversion's [auto-props] setting.
- """
- if self.options.emulate_svn_auto_props and IsFileNew(filename):
- svnprops = GetSubversionPropertyChanges(filename)
- if svnprops:
- svndiff.append("\n" + svnprops + "\n")
-
- svndiff = []
- filecount = 0
- filename = None
- for line in gitdiff.splitlines():
- match = re.match(r"diff --git a/(.*) b/(.*)$", line)
- if match:
- # Add auto property here for previously seen file.
- if filename is not None:
- AddSubversionPropertyChange(filename)
- filecount += 1
- # Intentionally use the "after" filename so we can show renames.
- filename = match.group(2)
- svndiff.append("Index: %s\n" % filename)
- if match.group(1) != match.group(2):
- self.renames[match.group(2)] = match.group(1)
- else:
- # The "index" line in a git diff looks like this (long hashes elided):
- # index 82c0d44..b2cee3f 100755
- # We want to save the left hash, as that identifies the base file.
- match = re.match(r"index (\w+)\.\.(\w+)", line)
- if match:
- before, after = (match.group(1), match.group(2))
- if before == NULL_HASH:
- before = None
- if after == NULL_HASH:
- after = None
- self.hashes[filename] = (before, after)
- svndiff.append(line + "\n")
- if not filecount:
- ErrorExit("No valid patches found in output from git diff")
- # Add auto property for the last seen file.
- assert filename is not None
- AddSubversionPropertyChange(filename)
- return "".join(svndiff)
-
- def GenerateDiff(self, extra_args):
- extra_args = extra_args[:]
- if self.options.revision:
- if ":" in self.options.revision:
- extra_args = self.options.revision.split(":", 1) + extra_args
- else:
- extra_args = [self.options.revision] + extra_args
-
- # --no-ext-diff is broken in some versions of Git, so try to work around
- # this by overriding the environment (but there is still a problem if the
- # git config key "diff.external" is used).
- env = os.environ.copy()
- if 'GIT_EXTERNAL_DIFF' in env: del env['GIT_EXTERNAL_DIFF']
- return RunShell(["git", "diff", "--no-ext-diff", "--full-index", "-M"]
- + extra_args, env=env)
-
- def GetUnknownFiles(self):
- status = RunShell(["git", "ls-files", "--exclude-standard", "--others"],
- silent_ok=True)
- return status.splitlines()
-
- def GetFileContent(self, file_hash, is_binary):
- """Returns the content of a file identified by its git hash."""
- data, retcode = RunShellWithReturnCode(["git", "show", file_hash],
- universal_newlines=not is_binary)
- if retcode:
- ErrorExit("Got error status from 'git show %s'" % file_hash)
- return data
-
- def GetBaseFile(self, filename):
- hash_before, hash_after = self.hashes.get(filename, (None,None))
- base_content = None
- new_content = None
- is_binary = self.IsBinary(filename)
- status = None
-
- if filename in self.renames:
- status = "A +" # Match svn attribute name for renames.
- if filename not in self.hashes:
- # If a rename doesn't change the content, we never get a hash.
- base_content = RunShell(["git", "show", "HEAD:" + filename])
- elif not hash_before:
- status = "A"
- base_content = ""
- elif not hash_after:
- status = "D"
- else:
- status = "M"
-
- is_image = self.IsImage(filename)
-
- # Grab the before/after content if we need it.
- # We should include file contents if it's text or it's an image.
- if not is_binary or is_image:
- # Grab the base content if we don't have it already.
- if base_content is None and hash_before:
- base_content = self.GetFileContent(hash_before, is_binary)
- # Only include the "after" file if it's an image; otherwise it
- # it is reconstructed from the diff.
- if is_image and hash_after:
- new_content = self.GetFileContent(hash_after, is_binary)
-
- return (base_content, new_content, is_binary, status)
-
-
-class MercurialVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Mercurial."""
-
- def __init__(self, options, repo_dir):
- super(MercurialVCS, self).__init__(options)
- # Absolute path to repository (we can be in a subdir)
- self.repo_dir = os.path.normpath(repo_dir)
- # Compute the subdir
- cwd = os.path.normpath(os.getcwd())
- assert cwd.startswith(self.repo_dir)
- self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
- if self.options.revision:
- self.base_rev = self.options.revision
- else:
- self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip()
-
- def _GetRelPath(self, filename):
- """Get relative path of a file according to the current directory,
- given its logical path in the repo."""
- assert filename.startswith(self.subdir), (filename, self.subdir)
- return filename[len(self.subdir):].lstrip(r"\/")
-
- def GenerateDiff(self, extra_args):
- cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
- data = RunShell(cmd, silent_ok=True)
- svndiff = []
- filecount = 0
- for line in data.splitlines():
- m = re.match("diff --git a/(\S+) b/(\S+)", line)
- if m:
- # Modify line to make it look like as it comes from svn diff.
- # With this modification no changes on the server side are required
- # to make upload.py work with Mercurial repos.
- # NOTE: for proper handling of moved/copied files, we have to use
- # the second filename.
- filename = m.group(2)
- svndiff.append("Index: %s" % filename)
- svndiff.append("=" * 67)
- filecount += 1
- logging.info(line)
- else:
- svndiff.append(line)
- if not filecount:
- ErrorExit("No valid patches found in output from hg diff")
- return "\n".join(svndiff) + "\n"
-
- def GetUnknownFiles(self):
- """Return a list of files unknown to the VCS."""
- args = []
- status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
- silent_ok=True)
- unknown_files = []
- for line in status.splitlines():
- st, fn = line.split(" ", 1)
- if st == "?":
- unknown_files.append(fn)
- return unknown_files
-
- def GetBaseFile(self, filename):
- # "hg status" and "hg cat" both take a path relative to the current subdir
- # rather than to the repo root, but "hg diff" has given us the full path
- # to the repo root.
- base_content = ""
- new_content = None
- is_binary = False
- oldrelpath = relpath = self._GetRelPath(filename)
- # "hg status -C" returns two lines for moved/copied files, one otherwise
- out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
- out = out.splitlines()
- # HACK: strip error message about missing file/directory if it isn't in
- # the working copy
- if out[0].startswith('%s: ' % relpath):
- out = out[1:]
- status, _ = out[0].split(' ', 1)
- if len(out) > 1 and status == "A":
- # Moved/copied => considered as modified, use old filename to
- # retrieve base contents
- oldrelpath = out[1].strip()
- status = "M"
- if ":" in self.base_rev:
- base_rev = self.base_rev.split(":", 1)[0]
- else:
- base_rev = self.base_rev
- if status != "A":
- base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
- silent_ok=True)
- is_binary = "\0" in base_content # Mercurial's heuristic
- if status != "R":
- new_content = open(relpath, "rb").read()
- is_binary = is_binary or "\0" in new_content
- if is_binary and base_content:
- # Fetch again without converting newlines
- base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
- silent_ok=True, universal_newlines=False)
- if not is_binary or not self.IsImage(relpath):
- new_content = None
- return base_content, new_content, is_binary, status
-
-
-# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync.
-def SplitPatch(data):
- """Splits a patch into separate pieces for each file.
-
- Args:
- data: A string containing the output of svn diff.
-
- Returns:
- A list of 2-tuple (filename, text) where text is the svn diff output
- pertaining to filename.
- """
- patches = []
- filename = None
- diff = []
- for line in data.splitlines(True):
- new_filename = None
- if line.startswith('Index:'):
- unused, new_filename = line.split(':', 1)
- new_filename = new_filename.strip()
- elif line.startswith('Property changes on:'):
- unused, temp_filename = line.split(':', 1)
- # When a file is modified, paths use '/' between directories, however
- # when a property is modified '\' is used on Windows. Make them the same
- # otherwise the file shows up twice.
- temp_filename = temp_filename.strip().replace('\\', '/')
- if temp_filename != filename:
- # File has property changes but no modifications, create a new diff.
- new_filename = temp_filename
- if new_filename:
- if filename and diff:
- patches.append((filename, ''.join(diff)))
- filename = new_filename
- diff = [line]
- continue
- if diff is not None:
- diff.append(line)
- if filename and diff:
- patches.append((filename, ''.join(diff)))
- return patches
-
-
-def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
- """Uploads a separate patch for each file in the diff output.
-
- Returns a list of [patch_key, filename] for each file.
- """
- patches = SplitPatch(data)
- rv = []
- for patch in patches:
- if len(patch[1]) > MAX_UPLOAD_SIZE:
- print ("Not uploading the patch for " + patch[0] +
- " because the file is too large.")
- continue
- form_fields = [("filename", patch[0])]
- if not options.download_base:
- form_fields.append(("content_upload", "1"))
- files = [("data", "data.diff", patch[1])]
- ctype, body = EncodeMultipartFormData(form_fields, files)
- url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
- print "Uploading patch for " + patch[0]
- response_body = rpc_server.Send(url, body, content_type=ctype)
- lines = response_body.splitlines()
- if not lines or lines[0] != "OK":
- StatusUpdate(" --> %s" % response_body)
- sys.exit(1)
- rv.append([lines[1], patch[0]])
- return rv
-
-
-def GuessVCSName():
- """Helper to guess the version control system.
-
- This examines the current directory, guesses which VersionControlSystem
- we're using, and returns an string indicating which VCS is detected.
-
- Returns:
- A pair (vcs, output). vcs is a string indicating which VCS was detected
- and is one of VCS_GIT, VCS_MERCURIAL, VCS_SUBVERSION, or VCS_UNKNOWN.
- output is a string containing any interesting output from the vcs
- detection routine, or None if there is nothing interesting.
- """
- def RunDetectCommand(vcs_type, command):
- """Helper to detect VCS by executing command.
-
- Returns:
- A pair (vcs, output) or None. Throws exception on error.
- """
- try:
- out, returncode = RunShellWithReturnCode(command)
- if returncode == 0:
- return (vcs_type, out.strip())
- except OSError, (errcode, message):
- if errcode != errno.ENOENT: # command not found code
- raise
-
- # Mercurial has a command to get the base directory of a repository
- # Try running it, but don't die if we don't have hg installed.
- # NOTE: we try Mercurial first as it can sit on top of an SVN working copy.
- res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"])
- if res != None:
- return res
-
- # Subversion has a .svn in all working directories.
- if os.path.isdir('.svn'):
- logging.info("Guessed VCS = Subversion")
- return (VCS_SUBVERSION, None)
-
- # Git has a command to test if you're in a git tree.
- # Try running it, but don't die if we don't have git installed.
- res = RunDetectCommand(VCS_GIT, ["git", "rev-parse",
- "--is-inside-work-tree"])
- if res != None:
- return res
-
- return (VCS_UNKNOWN, None)
-
-
-def GuessVCS(options):
- """Helper to guess the version control system.
-
- This verifies any user-specified VersionControlSystem (by command line
- or environment variable). If the user didn't specify one, this examines
- the current directory, guesses which VersionControlSystem we're using,
- and returns an instance of the appropriate class. Exit with an error
- if we can't figure it out.
-
- Returns:
- A VersionControlSystem instance. Exits if the VCS can't be guessed.
- """
- vcs = options.vcs
- if not vcs:
- vcs = os.environ.get("CODEREVIEW_VCS")
- if vcs:
- v = VCS_ABBREVIATIONS.get(vcs.lower())
- if v is None:
- ErrorExit("Unknown version control system %r specified." % vcs)
- (vcs, extra_output) = (v, None)
- else:
- (vcs, extra_output) = GuessVCSName()
-
- if vcs == VCS_MERCURIAL:
- if extra_output is None:
- extra_output = RunShell(["hg", "root"]).strip()
- return MercurialVCS(options, extra_output)
- elif vcs == VCS_SUBVERSION:
- return SubversionVCS(options)
- elif vcs == VCS_GIT:
- return GitVCS(options)
-
- ErrorExit(("Could not guess version control system. "
- "Are you in a working copy directory?"))
-
-
-def CheckReviewer(reviewer):
- """Validate a reviewer -- either a nickname or an email addres.
-
- Args:
- reviewer: A nickname or an email address.
-
- Calls ErrorExit() if it is an invalid email address.
- """
- if "@" not in reviewer:
- return # Assume nickname
- parts = reviewer.split("@")
- if len(parts) > 2:
- ErrorExit("Invalid email address: %r" % reviewer)
- assert len(parts) == 2
- if "." not in parts[1]:
- ErrorExit("Invalid email address: %r" % reviewer)
-
-
-def LoadSubversionAutoProperties():
- """Returns the content of [auto-props] section of Subversion's config file as
- a dictionary.
-
- Returns:
- A dictionary whose key-value pair corresponds the [auto-props] section's
- key-value pair.
- In following cases, returns empty dictionary:
- - config file doesn't exist, or
- - 'enable-auto-props' is not set to 'true-like-value' in [miscellany].
- """
- if os.name == 'nt':
- subversion_config = os.environ.get("APPDATA") + "\\Subversion\\config"
- else:
- subversion_config = os.path.expanduser("~/.subversion/config")
- if not os.path.exists(subversion_config):
- return {}
- config = ConfigParser.ConfigParser()
- config.read(subversion_config)
- if (config.has_section("miscellany") and
- config.has_option("miscellany", "enable-auto-props") and
- config.getboolean("miscellany", "enable-auto-props") and
- config.has_section("auto-props")):
- props = {}
- for file_pattern in config.options("auto-props"):
- props[file_pattern] = ParseSubversionPropertyValues(
- config.get("auto-props", file_pattern))
- return props
- else:
- return {}
-
-def ParseSubversionPropertyValues(props):
- """Parse the given property value which comes from [auto-props] section and
- returns a list whose element is a (svn_prop_key, svn_prop_value) pair.
-
- See the following doctest for example.
-
- >>> ParseSubversionPropertyValues('svn:eol-style=LF')
- [('svn:eol-style', 'LF')]
- >>> ParseSubversionPropertyValues('svn:mime-type=image/jpeg')
- [('svn:mime-type', 'image/jpeg')]
- >>> ParseSubversionPropertyValues('svn:eol-style=LF;svn:executable')
- [('svn:eol-style', 'LF'), ('svn:executable', '*')]
- """
- key_value_pairs = []
- for prop in props.split(";"):
- key_value = prop.split("=")
- assert len(key_value) <= 2
- if len(key_value) == 1:
- # If value is not given, use '*' as a Subversion's convention.
- key_value_pairs.append((key_value[0], "*"))
- else:
- key_value_pairs.append((key_value[0], key_value[1]))
- return key_value_pairs
-
-
-def GetSubversionPropertyChanges(filename):
- """Return a Subversion's 'Property changes on ...' string, which is used in
- the patch file.
-
- Args:
- filename: filename whose property might be set by [auto-props] config.
-
- Returns:
- A string like 'Property changes on |filename| ...' if given |filename|
- matches any entries in [auto-props] section. None, otherwise.
- """
- global svn_auto_props_map
- if svn_auto_props_map is None:
- svn_auto_props_map = LoadSubversionAutoProperties()
-
- all_props = []
- for file_pattern, props in svn_auto_props_map.items():
- if fnmatch.fnmatch(filename, file_pattern):
- all_props.extend(props)
- if all_props:
- return FormatSubversionPropertyChanges(filename, all_props)
- return None
-
-
-def FormatSubversionPropertyChanges(filename, props):
- """Returns Subversion's 'Property changes on ...' strings using given filename
- and properties.
-
- Args:
- filename: filename
- props: A list whose element is a (svn_prop_key, svn_prop_value) pair.
-
- Returns:
- A string which can be used in the patch file for Subversion.
-
- See the following doctest for example.
-
- >>> print FormatSubversionPropertyChanges('foo.cc', [('svn:eol-style', 'LF')])
- Property changes on: foo.cc
- ___________________________________________________________________
- Added: svn:eol-style
- + LF
- <BLANKLINE>
- """
- prop_changes_lines = [
- "Property changes on: %s" % filename,
- "___________________________________________________________________"]
- for key, value in props:
- prop_changes_lines.append("Added: " + key)
- prop_changes_lines.append(" + " + value)
- return "\n".join(prop_changes_lines) + "\n"
-
-
-def RealMain(argv, data=None):
- """The real main function.
-
- Args:
- argv: Command line arguments.
- data: Diff contents. If None (default) the diff is generated by
- the VersionControlSystem implementation returned by GuessVCS().
-
- Returns:
- A 2-tuple (issue id, patchset id).
- The patchset id is None if the base files are not uploaded by this
- script (applies only to SVN checkouts).
- """
- options, args = parser.parse_args(argv[1:])
- global verbosity
- verbosity = options.verbose
- if verbosity >= 3:
- logging.getLogger().setLevel(logging.DEBUG)
- elif verbosity >= 2:
- logging.getLogger().setLevel(logging.INFO)
-
- vcs = GuessVCS(options)
-
- base = options.base_url
- if isinstance(vcs, SubversionVCS):
- # Guessing the base field is only supported for Subversion.
- # Note: Fetching base files may become deprecated in future releases.
- guessed_base = vcs.GuessBase(options.download_base)
- if base:
- if guessed_base and base != guessed_base:
- print "Using base URL \"%s\" from --base_url instead of \"%s\"" % \
- (base, guessed_base)
- else:
- base = guessed_base
-
- if not base and options.download_base:
- options.download_base = True
- logging.info("Enabled upload of base file")
- if not options.assume_yes:
- vcs.CheckForUnknownFiles()
- if data is None:
- data = vcs.GenerateDiff(args)
- data = vcs.PostProcessDiff(data)
- files = vcs.GetBaseFiles(data)
- if verbosity >= 1:
- print "Upload server:", options.server, "(change with -s/--server)"
- if options.issue:
- prompt = "Message describing this patch set: "
- else:
- prompt = "New issue subject: "
- message = options.message or raw_input(prompt).strip()
- if not message:
- ErrorExit("A non-empty message is required")
- rpc_server = GetRpcServer(options.server,
- options.email,
- options.host,
- options.save_cookies,
- options.account_type)
- form_fields = [("subject", message)]
- if base:
- b = urlparse.urlparse(base)
- username, netloc = urllib.splituser(b.netloc)
- if username:
- logging.info("Removed username from base URL")
- base = urlparse.urlunparse((b.scheme, netloc, b.path, b.params,
- b.query, b.fragment))
- form_fields.append(("base", base))
- if options.issue:
- form_fields.append(("issue", str(options.issue)))
- if options.email:
- form_fields.append(("user", options.email))
- if options.reviewers:
- for reviewer in options.reviewers.split(','):
- CheckReviewer(reviewer)
- form_fields.append(("reviewers", options.reviewers))
- if options.cc:
- for cc in options.cc.split(','):
- CheckReviewer(cc)
- form_fields.append(("cc", options.cc))
- description = options.description
- if options.description_file:
- if options.description:
- ErrorExit("Can't specify description and description_file")
- file = open(options.description_file, 'r')
- description = file.read()
- file.close()
- if description:
- form_fields.append(("description", description))
- # Send a hash of all the base file so the server can determine if a copy
- # already exists in an earlier patchset.
- base_hashes = ""
- for file, info in files.iteritems():
- if not info[0] is None:
- checksum = md5(info[0]).hexdigest()
- if base_hashes:
- base_hashes += "|"
- base_hashes += checksum + ":" + file
- form_fields.append(("base_hashes", base_hashes))
- if options.private:
- if options.issue:
- print "Warning: Private flag ignored when updating an existing issue."
- else:
- form_fields.append(("private", "1"))
- # If we're uploading base files, don't send the email before the uploads, so
- # that it contains the file status.
- if options.send_mail and options.download_base:
- form_fields.append(("send_mail", "1"))
- if not options.download_base:
- form_fields.append(("content_upload", "1"))
- if len(data) > MAX_UPLOAD_SIZE:
- print "Patch is large, so uploading file patches separately."
- uploaded_diff_file = []
- form_fields.append(("separate_patches", "1"))
- else:
- uploaded_diff_file = [("data", "data.diff", data)]
- ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
- response_body = rpc_server.Send("/upload", body, content_type=ctype)
- patchset = None
- if not options.download_base or not uploaded_diff_file:
- lines = response_body.splitlines()
- if len(lines) >= 2:
- msg = lines[0]
- patchset = lines[1].strip()
- patches = [x.split(" ", 1) for x in lines[2:]]
- else:
- msg = response_body
- else:
- msg = response_body
- StatusUpdate(msg)
- if not response_body.startswith("Issue created.") and \
- not response_body.startswith("Issue updated."):
- sys.exit(0)
- issue = msg[msg.rfind("/")+1:]
-
- if not uploaded_diff_file:
- result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
- if not options.download_base:
- patches = result
-
- if not options.download_base:
- vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files)
- if options.send_mail:
- rpc_server.Send("/" + issue + "/mail", payload="")
- return issue, patchset
-
-
-def main():
- try:
- logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
- "%(lineno)s %(message)s "))
- os.environ['LC_ALL'] = 'C'
- RealMain(sys.argv)
- except KeyboardInterrupt:
- print
- StatusUpdate("Interrupted.")
- sys.exit(1)
-
-
-if __name__ == "__main__":
- main()
-
+#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import print_function + +from six import PY3 + +"""Tool for uploading diffs from a version control system to the codereview app. + +Usage summary: upload.py [options] [-- diff_options] [path...] + +Diff options are passed to the diff command of the underlying system. + +Supported version control systems: + Git + Mercurial + Subversion + +It is important for Git/Mercurial users to specify a tree/node/branch to diff +against by using the '--rev' option. +""" +# This code is derived from appcfg.py in the App Engine SDK (open source), +# and from ASPN recipe #146306. + +if PY3: + from configparser import ConfigParser +else: + from ConfigParser import ConfigParser +if PY3: + from http.cookiejar import ( + CookieJar, MozillaCookieJar, LoadError as CookieLoadError) +else: + from cookielib import ( + CookieJar, MozillaCookieJar, LoadError as CookieLoadError) +import fnmatch +import getpass +import logging +import mimetypes +import optparse +import os +import re +import socket +import subprocess +import sys +if PY3: + from urllib.request import ( + Request, OpenerDirector, + ProxyHandler, UnknownHandler, HTTPHandler, HTTPSHandler, + HTTPDefaultErrorHandler, HTTPErrorProcessor, + HTTPCookieProcessor) + from urllib.error import HTTPError + from urllib.parse import ( + urlencode, urlparse, urlunparse, splituser as urlsplituser) +else: + from urllib2 import ( + Request, OpenerDirector, + ProxyHandler, UnknownHandler, HTTPHandler, HTTPSHandler, + HTTPDefaultErrorHandler, HTTPErrorProcessor, HTTPError, + HTTPCookieProcessor, + urlparse) + from urllib import urlencode, splituser as urlsplituser + from urlparse import urlparse, urlunparse +import urllib.request, urllib.parse, urllib.error +import urllib.request, urllib.error, urllib.parse +import urllib.parse + +# The md5 module was deprecated in Python 2.5. +try: + from hashlib import md5 +except ImportError: + from md5 import md5 + +try: + import readline +except ImportError: + pass + +try: + import keyring +except ImportError: + keyring = None + +# The logging verbosity: +# 0: Errors only. +# 1: Status messages. +# 2: Info logs. +# 3: Debug logs. +verbosity = 1 + +# The account type used for authentication. +# This line could be changed by the review server (see handler for +# upload.py). +AUTH_ACCOUNT_TYPE = "GOOGLE" + +# URL of the default review server. As for AUTH_ACCOUNT_TYPE, this line could be +# changed by the review server (see handler for upload.py). +DEFAULT_REVIEW_SERVER = "codereview.appspot.com" + +# Max size of patch or base file. +MAX_UPLOAD_SIZE = 900 * 1024 + +# Constants for version control names. Used by GuessVCSName. +VCS_GIT = "Git" +VCS_MERCURIAL = "Mercurial" +VCS_SUBVERSION = "Subversion" +VCS_UNKNOWN = "Unknown" + +# whitelist for non-binary filetypes which do not start with "text/" +# .mm (Objective-C) shows up as application/x-freemind on my Linux box. +TEXT_MIMETYPES = ['application/javascript', 'application/x-javascript', + 'application/xml', 'application/x-freemind', + 'application/x-sh'] + +VCS_ABBREVIATIONS = { + VCS_MERCURIAL.lower(): VCS_MERCURIAL, + "hg": VCS_MERCURIAL, + VCS_SUBVERSION.lower(): VCS_SUBVERSION, + "svn": VCS_SUBVERSION, + VCS_GIT.lower(): VCS_GIT, +} + +# The result of parsing Subversion's [auto-props] setting. +svn_auto_props_map = None + +def GetEmail(prompt): + """Prompts the user for their email address and returns it. + + The last used email address is saved to a file and offered up as a suggestion + to the user. If the user presses enter without typing in anything the last + used email address is used. If the user enters a new address, it is saved + for next time we prompt. + + """ + last_email_file_name = os.path.expanduser("~/.last_codereview_email_address") + last_email = "" + if os.path.exists(last_email_file_name): + try: + last_email_file = open(last_email_file_name, "r") + last_email = last_email_file.readline().strip("\n") + last_email_file.close() + prompt += " [%s]" % last_email + except IOError as e: + pass + email = input(prompt + ": ").strip() + if email: + try: + last_email_file = open(last_email_file_name, "w") + last_email_file.write(email) + last_email_file.close() + except IOError as e: + pass + else: + email = last_email + return email + + +def StatusUpdate(msg): + """Print a status message to stdout. + + If 'verbosity' is greater than 0, print the message. + + Args: + msg: The string to print. + """ + if verbosity > 0: + print(msg) + + +def ErrorExit(msg): + """Print an error message to stderr and exit.""" + print(msg, file=sys.stderr) + sys.exit(1) + + +class ClientLoginError(HTTPError): + """Raised to indicate there was an error authenticating with ClientLogin.""" + + def __init__(self, url, code, msg, headers, args): + HTTPError.__init__(self, url, code, msg, headers, None) + self.args = args + self.reason = args["Error"] + self.info = args.get("Info", None) + + +class AbstractRpcServer(object): + """Provides a common interface for a simple RPC server.""" + + def __init__(self, host, auth_function, host_override=None, extra_headers={}, + save_cookies=False, account_type=AUTH_ACCOUNT_TYPE): + """Creates a new HttpRpcServer. + + Args: + host: The host to send requests to. + auth_function: A function that takes no arguments and returns an + (email, password) tuple when called. Will be called if authentication + is required. + host_override: The host header to send to the server (defaults to host). + extra_headers: A dict of extra headers to append to every request. + save_cookies: If True, save the authentication cookies to local disk. + If False, use an in-memory cookiejar instead. Subclasses must + implement this functionality. Defaults to False. + account_type: Account type used for authentication. Defaults to + AUTH_ACCOUNT_TYPE. + """ + self.host = host + if (not self.host.startswith("http://") and + not self.host.startswith("https://")): + self.host = "http://" + self.host + self.host_override = host_override + self.auth_function = auth_function + self.authenticated = False + self.extra_headers = extra_headers + self.save_cookies = save_cookies + self.account_type = account_type + self.opener = self._GetOpener() + if self.host_override: + logging.info("Server: %s; Host: %s", self.host, self.host_override) + else: + logging.info("Server: %s", self.host) + + def _GetOpener(self): + """Returns an OpenerDirector for making HTTP requests. + + Returns: + A urllib2.OpenerDirector object. + """ + raise NotImplementedError() + + def _CreateRequest(self, url, data=None): + """Creates a new urllib request.""" + logging.debug("Creating request for: '%s' with payload:\n%s", url, data) + req = Request(url, data=data) + if self.host_override: + req.add_header("Host", self.host_override) + for key, value in self.extra_headers.items(): + req.add_header(key, value) + return req + + def _GetAuthToken(self, email, password): + """Uses ClientLogin to authenticate the user, returning an auth token. + + Args: + email: The user's email address + password: The user's password + + Raises: + ClientLoginError: If there was an error authenticating with ClientLogin. + HTTPError: If there was some other form of HTTP error. + + Returns: + The authentication token returned by ClientLogin. + """ + account_type = self.account_type + if self.host.endswith(".google.com"): + # Needed for use inside Google. + account_type = "HOSTED" + req = self._CreateRequest( + url="https://www.google.com/accounts/ClientLogin", + data=urlencode({ + "Email": email, + "Passwd": password, + "service": "ah", + "source": "rietveld-codereview-upload", + "accountType": account_type, + }), + ) + try: + response = self.opener.open(req) + response_body = response.read() + response_dict = dict(x.split("=") + for x in response_body.split("\n") if x) + return response_dict["Auth"] + except HTTPError as e: + if e.code == 403: + body = e.read() + response_dict = dict(x.split("=", 1) for x in body.split("\n") if x) + raise ClientLoginError(req.get_full_url(), e.code, e.msg, + e.headers, response_dict) + else: + raise + + def _GetAuthCookie(self, auth_token): + """Fetches authentication cookies for an authentication token. + + Args: + auth_token: The authentication token returned by ClientLogin. + + Raises: + HTTPError: If there was an error fetching the authentication cookies. + """ + # This is a dummy value to allow us to identify when we're successful. + continue_location = "http://localhost/" + args = {"continue": continue_location, "auth": auth_token} + req = self._CreateRequest("%s/_ah/login?%s" % + (self.host, urlencode(args))) + try: + response = self.opener.open(req) + except HTTPError as e: + response = e + if (response.code != 302 or + response.info()["location"] != continue_location): + raise HTTPError(req.get_full_url(), response.code, response.msg, + response.headers, response.fp) + self.authenticated = True + + def _Authenticate(self): + """Authenticates the user. + + The authentication process works as follows: + 1) We get a username and password from the user + 2) We use ClientLogin to obtain an AUTH token for the user + (see http://code.google.com/apis/accounts/AuthForInstalledApps.html). + 3) We pass the auth token to /_ah/login on the server to obtain an + authentication cookie. If login was successful, it tries to redirect + us to the URL we provided. + + If we attempt to access the upload API without first obtaining an + authentication cookie, it returns a 401 response (or a 302) and + directs us to authenticate ourselves with ClientLogin. + """ + for i in range(3): + credentials = self.auth_function() + try: + auth_token = self._GetAuthToken(credentials[0], credentials[1]) + except ClientLoginError as e: + print(file=sys.stderr) + if e.reason == "BadAuthentication": + if e.info == "InvalidSecondFactor": + print("Use an application-specific password instead " + "of your regular account password.\n" + "See http://www.google.com/" + "support/accounts/bin/answer.py?answer=185833", + file=sys.stderr) + else: + print("Invalid username or password.", file=sys.stderr) + elif e.reason == "CaptchaRequired": + print("Please go to\n" + "https://www.google.com/accounts/DisplayUnlockCaptcha\n" + "and verify you are a human. Then try again.\n" + "If you are using a Google Apps account the URL is:\n" + "https://www.google.com/a/yourdomain.com/UnlockCaptcha", + file=sys.stderr) + elif e.reason == "NotVerified": + print("Account not verified.", file=sys.stderr) + elif e.reason == "TermsNotAgreed": + print("User has not agreed to TOS.", file=sys.stderr) + elif e.reason == "AccountDeleted": + print("The user account has been deleted.", file=sys.stderr) + elif e.reason == "AccountDisabled": + print("The user account has been disabled.", file=sys.stderr) + break + elif e.reason == "ServiceDisabled": + print("The user's access to the service has been disabled.", + file=sys.stderr) + elif e.reason == "ServiceUnavailable": + print("The service is not available; try again later.", + file=sys.stderr) + else: + # Unknown error. + raise + print(file=sys.stderr) + continue + self._GetAuthCookie(auth_token) + return + + def Send(self, request_path, payload=None, + content_type="application/octet-stream", + timeout=None, + extra_headers=None, + **kwargs): + """Sends an RPC and returns the response. + + Args: + request_path: The path to send the request to, eg /api/appversion/create. + payload: The body of the request, or None to send an empty request. + content_type: The Content-Type header to use. + timeout: timeout in seconds; default None i.e. no timeout. + (Note: for large requests on OS X, the timeout doesn't work right.) + extra_headers: Dict containing additional HTTP headers that should be + included in the request (string header names mapped to their values), + or None to not include any additional headers. + kwargs: Any keyword arguments are converted into query string parameters. + + Returns: + The response body, as a string. + """ + # TODO: Don't require authentication. Let the server say + # whether it is necessary. + if not self.authenticated: + self._Authenticate() + + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + tries = 0 + while True: + tries += 1 + args = dict(kwargs) + url = "%s%s" % (self.host, request_path) + if args: + url += "?" + urlencode(args) + req = self._CreateRequest(url=url, data=payload) + req.add_header("Content-Type", content_type) + if extra_headers: + for header, value in extra_headers.items(): + req.add_header(header, value) + try: + f = self.opener.open(req) + response = f.read() + f.close() + return response + except HTTPError as e: + if tries > 3: + raise + elif e.code == 401 or e.code == 302: + self._Authenticate() +## elif e.code >= 500 and e.code < 600: +## # Server Error - try again. +## continue + elif e.code == 301: + # Handle permanent redirect manually. + url = e.info()["location"] + url_loc = urlparse(url) + self.host = '%s://%s' % (url_loc[0], url_loc[1]) + else: + raise + finally: + socket.setdefaulttimeout(old_timeout) + + +class HttpRpcServer(AbstractRpcServer): + """Provides a simplified RPC-style interface for HTTP requests.""" + + def _Authenticate(self): + """Save the cookie jar after authentication.""" + super(HttpRpcServer, self)._Authenticate() + if self.save_cookies: + StatusUpdate("Saving authentication cookies to %s" % self.cookie_file) + self.cookie_jar.save() + + def _GetOpener(self): + """Returns an OpenerDirector that supports cookies and ignores redirects. + + Returns: + A urllib2.OpenerDirector object. + """ + opener = OpenerDirector() + opener.add_handler(ProxyHandler()) + opener.add_handler(UnknownHandler()) + opener.add_handler(HTTPHandler()) + opener.add_handler(HTTPDefaultErrorHandler()) + opener.add_handler(HTTPSHandler()) + opener.add_handler(HTTPErrorProcessor()) + if self.save_cookies: + self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies") + self.cookie_jar = MozillaCookieJar(self.cookie_file) + if os.path.exists(self.cookie_file): + try: + self.cookie_jar.load() + self.authenticated = True + StatusUpdate("Loaded authentication cookies from %s" % + self.cookie_file) + except (CookieLoadError, IOError): + # Failed to load cookies - just ignore them. + pass + else: + # Create an empty cookie file with mode 600 + fd = os.open(self.cookie_file, os.O_CREAT, 0o600) + os.close(fd) + # Always chmod the cookie file + os.chmod(self.cookie_file, 0o600) + else: + # Don't save cookies across runs of update.py. + self.cookie_jar = CookieJar() + opener.add_handler(HTTPCookieProcessor(self.cookie_jar)) + return opener + + +parser = optparse.OptionParser( + usage="%prog [options] [-- diff_options] [path...]") +parser.add_option("-y", "--assume_yes", action="store_true", + dest="assume_yes", default=False, + help="Assume that the answer to yes/no questions is 'yes'.") +# Logging +group = parser.add_option_group("Logging options") +group.add_option("-q", "--quiet", action="store_const", const=0, + dest="verbose", help="Print errors only.") +group.add_option("-v", "--verbose", action="store_const", const=2, + dest="verbose", default=1, + help="Print info level logs.") +group.add_option("--noisy", action="store_const", const=3, + dest="verbose", help="Print all logs.") +# Review server +group = parser.add_option_group("Review server options") +group.add_option("-s", "--server", action="store", dest="server", + default=DEFAULT_REVIEW_SERVER, + metavar="SERVER", + help=("The server to upload to. The format is host[:port]. " + "Defaults to '%default'.")) +group.add_option("-e", "--email", action="store", dest="email", + metavar="EMAIL", default=None, + help="The username to use. Will prompt if omitted.") +group.add_option("-H", "--host", action="store", dest="host", + metavar="HOST", default=None, + help="Overrides the Host header sent with all RPCs.") +group.add_option("--no_cookies", action="store_false", + dest="save_cookies", default=True, + help="Do not save authentication cookies to local disk.") +group.add_option("--account_type", action="store", dest="account_type", + metavar="TYPE", default=AUTH_ACCOUNT_TYPE, + choices=["GOOGLE", "HOSTED"], + help=("Override the default account type " + "(defaults to '%default', " + "valid choices are 'GOOGLE' and 'HOSTED').")) +# Issue +group = parser.add_option_group("Issue options") +group.add_option("-d", "--description", action="store", dest="description", + metavar="DESCRIPTION", default=None, + help="Optional description when creating an issue.") +group.add_option("-f", "--description_file", action="store", + dest="description_file", metavar="DESCRIPTION_FILE", + default=None, + help="Optional path of a file that contains " + "the description when creating an issue.") +group.add_option("-r", "--reviewers", action="store", dest="reviewers", + metavar="REVIEWERS", default=None, + help="Add reviewers (comma separated email addresses).") +group.add_option("--cc", action="store", dest="cc", + metavar="CC", default="dev@scons.tigris.org", + help="Add CC (comma separated email addresses).") +group.add_option("--private", action="store_true", dest="private", + default=False, + help="Make the issue restricted to reviewers and those CCed") +# Upload options +group = parser.add_option_group("Patch options") +group.add_option("-m", "--message", action="store", dest="message", + metavar="MESSAGE", default=None, + help="A message to identify the patch. " + "Will prompt if omitted.") +group.add_option("-i", "--issue", type="int", action="store", + metavar="ISSUE", default=None, + help="Issue number to which to add. Defaults to new issue.") +group.add_option("--base_url", action="store", dest="base_url", default=None, + help="Base repository URL (listed as \"Base URL\" when " + "viewing issue). If omitted, will be guessed automatically " + "for SVN repos and left blank for others.") +group.add_option("--download_base", action="store_true", + dest="download_base", default=False, + help="Base files will be downloaded by the server " + "(side-by-side diffs may not work on files with CRs).") +group.add_option("--rev", action="store", dest="revision", + metavar="REV", default=None, + help="Base revision/branch/tree to diff against. Use " + "rev1:rev2 range to review already committed changeset.") +group.add_option("--send_mail", action="store_true", + dest="send_mail", default=True, + help="Send notification email to reviewers.") +group.add_option("--vcs", action="store", dest="vcs", + metavar="VCS", default="svn", + help=("Version control system (optional, usually upload.py " + "already guesses the right VCS).")) +group.add_option("--emulate_svn_auto_props", action="store_true", + dest="emulate_svn_auto_props", default=False, + help=("Emulate Subversion's auto properties feature.")) + + +def GetRpcServer(server, email=None, host_override=None, save_cookies=True, + account_type=AUTH_ACCOUNT_TYPE): + """Returns an instance of an AbstractRpcServer. + + Args: + server: String containing the review server URL. + email: String containing user's email address. + host_override: If not None, string containing an alternate hostname to use + in the host header. + save_cookies: Whether authentication cookies should be saved to disk. + account_type: Account type for authentication, either 'GOOGLE' + or 'HOSTED'. Defaults to AUTH_ACCOUNT_TYPE. + + Returns: + A new AbstractRpcServer, on which RPC calls can be made. + """ + + rpc_server_class = HttpRpcServer + + # If this is the dev_appserver, use fake authentication. + host = (host_override or server).lower() + if re.match(r'(http://)?localhost([:/]|$)', host): + if email is None: + email = "test@example.com" + logging.info("Using debug user %s. Override with --email" % email) + server = rpc_server_class( + server, + lambda: (email, "password"), + host_override=host_override, + extra_headers={"Cookie": + 'dev_appserver_login="%s:False"' % email}, + save_cookies=save_cookies, + account_type=account_type) + # Don't try to talk to ClientLogin. + server.authenticated = True + return server + + def GetUserCredentials(): + """Prompts the user for a username and password.""" + # Create a local alias to the email variable to avoid Python's crazy + # scoping rules. + local_email = email + if local_email is None: + local_email = GetEmail("Email (login for uploading to %s)" % server) + password = None + if keyring: + password = keyring.get_password(host, local_email) + if password is not None: + print("Using password from system keyring.") + else: + password = getpass.getpass("Password for %s: " % local_email) + if keyring: + answer = input("Store password in system keyring?(y/N) ").strip() + if answer == "y": + keyring.set_password(host, local_email, password) + return (local_email, password) + + return rpc_server_class(server, + GetUserCredentials, + host_override=host_override, + save_cookies=save_cookies) + + +def EncodeMultipartFormData(fields, files): + """Encode form fields for multipart/form-data. + + Args: + fields: A sequence of (name, value) elements for regular form fields. + files: A sequence of (name, filename, value) elements for data to be + uploaded as files. + Returns: + (content_type, body) ready for httplib.HTTP instance. + + Source: + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306 + """ + BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-' + CRLF = '\r\n' + lines = [] + for (key, value) in fields: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"' % key) + lines.append('') + if isinstance(value, str): + value = value.encode('utf-8') + lines.append(value) + for (key, filename, value) in files: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)) + lines.append('Content-Type: %s' % GetContentType(filename)) + lines.append('') + if isinstance(value, str): + value = value.encode('utf-8') + lines.append(value) + lines.append('--' + BOUNDARY + '--') + lines.append('') + body = CRLF.join(lines) + content_type = 'multipart/form-data; boundary=%s' % BOUNDARY + return content_type, body + + +def GetContentType(filename): + """Helper to guess the content-type from the filename.""" + return mimetypes.guess_type(filename)[0] or 'application/octet-stream' + + +# Use a shell for subcommands on Windows to get a PATH search. +use_shell = sys.platform.startswith("win") + +def RunShellWithReturnCodeAndStderr(command, print_output=False, + universal_newlines=True, + env=os.environ): + """Executes a command and returns the output from stdout, stderr and the return code. + + Args: + command: Command to execute. + print_output: If True, the output is printed to stdout. + If False, both stdout and stderr are ignored. + universal_newlines: Use universal_newlines flag (default: True). + + Returns: + Tuple (stdout, stderr, return code) + """ + logging.info("Running %s", command) + env = env.copy() + env['LC_MESSAGES'] = 'C' + p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=use_shell, universal_newlines=universal_newlines, + env=env) + if print_output: + output_array = [] + while True: + line = p.stdout.readline() + if not line: + break + print(line.strip("\n")) + output_array.append(line) + output = "".join(output_array) + else: + output = p.stdout.read() + p.wait() + errout = p.stderr.read() + if print_output and errout: + print(errout, file=sys.stderr) + p.stdout.close() + p.stderr.close() + return output, errout, p.returncode + +def RunShellWithReturnCode(command, print_output=False, + universal_newlines=True, + env=os.environ): + """Executes a command and returns the output from stdout and the return code.""" + out, err, retcode = RunShellWithReturnCodeAndStderr(command, print_output, + universal_newlines, env) + return out, retcode + +def RunShell(command, silent_ok=False, universal_newlines=True, + print_output=False, env=os.environ): + data, retcode = RunShellWithReturnCode(command, print_output, + universal_newlines, env) + if retcode: + ErrorExit("Got error status from %s:\n%s" % (command, data)) + if not silent_ok and not data: + ErrorExit("No output from %s" % command) + return data + + +class VersionControlSystem(object): + """Abstract base class providing an interface to the VCS.""" + + def __init__(self, options): + """Constructor. + + Args: + options: Command line options. + """ + self.options = options + + def PostProcessDiff(self, diff): + """Return the diff with any special post processing this VCS needs, e.g. + to include an svn-style "Index:".""" + return diff + + def GenerateDiff(self, args): + """Return the current diff as a string. + + Args: + args: Extra arguments to pass to the diff command. + """ + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def CheckForUnknownFiles(self): + """Show an "are you sure?" prompt if there are unknown files.""" + unknown_files = self.GetUnknownFiles() + if unknown_files: + print("The following files are not added to version control:") + for line in unknown_files: + print(line) + prompt = "Are you sure to continue?(y/N) " + answer = input(prompt).strip() + if answer != "y": + ErrorExit("User aborted") + + def GetBaseFile(self, filename): + """Get the content of the upstream version of a file. + + Returns: + A tuple (base_content, new_content, is_binary, status) + base_content: The contents of the base file. + new_content: For text files, this is empty. For binary files, this is + the contents of the new file, since the diff output won't contain + information to reconstruct the current file. + is_binary: True iff the file is binary. + status: The status of the file. + """ + + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + + def GetBaseFiles(self, diff): + """Helper that calls GetBase file for each file in the patch. + + Returns: + A dictionary that maps from filename to GetBaseFile's tuple. Filenames + are retrieved based on lines that start with "Index:" or + "Property changes on:". + """ + files = {} + for line in diff.splitlines(True): + if line.startswith('Index:') or line.startswith('Property changes on:'): + unused, filename = line.split(':', 1) + # On Windows if a file has property changes its filename uses '\' + # instead of '/'. + filename = filename.strip().replace('\\', '/') + files[filename] = self.GetBaseFile(filename) + return files + + + def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, + files): + """Uploads the base files (and if necessary, the current ones as well).""" + + def UploadFile(filename, file_id, content, is_binary, status, is_base): + """Uploads a file to the server.""" + file_too_large = False + if is_base: + type = "base" + else: + type = "current" + if len(content) > MAX_UPLOAD_SIZE: + print("Not uploading the %s file for %s because it's too large." % + (type, filename)) + file_too_large = True + content = "" + checksum = md5(content).hexdigest() + if options.verbose > 0 and not file_too_large: + print("Uploading %s file for %s" % (type, filename)) + url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id) + form_fields = [("filename", filename), + ("status", status), + ("checksum", checksum), + ("is_binary", str(is_binary)), + ("is_current", str(not is_base)), + ] + if file_too_large: + form_fields.append(("file_too_large", "1")) + if options.email: + form_fields.append(("user", options.email)) + ctype, body = EncodeMultipartFormData(form_fields, + [("data", filename, content)]) + response_body = rpc_server.Send(url, body, + content_type=ctype) + if not response_body.startswith("OK"): + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + + patches = dict() + [patches.setdefault(v, k) for k, v in patch_list] + for filename in patches.keys(): + base_content, new_content, is_binary, status = files[filename] + file_id_str = patches.get(filename) + if file_id_str.find("nobase") != -1: + base_content = None + file_id_str = file_id_str[file_id_str.rfind("_") + 1:] + file_id = int(file_id_str) + if base_content != None: + UploadFile(filename, file_id, base_content, is_binary, status, True) + if new_content != None: + UploadFile(filename, file_id, new_content, is_binary, status, False) + + def IsImage(self, filename): + """Returns true if the filename has an image extension.""" + mimetype = mimetypes.guess_type(filename)[0] + if not mimetype: + return False + return mimetype.startswith("image/") + + def IsBinary(self, filename): + """Returns true if the guessed mimetyped isnt't in text group.""" + mimetype = mimetypes.guess_type(filename)[0] + if not mimetype: + return False # e.g. README, "real" binaries usually have an extension + # special case for text files which don't start with text/ + if mimetype in TEXT_MIMETYPES: + return False + return not mimetype.startswith("text/") + + +class SubversionVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Subversion.""" + + def __init__(self, options): + super(SubversionVCS, self).__init__(options) + if self.options.revision: + match = re.match(r"(\d+)(:(\d+))?", self.options.revision) + if not match: + ErrorExit("Invalid Subversion revision %s." % self.options.revision) + self.rev_start = match.group(1) + self.rev_end = match.group(3) + else: + self.rev_start = self.rev_end = None + # Cache output from "svn list -r REVNO dirname". + # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev). + self.svnls_cache = {} + # Base URL is required to fetch files deleted in an older revision. + # Result is cached to not guess it over and over again in GetBaseFile(). + required = self.options.download_base or self.options.revision is not None + self.svn_base = self._GuessBase(required) + + def GuessBase(self, required): + """Wrapper for _GuessBase.""" + return self.svn_base + + def _GuessBase(self, required): + """Returns base URL for current diff. + + Args: + required: If true, exits if the url can't be guessed, otherwise None is + returned. + """ + info = RunShell(["svn", "info"]) + for line in info.splitlines(): + if line.startswith("URL: "): + url = line.split()[1] + scheme, netloc, path, params, query, fragment = urlparse(url) + guess = "" + if netloc == "svn.python.org" and scheme == "svn+ssh": + path = "projects" + path + scheme = "http" + guess = "Python " + elif netloc.endswith(".googlecode.com"): + scheme = "http" + guess = "Google Code " + path = path + "/" + base = urlunparse((scheme, netloc, path, params, query, fragment)) + logging.info("Guessed %sbase = %s", guess, base) + return base + if required: + ErrorExit("Can't find URL in output from svn info") + return None + + def GenerateDiff(self, args): + cmd = ["svn", "diff"] + if self.options.revision: + cmd += ["-r", self.options.revision] + cmd.extend(args) + data = RunShell(cmd) + count = 0 + for line in data.splitlines(): + if line.startswith("Index:") or line.startswith("Property changes on:"): + count += 1 + logging.info(line) + if not count: + ErrorExit("No valid patches found in output from svn diff") + return data + + def _CollapseKeywords(self, content, keyword_str): + """Collapses SVN keywords.""" + # svn cat translates keywords but svn diff doesn't. As a result of this + # behavior patching.PatchChunks() fails with a chunk mismatch error. + # This part was originally written by the Review Board development team + # who had the same problem (http://reviews.review-board.org/r/276/). + # Mapping of keywords to known aliases + svn_keywords = { + # Standard keywords + 'Date': ['Date', 'LastChangedDate'], + 'Revision': ['Revision', 'LastChangedRevision', 'Rev'], + 'Author': ['Author', 'LastChangedBy'], + 'HeadURL': ['HeadURL', 'URL'], + 'Id': ['Id'], + + # Aliases + 'LastChangedDate': ['LastChangedDate', 'Date'], + 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'], + 'LastChangedBy': ['LastChangedBy', 'Author'], + 'URL': ['URL', 'HeadURL'], + } + + def repl(m): + if m.group(2): + return "$%s::%s$" % (m.group(1), " " * len(m.group(3))) + return "$%s$" % m.group(1) + keywords = [keyword + for name in keyword_str.split(" ") + for keyword in svn_keywords.get(name, [])] + return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content) + + def GetUnknownFiles(self): + status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True) + unknown_files = [] + for line in status.split("\n"): + if line and line[0] == "?": + unknown_files.append(line) + return unknown_files + + def ReadFile(self, filename): + """Returns the contents of a file.""" + file = open(filename, 'rb') + result = "" + try: + result = file.read() + finally: + file.close() + return result + + def GetStatus(self, filename): + """Returns the status of a file.""" + if not self.options.revision: + status = RunShell(["svn", "status", "--ignore-externals", filename]) + if not status: + ErrorExit("svn status returned no output for %s" % filename) + status_lines = status.splitlines() + # If file is in a cl, the output will begin with + # "\n--- Changelist 'cl_name':\n". See + # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt + if (len(status_lines) == 3 and + not status_lines[0] and + status_lines[1].startswith("--- Changelist")): + status = status_lines[2] + else: + status = status_lines[0] + # If we have a revision to diff against we need to run "svn list" + # for the old and the new revision and compare the results to get + # the correct status for a file. + else: + dirname, relfilename = os.path.split(filename) + if dirname not in self.svnls_cache: + cmd = ["svn", "list", "-r", self.rev_start, dirname or "."] + out, err, returncode = RunShellWithReturnCodeAndStderr(cmd) + if returncode: + # Directory might not yet exist at start revison + # svn: Unable to find repository location for 'abc' in revision nnn + if re.match('^svn: Unable to find repository location for .+ in revision \d+', err): + old_files = () + else: + ErrorExit("Failed to get status for %s:\n%s" % (filename, err)) + else: + old_files = out.splitlines() + args = ["svn", "list"] + if self.rev_end: + args += ["-r", self.rev_end] + cmd = args + [dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to run command %s" % cmd) + self.svnls_cache[dirname] = (old_files, out.splitlines()) + old_files, new_files = self.svnls_cache[dirname] + if relfilename in old_files and relfilename not in new_files: + status = "D " + elif relfilename in old_files and relfilename in new_files: + status = "M " + else: + status = "A " + return status + + def GetBaseFile(self, filename): + status = self.GetStatus(filename) + base_content = None + new_content = None + + # If a file is copied its status will be "A +", which signifies + # "addition-with-history". See "svn st" for more information. We need to + # upload the original file or else diff parsing will fail if the file was + # edited. + if status[0] == "A" and status[3] != "+": + # We'll need to upload the new content if we're adding a binary file + # since diff's output won't contain it. + mimetype = RunShell(["svn", "propget", "svn:mime-type", filename], + silent_ok=True) + base_content = "" + is_binary = bool(mimetype) and not mimetype.startswith("text/") + if is_binary and self.IsImage(filename): + new_content = self.ReadFile(filename) + elif (status[0] in ("M", "D", "R") or + (status[0] == "A" and status[3] == "+") or # Copied file. + (status[0] == " " and status[1] == "M")): # Property change. + args = [] + if self.options.revision: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + # Don't change filename, it's needed later. + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:mime-type", url] + mimetype, returncode = RunShellWithReturnCode(cmd) + if returncode: + # File does not exist in the requested revision. + # Reset mimetype, it contains an error message. + mimetype = "" + else: + mimetype = mimetype.strip() + get_base = False + is_binary = (bool(mimetype) and + not mimetype.startswith("text/") and + not mimetype in TEXT_MIMETYPES) + if status[0] == " ": + # Empty base content just to force an upload. + base_content = "" + elif is_binary: + if self.IsImage(filename): + get_base = True + if status[0] == "M": + if not self.rev_end: + new_content = self.ReadFile(filename) + else: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end) + new_content = RunShell(["svn", "cat", url], + universal_newlines=True, silent_ok=True) + else: + base_content = "" + else: + get_base = True + + if get_base: + if is_binary: + universal_newlines = False + else: + universal_newlines = True + if self.rev_start: + # "svn cat -r REV delete_file.txt" doesn't work. cat requires + # the full URL with "@REV" appended instead of using "-r" option. + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + base_content = RunShell(["svn", "cat", url], + universal_newlines=universal_newlines, + silent_ok=True) + else: + base_content, ret_code = RunShellWithReturnCode( + ["svn", "cat", filename], universal_newlines=universal_newlines) + if ret_code and status[0] == "R": + # It's a replaced file without local history (see issue208). + # The base file needs to be fetched from the server. + url = "%s/%s" % (self.svn_base, filename) + base_content = RunShell(["svn", "cat", url], + universal_newlines=universal_newlines, + silent_ok=True) + elif ret_code: + ErrorExit("Got error status from 'svn cat %s'" % filename) + if not is_binary: + args = [] + if self.rev_start: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:keywords", url] + keywords, returncode = RunShellWithReturnCode(cmd) + if keywords and not returncode: + base_content = self._CollapseKeywords(base_content, keywords) + else: + StatusUpdate("svn status returned unexpected output: %s" % status) + sys.exit(1) + return base_content, new_content, is_binary, status[0:5] + + +class GitVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Git.""" + + def __init__(self, options): + super(GitVCS, self).__init__(options) + # Map of filename -> (hash before, hash after) of base file. + # Hashes for "no such file" are represented as None. + self.hashes = {} + # Map of new filename -> old filename for renames. + self.renames = {} + + def PostProcessDiff(self, gitdiff): + """Converts the diff output to include an svn-style "Index:" line as well + as record the hashes of the files, so we can upload them along with our + diff.""" + # Special used by git to indicate "no such content". + NULL_HASH = "0"*40 + + def IsFileNew(filename): + return filename in self.hashes and self.hashes[filename][0] is None + + def AddSubversionPropertyChange(filename): + """Add svn's property change information into the patch if given file is + new file. + + We use Subversion's auto-props setting to retrieve its property. + See http://svnbook.red-bean.com/en/1.1/ch07.html#svn-ch-7-sect-1.3.2 for + Subversion's [auto-props] setting. + """ + if self.options.emulate_svn_auto_props and IsFileNew(filename): + svnprops = GetSubversionPropertyChanges(filename) + if svnprops: + svndiff.append("\n" + svnprops + "\n") + + svndiff = [] + filecount = 0 + filename = None + for line in gitdiff.splitlines(): + match = re.match(r"diff --git a/(.*) b/(.*)$", line) + if match: + # Add auto property here for previously seen file. + if filename is not None: + AddSubversionPropertyChange(filename) + filecount += 1 + # Intentionally use the "after" filename so we can show renames. + filename = match.group(2) + svndiff.append("Index: %s\n" % filename) + if match.group(1) != match.group(2): + self.renames[match.group(2)] = match.group(1) + else: + # The "index" line in a git diff looks like this (long hashes elided): + # index 82c0d44..b2cee3f 100755 + # We want to save the left hash, as that identifies the base file. + match = re.match(r"index (\w+)\.\.(\w+)", line) + if match: + before, after = (match.group(1), match.group(2)) + if before == NULL_HASH: + before = None + if after == NULL_HASH: + after = None + self.hashes[filename] = (before, after) + svndiff.append(line + "\n") + if not filecount: + ErrorExit("No valid patches found in output from git diff") + # Add auto property for the last seen file. + assert filename is not None + AddSubversionPropertyChange(filename) + return "".join(svndiff) + + def GenerateDiff(self, extra_args): + extra_args = extra_args[:] + if self.options.revision: + if ":" in self.options.revision: + extra_args = self.options.revision.split(":", 1) + extra_args + else: + extra_args = [self.options.revision] + extra_args + + # --no-ext-diff is broken in some versions of Git, so try to work around + # this by overriding the environment (but there is still a problem if the + # git config key "diff.external" is used). + env = os.environ.copy() + if 'GIT_EXTERNAL_DIFF' in env: del env['GIT_EXTERNAL_DIFF'] + return RunShell(["git", "diff", "--no-ext-diff", "--full-index", "-M"] + + extra_args, env=env) + + def GetUnknownFiles(self): + status = RunShell(["git", "ls-files", "--exclude-standard", "--others"], + silent_ok=True) + return status.splitlines() + + def GetFileContent(self, file_hash, is_binary): + """Returns the content of a file identified by its git hash.""" + data, retcode = RunShellWithReturnCode(["git", "show", file_hash], + universal_newlines=not is_binary) + if retcode: + ErrorExit("Got error status from 'git show %s'" % file_hash) + return data + + def GetBaseFile(self, filename): + hash_before, hash_after = self.hashes.get(filename, (None,None)) + base_content = None + new_content = None + is_binary = self.IsBinary(filename) + status = None + + if filename in self.renames: + status = "A +" # Match svn attribute name for renames. + if filename not in self.hashes: + # If a rename doesn't change the content, we never get a hash. + base_content = RunShell(["git", "show", "HEAD:" + filename]) + elif not hash_before: + status = "A" + base_content = "" + elif not hash_after: + status = "D" + else: + status = "M" + + is_image = self.IsImage(filename) + + # Grab the before/after content if we need it. + # We should include file contents if it's text or it's an image. + if not is_binary or is_image: + # Grab the base content if we don't have it already. + if base_content is None and hash_before: + base_content = self.GetFileContent(hash_before, is_binary) + # Only include the "after" file if it's an image; otherwise it + # it is reconstructed from the diff. + if is_image and hash_after: + new_content = self.GetFileContent(hash_after, is_binary) + + return (base_content, new_content, is_binary, status) + + +class MercurialVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Mercurial.""" + + def __init__(self, options, repo_dir): + super(MercurialVCS, self).__init__(options) + # Absolute path to repository (we can be in a subdir) + self.repo_dir = os.path.normpath(repo_dir) + # Compute the subdir + cwd = os.path.normpath(os.getcwd()) + assert cwd.startswith(self.repo_dir) + self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") + if self.options.revision: + self.base_rev = self.options.revision + else: + self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip() + + def _GetRelPath(self, filename): + """Get relative path of a file according to the current directory, + given its logical path in the repo.""" + assert filename.startswith(self.subdir), (filename, self.subdir) + return filename[len(self.subdir):].lstrip(r"\/") + + def GenerateDiff(self, extra_args): + cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args + data = RunShell(cmd, silent_ok=True) + svndiff = [] + filecount = 0 + for line in data.splitlines(): + m = re.match("diff --git a/(\S+) b/(\S+)", line) + if m: + # Modify line to make it look like as it comes from svn diff. + # With this modification no changes on the server side are required + # to make upload.py work with Mercurial repos. + # NOTE: for proper handling of moved/copied files, we have to use + # the second filename. + filename = m.group(2) + svndiff.append("Index: %s" % filename) + svndiff.append("=" * 67) + filecount += 1 + logging.info(line) + else: + svndiff.append(line) + if not filecount: + ErrorExit("No valid patches found in output from hg diff") + return "\n".join(svndiff) + "\n" + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + args = [] + status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], + silent_ok=True) + unknown_files = [] + for line in status.splitlines(): + st, fn = line.split(" ", 1) + if st == "?": + unknown_files.append(fn) + return unknown_files + + def GetBaseFile(self, filename): + # "hg status" and "hg cat" both take a path relative to the current subdir + # rather than to the repo root, but "hg diff" has given us the full path + # to the repo root. + base_content = "" + new_content = None + is_binary = False + oldrelpath = relpath = self._GetRelPath(filename) + # "hg status -C" returns two lines for moved/copied files, one otherwise + out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) + out = out.splitlines() + # HACK: strip error message about missing file/directory if it isn't in + # the working copy + if out[0].startswith('%s: ' % relpath): + out = out[1:] + status, _ = out[0].split(' ', 1) + if len(out) > 1 and status == "A": + # Moved/copied => considered as modified, use old filename to + # retrieve base contents + oldrelpath = out[1].strip() + status = "M" + if ":" in self.base_rev: + base_rev = self.base_rev.split(":", 1)[0] + else: + base_rev = self.base_rev + if status != "A": + base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], + silent_ok=True) + is_binary = "\0" in base_content # Mercurial's heuristic + if status != "R": + new_content = open(relpath, "rb").read() + is_binary = is_binary or "\0" in new_content + if is_binary and base_content: + # Fetch again without converting newlines + base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], + silent_ok=True, universal_newlines=False) + if not is_binary or not self.IsImage(relpath): + new_content = None + return base_content, new_content, is_binary, status + + +# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync. +def SplitPatch(data): + """Splits a patch into separate pieces for each file. + + Args: + data: A string containing the output of svn diff. + + Returns: + A list of 2-tuple (filename, text) where text is the svn diff output + pertaining to filename. + """ + patches = [] + filename = None + diff = [] + for line in data.splitlines(True): + new_filename = None + if line.startswith('Index:'): + unused, new_filename = line.split(':', 1) + new_filename = new_filename.strip() + elif line.startswith('Property changes on:'): + unused, temp_filename = line.split(':', 1) + # When a file is modified, paths use '/' between directories, however + # when a property is modified '\' is used on Windows. Make them the same + # otherwise the file shows up twice. + temp_filename = temp_filename.strip().replace('\\', '/') + if temp_filename != filename: + # File has property changes but no modifications, create a new diff. + new_filename = temp_filename + if new_filename: + if filename and diff: + patches.append((filename, ''.join(diff))) + filename = new_filename + diff = [line] + continue + if diff is not None: + diff.append(line) + if filename and diff: + patches.append((filename, ''.join(diff))) + return patches + + +def UploadSeparatePatches(issue, rpc_server, patchset, data, options): + """Uploads a separate patch for each file in the diff output. + + Returns a list of [patch_key, filename] for each file. + """ + patches = SplitPatch(data) + rv = [] + for patch in patches: + if len(patch[1]) > MAX_UPLOAD_SIZE: + print("Not uploading the patch for " + patch[0] + + " because the file is too large.") + continue + form_fields = [("filename", patch[0])] + if not options.download_base: + form_fields.append(("content_upload", "1")) + files = [("data", "data.diff", patch[1])] + ctype, body = EncodeMultipartFormData(form_fields, files) + url = "/%d/upload_patch/%d" % (int(issue), int(patchset)) + print("Uploading patch for " + patch[0]) + response_body = rpc_server.Send(url, body, content_type=ctype) + lines = response_body.splitlines() + if not lines or lines[0] != "OK": + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + rv.append([lines[1], patch[0]]) + return rv + + +def GuessVCSName(): + """Helper to guess the version control system. + + This examines the current directory, guesses which VersionControlSystem + we're using, and returns an string indicating which VCS is detected. + + Returns: + A pair (vcs, output). vcs is a string indicating which VCS was detected + and is one of VCS_GIT, VCS_MERCURIAL, VCS_SUBVERSION, or VCS_UNKNOWN. + output is a string containing any interesting output from the vcs + detection routine, or None if there is nothing interesting. + """ + def RunDetectCommand(vcs_type, command): + """Helper to detect VCS by executing command. + + Returns: + A pair (vcs, output) or None. Throws exception on error. + """ + try: + out, returncode = RunShellWithReturnCode(command) + if returncode == 0: + return (vcs_type, out.strip()) + except OSError as xxx_todo_changeme: + (errcode, message) = xxx_todo_changeme.args + if errcode != errno.ENOENT: # command not found code + raise + + # Mercurial has a command to get the base directory of a repository + # Try running it, but don't die if we don't have hg installed. + # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. + res = RunDetectCommand(VCS_MERCURIAL, ["hg", "root"]) + if res != None: + return res + + # Subversion has a .svn in all working directories. + if os.path.isdir('.svn'): + logging.info("Guessed VCS = Subversion") + return (VCS_SUBVERSION, None) + + # Git has a command to test if you're in a git tree. + # Try running it, but don't die if we don't have git installed. + res = RunDetectCommand(VCS_GIT, ["git", "rev-parse", + "--is-inside-work-tree"]) + if res != None: + return res + + return (VCS_UNKNOWN, None) + + +def GuessVCS(options): + """Helper to guess the version control system. + + This verifies any user-specified VersionControlSystem (by command line + or environment variable). If the user didn't specify one, this examines + the current directory, guesses which VersionControlSystem we're using, + and returns an instance of the appropriate class. Exit with an error + if we can't figure it out. + + Returns: + A VersionControlSystem instance. Exits if the VCS can't be guessed. + """ + vcs = options.vcs + if not vcs: + vcs = os.environ.get("CODEREVIEW_VCS") + if vcs: + v = VCS_ABBREVIATIONS.get(vcs.lower()) + if v is None: + ErrorExit("Unknown version control system %r specified." % vcs) + (vcs, extra_output) = (v, None) + else: + (vcs, extra_output) = GuessVCSName() + + if vcs == VCS_MERCURIAL: + if extra_output is None: + extra_output = RunShell(["hg", "root"]).strip() + return MercurialVCS(options, extra_output) + elif vcs == VCS_SUBVERSION: + return SubversionVCS(options) + elif vcs == VCS_GIT: + return GitVCS(options) + + ErrorExit(("Could not guess version control system. " + "Are you in a working copy directory?")) + + +def CheckReviewer(reviewer): + """Validate a reviewer -- either a nickname or an email addres. + + Args: + reviewer: A nickname or an email address. + + Calls ErrorExit() if it is an invalid email address. + """ + if "@" not in reviewer: + return # Assume nickname + parts = reviewer.split("@") + if len(parts) > 2: + ErrorExit("Invalid email address: %r" % reviewer) + assert len(parts) == 2 + if "." not in parts[1]: + ErrorExit("Invalid email address: %r" % reviewer) + + +def LoadSubversionAutoProperties(): + """Returns the content of [auto-props] section of Subversion's config file as + a dictionary. + + Returns: + A dictionary whose key-value pair corresponds the [auto-props] section's + key-value pair. + In following cases, returns empty dictionary: + - config file doesn't exist, or + - 'enable-auto-props' is not set to 'true-like-value' in [miscellany]. + """ + if os.name == 'nt': + subversion_config = os.environ.get("APPDATA") + "\\Subversion\\config" + else: + subversion_config = os.path.expanduser("~/.subversion/config") + if not os.path.exists(subversion_config): + return {} + config = ConfigParser() + config.read(subversion_config) + if (config.has_section("miscellany") and + config.has_option("miscellany", "enable-auto-props") and + config.getboolean("miscellany", "enable-auto-props") and + config.has_section("auto-props")): + props = {} + for file_pattern in config.options("auto-props"): + props[file_pattern] = ParseSubversionPropertyValues( + config.get("auto-props", file_pattern)) + return props + else: + return {} + +def ParseSubversionPropertyValues(props): + """Parse the given property value which comes from [auto-props] section and + returns a list whose element is a (svn_prop_key, svn_prop_value) pair. + + See the following doctest for example. + + >>> ParseSubversionPropertyValues('svn:eol-style=LF') + [('svn:eol-style', 'LF')] + >>> ParseSubversionPropertyValues('svn:mime-type=image/jpeg') + [('svn:mime-type', 'image/jpeg')] + >>> ParseSubversionPropertyValues('svn:eol-style=LF;svn:executable') + [('svn:eol-style', 'LF'), ('svn:executable', '*')] + """ + key_value_pairs = [] + for prop in props.split(";"): + key_value = prop.split("=") + assert len(key_value) <= 2 + if len(key_value) == 1: + # If value is not given, use '*' as a Subversion's convention. + key_value_pairs.append((key_value[0], "*")) + else: + key_value_pairs.append((key_value[0], key_value[1])) + return key_value_pairs + + +def GetSubversionPropertyChanges(filename): + """Return a Subversion's 'Property changes on ...' string, which is used in + the patch file. + + Args: + filename: filename whose property might be set by [auto-props] config. + + Returns: + A string like 'Property changes on |filename| ...' if given |filename| + matches any entries in [auto-props] section. None, otherwise. + """ + global svn_auto_props_map + if svn_auto_props_map is None: + svn_auto_props_map = LoadSubversionAutoProperties() + + all_props = [] + for file_pattern, props in svn_auto_props_map.items(): + if fnmatch.fnmatch(filename, file_pattern): + all_props.extend(props) + if all_props: + return FormatSubversionPropertyChanges(filename, all_props) + return None + + +def FormatSubversionPropertyChanges(filename, props): + """Returns Subversion's 'Property changes on ...' strings using given filename + and properties. + + Args: + filename: filename + props: A list whose element is a (svn_prop_key, svn_prop_value) pair. + + Returns: + A string which can be used in the patch file for Subversion. + + See the following doctest for example. + + >>> print(FormatSubversionPropertyChanges('foo.cc', [('svn:eol-style', 'LF')])) + Property changes on: foo.cc + ___________________________________________________________________ + Added: svn:eol-style + + LF + <BLANKLINE> + """ + prop_changes_lines = [ + "Property changes on: %s" % filename, + "___________________________________________________________________"] + for key, value in props: + prop_changes_lines.append("Added: " + key) + prop_changes_lines.append(" + " + value) + return "\n".join(prop_changes_lines) + "\n" + + +def RealMain(argv, data=None): + """The real main function. + + Args: + argv: Command line arguments. + data: Diff contents. If None (default) the diff is generated by + the VersionControlSystem implementation returned by GuessVCS(). + + Returns: + A 2-tuple (issue id, patchset id). + The patchset id is None if the base files are not uploaded by this + script (applies only to SVN checkouts). + """ + options, args = parser.parse_args(argv[1:]) + global verbosity + verbosity = options.verbose + if verbosity >= 3: + logging.getLogger().setLevel(logging.DEBUG) + elif verbosity >= 2: + logging.getLogger().setLevel(logging.INFO) + + vcs = GuessVCS(options) + + base = options.base_url + if isinstance(vcs, SubversionVCS): + # Guessing the base field is only supported for Subversion. + # Note: Fetching base files may become deprecated in future releases. + guessed_base = vcs.GuessBase(options.download_base) + if base: + if guessed_base and base != guessed_base: + print("Using base URL \"%s\" from --base_url instead of \"%s\"" % \ + (base, guessed_base)) + else: + base = guessed_base + + if not base and options.download_base: + options.download_base = True + logging.info("Enabled upload of base file") + if not options.assume_yes: + vcs.CheckForUnknownFiles() + if data is None: + data = vcs.GenerateDiff(args) + data = vcs.PostProcessDiff(data) + files = vcs.GetBaseFiles(data) + if verbosity >= 1: + print("Upload server:", options.server, "(change with -s/--server)") + if options.issue: + prompt = "Message describing this patch set: " + else: + prompt = "New issue subject: " + message = options.message or input(prompt).strip() + if not message: + ErrorExit("A non-empty message is required") + rpc_server = GetRpcServer(options.server, + options.email, + options.host, + options.save_cookies, + options.account_type) + form_fields = [("subject", message)] + if base: + b = urlparse(base) + username, netloc = urlsplituser(b.netloc) + if username: + logging.info("Removed username from base URL") + base = urlunparse((b.scheme, netloc, b.path, b.params, + b.query, b.fragment)) + form_fields.append(("base", base)) + if options.issue: + form_fields.append(("issue", str(options.issue))) + if options.email: + form_fields.append(("user", options.email)) + if options.reviewers: + for reviewer in options.reviewers.split(','): + CheckReviewer(reviewer) + form_fields.append(("reviewers", options.reviewers)) + if options.cc: + for cc in options.cc.split(','): + CheckReviewer(cc) + form_fields.append(("cc", options.cc)) + description = options.description + if options.description_file: + if options.description: + ErrorExit("Can't specify description and description_file") + file = open(options.description_file, 'r') + description = file.read() + file.close() + if description: + form_fields.append(("description", description)) + # Send a hash of all the base file so the server can determine if a copy + # already exists in an earlier patchset. + base_hashes = "" + for file, info in files.items(): + if not info[0] is None: + checksum = md5(info[0]).hexdigest() + if base_hashes: + base_hashes += "|" + base_hashes += checksum + ":" + file + form_fields.append(("base_hashes", base_hashes)) + if options.private: + if options.issue: + print("Warning: Private flag ignored when updating an existing issue.") + else: + form_fields.append(("private", "1")) + # If we're uploading base files, don't send the email before the uploads, so + # that it contains the file status. + if options.send_mail and options.download_base: + form_fields.append(("send_mail", "1")) + if not options.download_base: + form_fields.append(("content_upload", "1")) + if len(data) > MAX_UPLOAD_SIZE: + print("Patch is large, so uploading file patches separately.") + uploaded_diff_file = [] + form_fields.append(("separate_patches", "1")) + else: + uploaded_diff_file = [("data", "data.diff", data)] + ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) + response_body = rpc_server.Send("/upload", body, content_type=ctype) + patchset = None + if not options.download_base or not uploaded_diff_file: + lines = response_body.splitlines() + if len(lines) >= 2: + msg = lines[0] + patchset = lines[1].strip() + patches = [x.split(" ", 1) for x in lines[2:]] + else: + msg = response_body + else: + msg = response_body + StatusUpdate(msg) + if not response_body.startswith("Issue created.") and \ + not response_body.startswith("Issue updated."): + sys.exit(0) + issue = msg[msg.rfind("/")+1:] + + if not uploaded_diff_file: + result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) + if not options.download_base: + patches = result + + if not options.download_base: + vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) + if options.send_mail: + rpc_server.Send("/" + issue + "/mail", payload="") + return issue, patchset + + +def main(): + try: + logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" + "%(lineno)s %(message)s ")) + os.environ['LC_ALL'] = 'C' + RealMain(sys.argv) + except KeyboardInterrupt: + print() + StatusUpdate("Interrupted.") + sys.exit(1) + + +if __name__ == "__main__": + main() + @@ -79,6 +79,9 @@ # library directory. If we ever resurrect that as the default, then # you can find the appropriate code in the 0.04 version of this script, # rather than reinventing that wheel.) +from __future__ import print_function + +from six import PY3 import getopt import glob @@ -90,10 +93,13 @@ import time try: import threading - import Queue # 2to3: rename to queue + if PY3: + from queue import Queue + else: + from Queue import Queue threading_ok = True except ImportError: - print "Can't import threading or queue" + print("Can't import threading or queue") threading_ok = False cwd = os.getcwd() @@ -187,12 +193,12 @@ class PassThroughOptionParser(OptionParser): def _process_long_opt(self, rargs, values): try: OptionParser._process_long_opt(self, rargs, values) - except BadOptionError, err: + except BadOptionError as err: self.largs.append(err.opt_str) def _process_short_opts(self, rargs, values): try: OptionParser._process_short_opts(self, rargs, values) - except BadOptionError, err: + except BadOptionError as err: self.largs.append(err.opt_str) parser = PassThroughOptionParser(add_help_option=False) @@ -244,7 +250,7 @@ for o, a in opts: a = os.path.join(cwd, a) testlistfile = a elif o in ['-h', '--help']: - print helpstr + print(helpstr) sys.exit(0) elif o in ['-j', '--jobs']: jobs = int(a) @@ -334,7 +340,7 @@ else: st = os.stat(f) except OSError: continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return f return None @@ -572,7 +578,7 @@ else: base = os.path.join(base, os.path.split(url)[1]) if printcommand: - print command + print(command) if execute_tests: os.system(command) else: @@ -806,15 +812,15 @@ def run_test(t, io_lock, async=True): if suppress_stdout or suppress_stderr: sys.stdout.write(header) if not suppress_stdout and t.stdout: - print t.stdout + print(t.stdout) if not suppress_stderr and t.stderr: - print t.stderr + print(t.stderr) print_time_func("Test execution time: %.1f seconds\n", t.test_time) if io_lock: io_lock.release() if quit_on_failure and t.status == 1: - print "Exiting due to error" - print t.status + print("Exiting due to error") + print(t.status) sys.exit(1) class RunTest(threading.Thread): @@ -830,9 +836,9 @@ class RunTest(threading.Thread): self.queue.task_done() if jobs > 1 and threading_ok: - print "Running tests using %d jobs"%jobs + print("Running tests using %d jobs"%jobs) # Start worker threads - queue = Queue.Queue() + queue = Queue() io_lock = threading.Lock() for i in range(1, jobs): t = RunTest(queue, io_lock) @@ -845,7 +851,7 @@ if jobs > 1 and threading_ok: else: # Run tests serially if jobs > 1: - print "Ignoring -j%d option; no python threading module available."%jobs + print("Ignoring -j%d option; no python threading module available."%jobs) for t in tests: run_test(t, None, False) diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 33d87906..d7d9afd1 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -166,12 +166,12 @@ def _callable_contents(obj): """ try: # Test if obj is a method. - return _function_contents(obj.im_func) + return _function_contents(obj.__func__) except AttributeError: try: # Test if obj is a callable object. - return _function_contents(obj.__call__.im_func) + return _function_contents(obj.__call__.__func__) except AttributeError: try: @@ -191,12 +191,12 @@ def _object_contents(obj): """ try: # Test if obj is a method. - return _function_contents(obj.im_func) + return _function_contents(obj.__func__) except AttributeError: try: # Test if obj is a callable object. - return _function_contents(obj.__call__.im_func) + return _function_contents(obj.__call__.__func__) except AttributeError: try: @@ -237,9 +237,9 @@ def _code_contents(code): # The code contents depends on the number of local variables # but not their actual names. - contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames))) + contents.append(str.encode("%s,%s" % (code.co_argcount, len(code.co_varnames)))) try: - contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars))) + contents.append(str.encode(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))) except AttributeError: # Older versions of Python do not support closures. contents.append(",0,0") @@ -252,35 +252,35 @@ def _code_contents(code): # Note that we also always ignore the first entry of co_consts # which contains the function doc string. We assume that the # function does not access its doc string. - contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')') + contents.append(b',(' + b','.join(map(_object_contents,code.co_consts[1:])) + b')') # The code contents depends on the variable names used to # accessed global variable, as changing the variable name changes # the variable actually accessed and therefore changes the # function result. - contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')') + contents.append(b',(' + b','.join(map(_object_contents,code.co_names)) + b')') # The code contents depends on its actual code!!! - contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')') + contents.append(b',(' + remove_set_lineno_codes(code.co_code) + b')') - return ''.join(contents) + return b''.join(contents) def _function_contents(func): """Return the signature contents of a function.""" - contents = [_code_contents(func.func_code)] + contents = [_code_contents(func.__code__)] # The function contents depends on the value of defaults arguments - if func.func_defaults: - contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')') + if func.__defaults__: + contents.append(b',(' + b','.join(map(_object_contents,func.__defaults__)) + b')') else: - contents.append(',()') + contents.append(b',()') # The function contents depends on the closure captured cell values. try: - closure = func.func_closure or [] + closure = func.__closure__ or [] except AttributeError: # Older versions of Python do not support closures. closure = [] @@ -290,9 +290,9 @@ def _function_contents(func): xxx = [_object_contents(x.cell_contents) for x in closure] except AttributeError: xxx = [] - contents.append(',(' + ','.join(xxx) + ')') + contents.append(b',(' + b','.join(xxx) + b')') - return ''.join(contents) + return b''.join(contents) def _actionAppend(act1, act2): @@ -421,8 +421,8 @@ class ActionBase(object): other objects (Builders, Executors, etc.) This provides the common methods for manipulating and combining those actions.""" - def __cmp__(self, other): - return cmp(self.__dict__, other) + def __eq__(self, other): + return self.__dict__ == other def no_batch_key(self, env, target, source): return None @@ -434,6 +434,7 @@ class ActionBase(object): def get_contents(self, target, source, env): result = [ self.get_presig(target, source, env) ] + result = [ SCons.Util.to_bytes(r) for r in result ] # This should never happen, as the Action() factory should wrap # the varlist, but just in case an action is created directly, # we duplicate this check here. @@ -441,8 +442,8 @@ class ActionBase(object): if is_String(vl): vl = (vl,) for v in vl: # do the subst this way to ignore $(...$) parts: - result.append(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source)) - return ''.join(result) + result.append(SCons.Util.to_bytes(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source))) + return b''.join(result) def __add__(self, other): return _actionAppend(self, other) @@ -514,7 +515,7 @@ class _ActionAction(ActionBase): # This code assumes s is a regular string, but should # work if it's unicode too. try: - sys.stdout.write(unicode(s + "\n")) + sys.stdout.write(s + u"\n") except UnicodeDecodeError: sys.stdout.write(s + "\n") @@ -674,7 +675,7 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw): try: return subprocess.Popen(cmd, **kw) - except EnvironmentError, e: + except EnvironmentError as e: if error == 'raise': raise # return a dummy Popen instance that only returns error class dummyPopen(object): @@ -1062,11 +1063,11 @@ class FunctionAction(_ActionAction): rsources = list(map(rfile, source)) try: result = self.execfunction(target=target, source=rsources, env=env) - except KeyboardInterrupt, e: + except KeyboardInterrupt as e: raise - except SystemExit, e: + except SystemExit as e: raise - except Exception, e: + except Exception as e: result = e exc_info = sys.exc_info() @@ -1136,7 +1137,7 @@ class ListAction(ActionBase): Simple concatenation of the signatures of the elements. """ - return "".join([x.get_contents(target, source, env) for x in self.list]) + return b"".join([x.get_contents(target, source, env) for x in self.list]) def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, show=_null, execute=_null, chdir=_null, executor=None): @@ -1181,11 +1182,11 @@ class ActionCaller(object): actfunc = self.parent.actfunc try: # "self.actfunc" is a function. - contents = str(actfunc.func_code.co_code) + contents = str(actfunc.__code__.co_code) except AttributeError: # "self.actfunc" is a callable object. try: - contents = str(actfunc.__call__.im_func.func_code.co_code) + contents = str(actfunc.__call__.__func__.__code__.co_code) except AttributeError: # No __call__() method, so it might be a builtin # or something like that. Do the best we can. diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 809e5ceb..7815413b 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -63,7 +63,7 @@ test = TestCmd.TestCmd(workdir = '') test.write('act.py', """\ import os, string, sys f = open(sys.argv[1], 'w') -f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n") +f.write("act.py: '" + "' '".join(sys.argv[2:]) + "'\\n") try: if sys.argv[3]: f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n") @@ -270,7 +270,7 @@ def test_positional_args(pos_callback, cmd, **kw): try: #FUTURE a = SCons.Action.Action(cmd, [], **kw) a = SCons.Action.Action(cmd, [], **kw) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: s = str(e) m = 'Invalid command display variable' assert s.find(m) != -1, 'Unexpected string: %s' % s @@ -493,7 +493,7 @@ class _ActionActionTestCase(unittest.TestCase): def func(): pass try: a = SCons.Action.Action('foo', cmdstr='string', strfunction=func) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: s = str(e) m = 'Cannot have both strfunction and cmdstr args to Action()' assert s.find(m) != -1, 'Unexpected string: %s' % s @@ -1326,7 +1326,7 @@ class CommandActionTestCase(unittest.TestCase): c = a.get_contents(target=[], source=[], env=Environment(foo = 'FFF', bar = 'BBB', baz = CmdGen)) - assert c == "| | FFF BBB 1", c + assert c == b"| | FFF BBB 1", c # Make sure that CommandActions use an Environment's # subst_target_source() method for substitution. @@ -1337,7 +1337,7 @@ class CommandActionTestCase(unittest.TestCase): c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'), env=SpecialEnvironment(foo = 'GGG', bar = 'CCC', baz = 'ZZZ')) - assert c == 'subst_target_source: | $( $foo | $bar $) | $baz 1', c + assert c == b'subst_target_source: | $( $foo | $bar $) | $baz 1', c # We've discussed using the real target and source names in a # CommandAction's signature contents. This would have have the @@ -1354,35 +1354,35 @@ class CommandActionTestCase(unittest.TestCase): a = SCons.Action.CommandAction(["$TARGET"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "t1", c + assert c == b"t1", c a = SCons.Action.CommandAction(["$TARGETS"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "t1 t2 t3 t4 t5 t6", c + assert c == b"t1 t2 t3 t4 t5 t6", c a = SCons.Action.CommandAction(["${TARGETS[2]}"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "t3", c + assert c == b"t3", c a = SCons.Action.CommandAction(["${TARGETS[3:5]}"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "t4 t5", c + assert c == b"t4 t5", c a = SCons.Action.CommandAction(["$SOURCE"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "s1", c + assert c == b"s1", c a = SCons.Action.CommandAction(["$SOURCES"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "s1 s2 s3 s4 s5 s6", c + assert c == b"s1 s2 s3 s4 s5 s6", c a = SCons.Action.CommandAction(["${SOURCES[2]}"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "s3", c + assert c == b"s3", c a = SCons.Action.CommandAction(["${SOURCES[3:5]}"]) c = a.get_contents(target=t, source=s, env=env) - assert c == "s4 s5", c + assert c == b"s4 s5", c class CommandGeneratorActionTestCase(unittest.TestCase): @@ -1499,7 +1499,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase): ignore = 'foo', test=test) a = self.factory(f) c = a.get_contents(target=[], source=[], env=env) - assert c == "guux FFF BBB test", c + assert c == b"guux FFF BBB test", c def test_get_contents_of_function_action(self): """Test contents of a CommandGeneratorAction-generated FunctionAction @@ -1509,13 +1509,13 @@ class CommandGeneratorActionTestCase(unittest.TestCase): pass func_matches = [ - "0,0,0,0,(),(),(d\000\000S),(),()", - "0,0,0,0,(),(),(d\x00\x00S),(),()", + b"0,0,0,0,(),(),(d\000\000S),(),()", + b"0,0,0,0,(),(),(d\x00\x00S),(),()", ] meth_matches = [ - "1,1,0,0,(),(),(d\000\000S),(),()", - "1,1,0,0,(),(),(d\x00\x00S),(),()", + b"1,1,0,0,(),(),(d\000\000S),(),()", + b"1,1,0,0,(),(),(d\x00\x00S),(),()", ] def f_global(target, source, env, for_signature): @@ -1540,7 +1540,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase): def f_local(target, source, env, for_signature): return SCons.Action.Action(LocalFunc, varlist=['XYZ']) - matches_foo = [x + "foo" for x in func_matches] + matches_foo = [x + b"foo" for x in func_matches] a = self.factory(f_global) c = a.get_contents(target=[], source=[], env=env) @@ -1668,13 +1668,13 @@ class FunctionActionTestCase(unittest.TestCase): pass func_matches = [ - "0,0,0,0,(),(),(d\000\000S),(),()", - "0,0,0,0,(),(),(d\x00\x00S),(),()", + b"0,0,0,0,(),(),(d\000\000S),(),()", + b"0,0,0,0,(),(),(d\x00\x00S),(),()", ] meth_matches = [ - "1,1,0,0,(),(),(d\000\000S),(),()", - "1,1,0,0,(),(),(d\x00\x00S),(),()", + b"1,1,0,0,(),(),(d\000\000S),(),()", + b"1,1,0,0,(),(),(d\x00\x00S),(),()", ] def factory(act, **kw): @@ -1688,7 +1688,7 @@ class FunctionActionTestCase(unittest.TestCase): c = a.get_contents(target=[], source=[], env=Environment()) assert c in func_matches, repr(c) - matches_foo = [x + "foo" for x in func_matches] + matches_foo = [x + b"foo" for x in func_matches] a = factory(GlobalFunc, varlist=['XYZ']) c = a.get_contents(target=[], source=[], env=Environment()) @@ -1706,10 +1706,10 @@ class FunctionActionTestCase(unittest.TestCase): class Foo(object): def get_contents(self, target, source, env): - return 'xyzzy' + return b'xyzzy' a = factory(Foo()) c = a.get_contents(target=[], source=[], env=Environment()) - assert c == 'xyzzy', repr(c) + assert c == b'xyzzy', repr(c) class LocalClass(object): def LocalMethod(self): @@ -1820,7 +1820,7 @@ class ListActionTestCase(unittest.TestCase): "z"]) c = a.get_contents(target=[], source=[], env=Environment(s = self)) assert self.foo==1, self.foo - assert c == "xyz", c + assert c == b"xyz", c class LazyActionTestCase(unittest.TestCase): def test___init__(self): @@ -1871,7 +1871,7 @@ class LazyActionTestCase(unittest.TestCase): a = SCons.Action.Action("${FOO}") env = Environment(FOO = [["This", "is", "a", "test"]]) c = a.get_contents(target=[], source=[], env=env) - assert c == "This is a test", c + assert c == b"This is a test", c def test_get_contents_of_function_action(self): """Test fetching the contents of a lazy-evaluation FunctionAction @@ -1881,13 +1881,13 @@ class LazyActionTestCase(unittest.TestCase): pass func_matches = [ - "0,0,0,0,(),(),(d\000\000S),(),()", - "0,0,0,0,(),(),(d\x00\x00S),(),()", + b"0,0,0,0,(),(),(d\000\000S),(),()", + b"0,0,0,0,(),(),(d\x00\x00S),(),()", ] meth_matches = [ - "1,1,0,0,(),(),(d\000\000S),(),()", - "1,1,0,0,(),(),(d\x00\x00S),(),()", + b"1,1,0,0,(),(),(d\000\000S),(),()", + b"1,1,0,0,(),(),(d\x00\x00S),(),()", ] def factory(act, **kw): @@ -1904,7 +1904,7 @@ class LazyActionTestCase(unittest.TestCase): c = a.get_contents(target=[], source=[], env=env) assert c in func_matches, repr(c) - matches_foo = [x + "foo" for x in func_matches] + matches_foo = [x + b"foo" for x in func_matches] env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ'])) c = a.get_contents(target=[], source=[], env=env) @@ -1931,8 +1931,8 @@ class ActionCallerTestCase(unittest.TestCase): pass matches = [ - "d\000\000S", - "d\x00\x00S" + b"d\000\000S", + b"d\x00\x00S" ] af = SCons.Action.ActionFactory(GlobalFunc, strfunc) @@ -1946,8 +1946,8 @@ class ActionCallerTestCase(unittest.TestCase): assert c in matches, repr(c) matches = [ - 'd\000\000S', - "d\x00\x00S" + b'd\000\000S', + b"d\x00\x00S" ] class LocalActFunc(object): @@ -1965,8 +1965,8 @@ class ActionCallerTestCase(unittest.TestCase): assert c in matches, repr(c) matches = [ - "<built-in function str>", - "<type 'str'>", + b"<built-in function str>", + b"<type 'str'>", ] af = SCons.Action.ActionFactory(str, strfunc) diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index ed7650a8..db249bf1 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -168,7 +168,7 @@ class DictCmdGenerator(SCons.Util.Selector): try: ret = SCons.Util.Selector.__call__(self, env, source, ext) - except KeyError, e: + except KeyError as e: raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2])) if ret is None: raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \ @@ -346,8 +346,11 @@ class EmitterProxy(object): return (target, source) - def __cmp__(self, other): - return cmp(self.var, other.var) + def __eq__(self, other): + return self.var == other.var + + def __lt__(self, other): + return self.var < other.var class BuilderBase(object): """Base class for Builders, objects that create output @@ -430,6 +433,9 @@ class BuilderBase(object): def __nonzero__(self): raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead") + def __bool__(self): + return self.__nonzero__() + def get_name(self, env): """Attempts to get the name of the Builder. @@ -447,8 +453,8 @@ class BuilderBase(object): except AttributeError: return str(self.__class__) - def __cmp__(self, other): - return cmp(self.__dict__, other.__dict__) + def __eq__(self, other): + return self.__dict__ == other.__dict__ def splitext(self, path, env=None): if not env: diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 70a7a3fe..212872f9 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -145,8 +146,8 @@ class Environment(object): d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__'] d['SOURCE'] = d['SOURCES'][0] return d - def __cmp__(self, other): - return cmp(self.scanner, other.scanner) or cmp(self.d, other.d) + def __eq__(self, other): + return self.scanner == other.scanner or self.d == other.d class MyAction(object): def __init__(self, action): @@ -326,7 +327,7 @@ class BuilderTestCase(unittest.TestCase): flag = 0 try: target = builder(env, None, source=n20) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 assert flag, "UserError should be thrown if a source node can't create a target." @@ -342,7 +343,7 @@ class BuilderTestCase(unittest.TestCase): suffix = '.s') try: builder(env, target = 'n22', source = 'n22') - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: pass else: raise Exception("Did not catch expected UserError.") @@ -1498,11 +1499,12 @@ class CompositeBuilderTestCase(unittest.TestCase): flag = 0 try: builder(env, target='test3', source=['test2.bar', 'test1.foo'])[0] - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 + err = e assert flag, "UserError should be thrown when we call a builder with files of different suffixes." expect = "While building `['test3']' from `test1.foo': Cannot build multiple sources with different extensions: .bar, .foo" - assert str(e) == expect, e + assert str(err) == expect, err def test_source_ext_match(self): """Test the CompositeBuilder source_ext_match argument""" @@ -1529,8 +1531,8 @@ class CompositeBuilderTestCase(unittest.TestCase): try: tgt.build() flag = 1 - except SCons.Errors.UserError, e: - print e + except SCons.Errors.UserError as e: + print(e) flag = 0 assert flag, "It should be possible to define actions in composite builders using variables." env['FOO_SUFFIX'] = '.BAR2' @@ -1582,47 +1584,52 @@ class CompositeBuilderTestCase(unittest.TestCase): flag = 0 try: builder(env, target='t5', source=['test5a.foo', 'test5b.inb'])[0] - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 + err = e assert flag, "UserError should be thrown when we call a builder with files of different suffixes." expect = "While building `['t5']' from `test5b.bar': Cannot build multiple sources with different extensions: .foo, .bar" - assert str(e) == expect, e + assert str(err) == expect, err flag = 0 try: builder(env, target='t6', source=['test6a.bar', 'test6b.ina'])[0] - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 + err = e assert flag, "UserError should be thrown when we call a builder with files of different suffixes." expect = "While building `['t6']' from `test6b.foo': Cannot build multiple sources with different extensions: .bar, .foo" - assert str(e) == expect, e + assert str(err) == expect, err flag = 0 try: builder(env, target='t4', source=['test4a.ina', 'test4b.inb'])[0] - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 + err = e assert flag, "UserError should be thrown when we call a builder with files of different suffixes." expect = "While building `['t4']' from `test4b.bar': Cannot build multiple sources with different extensions: .foo, .bar" - assert str(e) == expect, e + assert str(err) == expect, err flag = 0 try: builder(env, target='t7', source=[env.fs.File('test7')])[0] - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 + err = e assert flag, "UserError should be thrown when we call a builder with files of different suffixes." expect = "While building `['t7']': Cannot deduce file extension from source files: ['test7']" - assert str(e) == expect, e + assert str(err) == expect, err flag = 0 try: builder(env, target='t8', source=['test8.unknown'])[0] - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: flag = 1 + err = e assert flag, "UserError should be thrown when we call a builder target with an unknown suffix." expect = "While building `['t8']' from `['test8.unknown']': Don't know how to build from a source file with suffix `.unknown'. Expected a suffix in this list: ['.foo', '.bar']." - assert str(e) == expect, e + assert str(err) == expect, err if __name__ == "__main__": suite = unittest.TestSuite() diff --git a/src/engine/SCons/CacheDirTests.py b/src/engine/SCons/CacheDirTests.py index 7ac97efa..878a87a8 100644 --- a/src/engine/SCons/CacheDirTests.py +++ b/src/engine/SCons/CacheDirTests.py @@ -242,7 +242,7 @@ class FileTestCase(BaseTestCase): warn_caught = 0 try: f7.push_to_cache() - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: assert e.exc_info[0] == SCons.Warnings.CacheWriteErrorWarning warn_caught = 1 assert warn_caught diff --git a/src/engine/SCons/Conftest.py b/src/engine/SCons/Conftest.py index e9702ff0..23441f1b 100644 --- a/src/engine/SCons/Conftest.py +++ b/src/engine/SCons/Conftest.py @@ -101,7 +101,6 @@ Autoconf-like configuration support; low level implementation of tests. # import re -from types import IntType # # PUBLIC VARIABLES @@ -729,7 +728,7 @@ def _Have(context, key, have, comment = None): line = "#define %s 1\n" % key_up elif have == 0: line = "/* #undef %s */\n" % key_up - elif isinstance(have, IntType): + elif isinstance(have, int): line = "#define %s %d\n" % (key_up, have) else: line = "#define %s %s\n" % (key_up, str(have)) diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index a99bcc78..92f23445 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -183,11 +183,11 @@ def copy_func(dest, src): if SCons.Util.is_List(src) and os.path.isdir(dest): for file in src: shutil.copy2(file, dest) - return 0 elif os.path.isfile(src): - return shutil.copy2(src, dest) + shutil.copy2(src, dest) else: - return shutil.copytree(src, dest, 1) + shutil.copytree(src, dest, 1) + return 0 Copy = ActionFactory(copy_func, lambda dest, src: 'Copy("%s", "%s")' % (dest, src), @@ -221,7 +221,7 @@ def mkdir_func(dest): for entry in dest: try: os.makedirs(str(entry)) - except os.error, e: + except os.error as e: p = str(entry) if (e.args[0] == errno.EEXIST or (sys.platform=='win32' and e.args[0]==183)) \ @@ -381,7 +381,7 @@ def processDefines(defs): else: l.append(str(d[0])) elif SCons.Util.is_Dict(d): - for macro,value in d.iteritems(): + for macro,value in d.items(): if value is not None: l.append(str(macro) + '=' + str(value)) else: diff --git a/src/engine/SCons/DefaultsTests.py b/src/engine/SCons/DefaultsTests.py index 8b9fb4ec..141243b6 100644 --- a/src/engine/SCons/DefaultsTests.py +++ b/src/engine/SCons/DefaultsTests.py @@ -70,7 +70,7 @@ class DefaultsTestCase(unittest.TestCase): test.write(file, "test\n") try: mkdir_func(file) - except os.error, e: + except os.error as e: pass else: fail("expected os.error") diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 3e499b6c..737289b0 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -128,7 +128,7 @@ future_reserved_construction_var_names = [ def copy_non_reserved_keywords(dict): result = semi_deepcopy(dict) - for k in result.keys(): + for k in list(result.keys()): if k in reserved_construction_var_names: msg = "Ignoring attempt to set reserved variable `$%s'" SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k) @@ -147,7 +147,7 @@ def _set_future_reserved(env, key, value): def _set_BUILDERS(env, key, value): try: bd = env._dict[key] - for k in bd.keys(): + for k in list(bd.keys()): del bd[k] except KeyError: bd = BuilderDict(kwbd, env) @@ -399,8 +399,8 @@ class SubstitutionEnvironment(object): # gotten better than dict.has_key() in Python 2.5.) self._special_set_keys = list(self._special_set.keys()) - def __cmp__(self, other): - return cmp(self._dict, other._dict) + def __eq__(self, other): + return self._dict == other._dict def __delitem__(self, key): special = self._special_del.get(key) @@ -592,7 +592,7 @@ class SubstitutionEnvironment(object): out,err = p.communicate() status = p.wait() if err: - sys.stderr.write(unicode(err)) + sys.stderr.write(u"" + err) if status: raise OSError("'%s' exited %d" % (command, status)) return out @@ -1153,7 +1153,7 @@ class Base(SubstitutionEnvironment): in an Environment. """ kw = copy_non_reserved_keywords(kw) - for key, val in kw.items(): + for key, val in list(kw.items()): # It would be easier on the eyes to write this using # "continue" statements whenever we finish processing an item, # but Python 1.5.2 apparently doesn't let you use "continue" @@ -1206,7 +1206,7 @@ class Base(SubstitutionEnvironment): # based on what we think the value looks like. if SCons.Util.is_List(val): if key == 'CPPDEFINES': - orig = orig.items() + orig = list(orig.items()) orig += val self._dict[key] = orig else: @@ -1217,7 +1217,7 @@ class Base(SubstitutionEnvironment): update_dict(val) except (AttributeError, TypeError, ValueError): if SCons.Util.is_Dict(val): - for k, v in val.items(): + for k, v in list(val.items()): orig[k] = v else: orig[val] = None @@ -1287,7 +1287,7 @@ class Base(SubstitutionEnvironment): tmp.append((i,)) val = tmp if SCons.Util.is_Dict(dk): - dk = dk.items() + dk = list(dk.items()) elif SCons.Util.is_String(dk): dk = [(dk,)] else: @@ -1328,11 +1328,11 @@ class Base(SubstitutionEnvironment): tmp.append((i,)) dk = tmp if SCons.Util.is_Dict(val): - val = val.items() + val = list(val.items()) elif SCons.Util.is_String(val): val = [(val,)] if delete_existing: - dk = filter(lambda x, val=val: x not in val, dk) + dk = list(filter(lambda x, val=val: x not in val, dk)) self._dict[key] = dk + val else: dk = [x for x in dk if x not in val] @@ -1341,7 +1341,7 @@ class Base(SubstitutionEnvironment): # By elimination, val is not a list. Since dk is a # list, wrap val in a list first. if delete_existing: - dk = filter(lambda x, val=val: x not in val, dk) + dk = list(filter(lambda x, val=val: x not in val, dk)) self._dict[key] = dk + [val] else: if not val in dk: @@ -1351,7 +1351,7 @@ class Base(SubstitutionEnvironment): if SCons.Util.is_String(dk): dk = [dk] elif SCons.Util.is_Dict(dk): - dk = dk.items() + dk = list(dk.items()) if SCons.Util.is_String(val): if val in dk: val = [] @@ -1359,7 +1359,7 @@ class Base(SubstitutionEnvironment): val = [val] elif SCons.Util.is_Dict(val): tmp = [] - for i,j in val.iteritems(): + for i,j in val.items(): if j is not None: tmp.append((i,j)) else: @@ -1657,7 +1657,7 @@ class Base(SubstitutionEnvironment): update_dict(val) except (AttributeError, TypeError, ValueError): if SCons.Util.is_Dict(val): - for k, v in val.items(): + for k, v in list(val.items()): orig[k] = v else: orig[val] = None @@ -1769,7 +1769,7 @@ class Base(SubstitutionEnvironment): return os.path.join(dir, new_prefix+name+new_suffix) def SetDefault(self, **kw): - for k in kw.keys(): + for k in list(kw.keys()): if k in self._dict: del kw[k] self.Replace(**kw) @@ -2244,7 +2244,7 @@ class Base(SubstitutionEnvironment): while (node != node.srcnode()): node = node.srcnode() return node - sources = map( final_source, sources ); + sources = list(map( final_source, sources )); # remove duplicates return list(set(sources)) @@ -2387,7 +2387,7 @@ def NoSubstitutionProxy(subject): def __setattr__(self, name, value): return setattr(self.__dict__['__subject'], name, value) def executor_to_lvars(self, kwdict): - if kwdict.has_key('executor'): + if 'executor' in kwdict: kwdict['lvars'] = kwdict['executor'].get_lvars() del kwdict['executor'] else: diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 52353428..c6e1f3b8 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -114,11 +115,11 @@ class Scanner(object): global scanned_it scanned_it[filename] = 1 - def __cmp__(self, other): + def __eq__(self, other): try: - return cmp(self.__dict__, other.__dict__) + return self.__dict__ == other.__dict__ except AttributeError: - return 1 + return False def get_skeys(self, env): return self.skeys @@ -265,16 +266,10 @@ class SubstitutionTestCase(unittest.TestCase): assert isinstance(nodes[0], X) assert nodes[0].name == "Util.py UtilTests.py" - try: unicode - except NameError: pass - else: - code = """if 1: - nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory) - assert len(nodes) == 1, nodes - assert isinstance(nodes[0], X) - assert nodes[0].name == u"Util.py UtilTests.py" - \n""" - exec code in globals(), locals() + nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory) + assert len(nodes) == 1, nodes + assert isinstance(nodes[0], X) + assert nodes[0].name == u"Util.py UtilTests.py" nodes = env.arg2nodes(["Util.py", "UtilTests.py"], Factory) assert len(nodes) == 2, nodes @@ -657,7 +652,7 @@ sys.exit(0) cmd = '%s %s' % (python, test.workpath('fail.py')) try: env.backtick(cmd) - except OSError, e: + except OSError as e: assert str(e) == "'%s' exited 1" % cmd, str(e) else: self.fail("did not catch expected OSError") @@ -1588,17 +1583,17 @@ def exists(env): env['XXX'] = copy.copy(input) try: env.Append(XXX = append) - except Exception, e: - if failed == 0: print - print " %s Append %s exception: %s" % \ - (repr(input), repr(append), e) + except Exception as e: + if failed == 0: print() + print(" %s Append %s exception: %s" % \ + (repr(input), repr(append), e)) failed = failed + 1 else: result = env['XXX'] if result != expect: - if failed == 0: print - print " %s Append %s => %s did not match %s" % \ - (repr(input), repr(append), repr(result), repr(expect)) + if failed == 0: print() + print(" %s Append %s => %s did not match %s" % \ + (repr(input), repr(append), repr(result), repr(expect))) failed = failed + 1 del cases[:3] assert failed == 0, "%d Append() cases failed" % failed @@ -1620,7 +1615,7 @@ def exists(env): self.name = name def __str__(self): return self.name - def __cmp__(self, other): + def __eq__(self, other): raise Exception("should not compare") ccc = C('ccc') @@ -1943,7 +1938,7 @@ def generate(env): assert x is None, x sub2_xxx_exe = test.workpath('sub2', 'xxx.exe') - os.chmod(sub2_xxx_exe, 0755) + os.chmod(sub2_xxx_exe, 0o755) env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] }) @@ -1951,7 +1946,7 @@ def generate(env): assert x == 'xxx.exe', x sub1_xxx_exe = test.workpath('sub1', 'xxx.exe') - os.chmod(sub1_xxx_exe, 0755) + os.chmod(sub1_xxx_exe, 0o755) x = env.Detect('xxx.exe') assert x == 'xxx.exe', x @@ -2266,17 +2261,17 @@ f5: \ env['XXX'] = copy.copy(input) try: env.Prepend(XXX = prepend) - except Exception, e: - if failed == 0: print - print " %s Prepend %s exception: %s" % \ - (repr(input), repr(prepend), e) + except Exception as e: + if failed == 0: print() + print(" %s Prepend %s exception: %s" % \ + (repr(input), repr(prepend), e)) failed = failed + 1 else: result = env['XXX'] if result != expect: - if failed == 0: print - print " %s Prepend %s => %s did not match %s" % \ - (repr(input), repr(prepend), repr(result), repr(expect)) + if failed == 0: print() + print(" %s Prepend %s => %s did not match %s" % \ + (repr(input), repr(prepend), repr(result), repr(expect))) failed = failed + 1 del cases[:3] assert failed == 0, "%d Prepend() cases failed" % failed @@ -2514,10 +2509,10 @@ def generate(env): os.mkdir(sub2_xxx_exe) test.write(sub3_xxx_exe, "\n") - os.chmod(sub3_xxx_exe, 0777) + os.chmod(sub3_xxx_exe, 0o777) test.write(sub4_xxx_exe, "\n") - os.chmod(sub4_xxx_exe, 0777) + os.chmod(sub4_xxx_exe, 0o777) env_path = os.environ['PATH'] diff --git a/src/engine/SCons/Errors.py b/src/engine/SCons/Errors.py index 3b8c3f90..54e888c3 100644 --- a/src/engine/SCons/Errors.py +++ b/src/engine/SCons/Errors.py @@ -32,8 +32,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -import exceptions - class BuildError(Exception): """ Errors occuring while building. @@ -163,7 +161,7 @@ def convert_to_BuildError(status, exc_info=None): status=2, exitstatus=2, exc_info=exc_info) - elif isinstance(status, exceptions.EnvironmentError): + elif isinstance(status, EnvironmentError): # If an IOError/OSError happens, raise a BuildError. # Report the name of the file or directory that caused the # error, which might be different from the target being built diff --git a/src/engine/SCons/ErrorsTests.py b/src/engine/SCons/ErrorsTests.py index d57faa50..c38158dd 100644 --- a/src/engine/SCons/ErrorsTests.py +++ b/src/engine/SCons/ErrorsTests.py @@ -38,7 +38,7 @@ class ErrorsTestCase(unittest.TestCase): raise SCons.Errors.BuildError( errstr = "foo", status=57, filename="file", exc_info=(1,2,3), node = "n", executor="e", action="a", command="c") - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: assert e.errstr == "foo" assert e.status == 57 assert e.exitstatus == 2, e.exitstatus @@ -53,7 +53,7 @@ class ErrorsTestCase(unittest.TestCase): try: raise SCons.Errors.BuildError("n", "foo", 57, 3, "file", "e", "a", "c", (1,2,3)) - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: assert e.errstr == "foo", e.errstr assert e.status == 57, e.status assert e.exitstatus == 3, e.exitstatus @@ -67,7 +67,7 @@ class ErrorsTestCase(unittest.TestCase): try: raise SCons.Errors.BuildError() - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: assert e.errstr == "Unknown error" assert e.status == 2 assert e.exitstatus == 2 @@ -83,21 +83,21 @@ class ErrorsTestCase(unittest.TestCase): """Test the InternalError exception.""" try: raise SCons.Errors.InternalError("test internal error") - except SCons.Errors.InternalError, e: + except SCons.Errors.InternalError as e: assert e.args == ("test internal error",) def test_UserError(self): """Test the UserError exception.""" try: raise SCons.Errors.UserError("test user error") - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert e.args == ("test user error",) def test_ExplicitExit(self): """Test the ExplicitExit exception.""" try: raise SCons.Errors.ExplicitExit("node") - except SCons.Errors.ExplicitExit, e: + except SCons.Errors.ExplicitExit as e: assert e.node == "node" if __name__ == "__main__": diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py index 051d275f..2c53f21d 100644 --- a/src/engine/SCons/Executor.py +++ b/src/engine/SCons/Executor.py @@ -431,9 +431,9 @@ class Executor(object): except KeyError: pass env = self.get_build_env() - result = "".join([action.get_contents(self.get_all_targets(), - self.get_all_sources(), - env) + result = b"".join([action.get_contents(self.get_all_targets(), + self.get_all_sources(), + env) for action in self.get_action_list()]) self._memo['get_contents'] = result return result diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py index 9df0b2d1..c649f0ed 100644 --- a/src/engine/SCons/ExecutorTests.py +++ b/src/engine/SCons/ExecutorTests.py @@ -309,7 +309,7 @@ class ExecutorTestCase(unittest.TestCase): try: r = x.prepare() - except SCons.Errors.StopError, e: + except SCons.Errors.StopError as e: assert str(e) == "Source `s2' not found, needed by target `t1'.", e else: raise AssertionError("did not catch expected StopError: %s" % r) diff --git a/src/engine/SCons/Job.py b/src/engine/SCons/Job.py index 184f5ba3..226a34e7 100644 --- a/src/engine/SCons/Job.py +++ b/src/engine/SCons/Job.py @@ -278,14 +278,14 @@ else: try: prev_size = threading.stack_size(stack_size*1024) - except AttributeError, e: + except AttributeError as e: # Only print a warning if the stack size has been # explicitly set. if not explicit_stack_size is None: msg = "Setting stack size is unsupported by this version of Python:\n " + \ e.args[0] SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) - except ValueError, e: + except ValueError as e: msg = "Setting stack size failed:\n " + str(e) SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) diff --git a/src/engine/SCons/Memoize.py b/src/engine/SCons/Memoize.py index e77aacf7..d2938c76 100644 --- a/src/engine/SCons/Memoize.py +++ b/src/engine/SCons/Memoize.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -143,12 +144,12 @@ class Counter(object): CounterList.append(self) def display(self): fmt = " %7d hits %7d misses %s()" - print fmt % (self.hit, self.miss, self.name) - def __cmp__(self, other): + print(fmt % (self.hit, self.miss, self.name)) + def __eq__(self, other): try: - return cmp(self.name, other.name) + return self.name == other.name except AttributeError: - return 0 + return True class CountValue(Counter): """ @@ -215,7 +216,7 @@ class Memoizer(object): def Dump(title=None): if title: - print title + print(title) CounterList.sort() for counter in CounterList: counter.display() diff --git a/src/engine/SCons/MemoizeTests.py b/src/engine/SCons/MemoizeTests.py index 3606d576..c1c69ae8 100644 --- a/src/engine/SCons/MemoizeTests.py +++ b/src/engine/SCons/MemoizeTests.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from six import add_metaclass __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -31,11 +32,9 @@ import TestUnit import SCons.Memoize - +@add_metaclass(SCons.Memoize.Memoized_Metaclass) class FakeObject(object): - __metaclass__ = SCons.Memoize.Memoized_Metaclass - memoizer_counters = [] def __init__(self): diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 219718cc..a537ca85 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -31,6 +31,7 @@ that can be used by scripts or modules looking for the canonical default. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -551,7 +552,7 @@ class EntryProxy(SCons.Util.Proxy): except KeyError: try: attr = SCons.Util.Proxy.__getattr__(self, name) - except AttributeError, e: + except AttributeError as e: # Raise our own AttributeError subclass with an # overridden __str__() method that identifies the # name of the entry that caused the exception. @@ -2423,7 +2424,7 @@ class File(Base): fname = self.rfile().abspath try: contents = open(fname, "rb").read() - except EnvironmentError, e: + except EnvironmentError as e: if not e.filename: e.filename = fname raise @@ -2458,7 +2459,7 @@ class File(Base): try: cs = SCons.Util.MD5filesignature(fname, chunksize=SCons.Node.FS.File.md5_chunksize*1024) - except EnvironmentError, e: + except EnvironmentError as e: if not e.filename: e.filename = fname raise @@ -2848,7 +2849,7 @@ class File(Base): def _rmv_existing(self): self.clear_memoized_values() if print_duplicate: - print "dup: removing existing target %s"%self + print("dup: removing existing target %s"%self) e = Unlink(self, [], None) if isinstance(e, SCons.Errors.BuildError): raise e @@ -2872,7 +2873,7 @@ class File(Base): else: try: self._createDir() - except SCons.Errors.StopError, drive: + except SCons.Errors.StopError as drive: desc = "No drive `%s' for target `%s'." % (drive, self) raise SCons.Errors.StopError(desc) @@ -2890,7 +2891,7 @@ class File(Base): def do_duplicate(self, src): self._createDir() if print_duplicate: - print "dup: relinking variant '%s' from '%s'"%(self, src) + print("dup: relinking variant '%s' from '%s'"%(self, src)) Unlink(self, None, None) e = Link(self, src, None) if isinstance(e, SCons.Errors.BuildError): @@ -2925,7 +2926,7 @@ class File(Base): # The source file does not exist. Make sure no old # copy remains in the variant directory. if print_duplicate: - print "dup: no src for %s, unlinking old variant copy"%self + print("dup: no src for %s, unlinking old variant copy"%self) if Base.exists(self) or self.islink(): self.fs.unlink(self.path) # Return None explicitly because the Base.exists() call diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index c4dc2ced..9a8763a6 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -20,7 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -from __future__ import division +from __future__ import division, print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -569,13 +569,13 @@ class VariantDirTestCase(unittest.TestCase): dp = dnode.srcnode().path expect = os.path.normpath(srcnode_map.get(dir, dir)) if dp != expect: - print "Dir `%s' srcnode() `%s' != expected `%s'" % (dir, dp, expect) + print("Dir `%s' srcnode() `%s' != expected `%s'" % (dir, dp, expect)) errors = errors + 1 fp = fnode.srcnode().path expect = os.path.normpath(srcnode_map.get(f, f)) if fp != expect: - print "File `%s' srcnode() `%s' != expected `%s'" % (f, fp, expect) + print("File `%s' srcnode() `%s' != expected `%s'" % (f, fp, expect)) errors = errors + 1 for dir in dir_list: @@ -587,14 +587,14 @@ class VariantDirTestCase(unittest.TestCase): tp = t[0].path expect = os.path.normpath(alter_map.get(dir, dir)) if tp != expect: - print "Dir `%s' alter_targets() `%s' != expected `%s'" % (dir, tp, expect) + print("Dir `%s' alter_targets() `%s' != expected `%s'" % (dir, tp, expect)) errors = errors + 1 t, m = fnode.alter_targets() tp = t[0].path expect = os.path.normpath(alter_map.get(f, f)) if tp != expect: - print "File `%s' alter_targets() `%s' != expected `%s'" % (f, tp, expect) + print("File `%s' alter_targets() `%s' != expected `%s'" % (f, tp, expect)) errors = errors + 1 self.failIf(errors) @@ -1090,7 +1090,7 @@ class FSTestCase(_tempdirTestCase): try: f2 = fs.File(sep.join(['f1', 'f2']), directory = d1) - except TypeError, x: + except TypeError as x: assert str(x) == ("Tried to lookup File '%s' as a Dir." % d1_f1), x except: @@ -1098,7 +1098,7 @@ class FSTestCase(_tempdirTestCase): try: dir = fs.Dir(sep.join(['d1', 'f1'])) - except TypeError, x: + except TypeError as x: assert str(x) == ("Tried to lookup File '%s' as a Dir." % d1_f1), x except: @@ -1106,7 +1106,7 @@ class FSTestCase(_tempdirTestCase): try: f2 = fs.File('d1') - except TypeError, x: + except TypeError as x: assert str(x) == ("Tried to lookup Dir '%s' as a File." % 'd1'), x except: @@ -1647,7 +1647,7 @@ class FSTestCase(_tempdirTestCase): def unc_workpath(dirs, test=test): import ntpath - x = apply(test.workpath, dirs) + x = test.workpath(*dirs) drive, path = ntpath.splitdrive(x) unc, path = ntpath.splitunc(path) path = strip_slash(path) @@ -1913,9 +1913,9 @@ class FSTestCase(_tempdirTestCase): del cases[:3] result = dir.rel_path(other) if result != expect: - if failed == 0: print + if failed == 0: print() fmt = " dir_path(%(dir)s, %(other)s) => '%(result)s' did not match '%(expect)s'" - print fmt % locals() + print(fmt % locals()) failed = failed + 1 assert failed == 0, "%d rel_path() cases failed" % failed @@ -2522,9 +2522,9 @@ class GlobTestCase(_tempdirTestCase): fmt = lambda n: n if r != result: import pprint - print "Glob(%s) expected:" % repr(input) + print("Glob(%s) expected:" % repr(input)) pprint.pprint(list(map(fmt, result))) - print "Glob(%s) got:" % repr(input) + print("Glob(%s) got:" % repr(input)) pprint.pprint(list(map(fmt, r))) self.fail() @@ -3623,7 +3623,7 @@ class SpecialAttrTestCase(unittest.TestCase): caught = None try: fs.Dir('ddd').get_subst_proxy().no_such_attr - except AttributeError, e: + except AttributeError as e: assert str(e) == "Dir instance 'ddd' has no attribute 'no_such_attr'", e caught = 1 assert caught, "did not catch expected AttributeError" @@ -3631,7 +3631,7 @@ class SpecialAttrTestCase(unittest.TestCase): caught = None try: fs.Entry('eee').get_subst_proxy().no_such_attr - except AttributeError, e: + except AttributeError as e: # Gets disambiguated to File instance by get_subst_proxy(). assert str(e) == "File instance 'eee' has no attribute 'no_such_attr'", e caught = 1 @@ -3640,7 +3640,7 @@ class SpecialAttrTestCase(unittest.TestCase): caught = None try: fs.File('fff').get_subst_proxy().no_such_attr - except AttributeError, e: + except AttributeError as e: assert str(e) == "File instance 'fff' has no attribute 'no_such_attr'", e caught = 1 assert caught, "did not catch expected AttributeError" diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 1f629712..f13fd03a 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -384,7 +384,7 @@ class Node(object): """ try: self.get_executor()(self, **kw) - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: e.node = self raise @@ -868,7 +868,7 @@ class Node(object): """Adds dependencies.""" try: self._add_child(self.depends, self.depends_set, depend) - except TypeError, e: + except TypeError as e: e = e.args[0] if SCons.Util.is_List(e): s = list(map(str, e)) @@ -887,7 +887,7 @@ class Node(object): """Adds dependencies to ignore.""" try: self._add_child(self.ignore, self.ignore_set, depend) - except TypeError, e: + except TypeError as e: e = e.args[0] if SCons.Util.is_List(e): s = list(map(str, e)) @@ -901,7 +901,7 @@ class Node(object): return try: self._add_child(self.sources, self.sources_set, source) - except TypeError, e: + except TypeError as e: e = e.args[0] if SCons.Util.is_List(e): s = list(map(str, e)) diff --git a/src/engine/SCons/Options/__init__.py b/src/engine/SCons/Options/__init__.py index f6c84835..2544aecd 100644 --- a/src/engine/SCons/Options/__init__.py +++ b/src/engine/SCons/Options/__init__.py @@ -33,11 +33,11 @@ and will then be removed entirely (some day). import SCons.Variables import SCons.Warnings -from BoolOption import BoolOption # okay -from EnumOption import EnumOption # okay -from ListOption import ListOption # naja -from PackageOption import PackageOption # naja -from PathOption import PathOption # okay +from .BoolOption import BoolOption # okay +from .EnumOption import EnumOption # okay +from .ListOption import ListOption # naja +from .PackageOption import PackageOption # naja +from .PathOption import PathOption # okay warned = False diff --git a/src/engine/SCons/Platform/__init__.py b/src/engine/SCons/Platform/__init__.py index 81a49e7e..dba36062 100644 --- a/src/engine/SCons/Platform/__init__.py +++ b/src/engine/SCons/Platform/__init__.py @@ -41,6 +41,7 @@ their own platform definition. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -223,8 +224,8 @@ class TempFileMunge(object): # purity get in the way of just being helpful, so we'll # reach into SCons.Action directly. if SCons.Action.print_actions: - print("Using tempfile "+native_tmp+" for command line:\n"+ - str(cmd[0]) + " " + " ".join(args)) + print(("Using tempfile "+native_tmp+" for command line:\n"+ + str(cmd[0]) + " " + " ".join(args))) return [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ] def Platform(name = platform_default()): diff --git a/src/engine/SCons/Platform/aix.py b/src/engine/SCons/Platform/aix.py index 0229112d..f6853b55 100644 --- a/src/engine/SCons/Platform/aix.py +++ b/src/engine/SCons/Platform/aix.py @@ -34,7 +34,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -import posix +from . import posix def get_xlc(env, xlc=None, xlc_r=None, packages=[]): # Use the AIX package installer tool lslpp to figure out where a diff --git a/src/engine/SCons/Platform/cygwin.py b/src/engine/SCons/Platform/cygwin.py index a0126826..e7c8b8a3 100644 --- a/src/engine/SCons/Platform/cygwin.py +++ b/src/engine/SCons/Platform/cygwin.py @@ -32,7 +32,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import posix +from . import posix from SCons.Platform import TempFileMunge def generate(env): diff --git a/src/engine/SCons/Platform/darwin.py b/src/engine/SCons/Platform/darwin.py index 005673b2..1cf4aeb5 100644 --- a/src/engine/SCons/Platform/darwin.py +++ b/src/engine/SCons/Platform/darwin.py @@ -32,7 +32,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import posix +from . import posix import os def generate(env): diff --git a/src/engine/SCons/Platform/hpux.py b/src/engine/SCons/Platform/hpux.py index 43d284b5..0e0bbcf8 100644 --- a/src/engine/SCons/Platform/hpux.py +++ b/src/engine/SCons/Platform/hpux.py @@ -32,7 +32,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import posix +from . import posix def generate(env): posix.generate(env) diff --git a/src/engine/SCons/Platform/irix.py b/src/engine/SCons/Platform/irix.py index 2baee0bb..2e5f2176 100644 --- a/src/engine/SCons/Platform/irix.py +++ b/src/engine/SCons/Platform/irix.py @@ -32,7 +32,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import posix +from . import posix def generate(env): posix.generate(env) diff --git a/src/engine/SCons/Platform/os2.py b/src/engine/SCons/Platform/os2.py index 0fa45531..5ca26bcc 100644 --- a/src/engine/SCons/Platform/os2.py +++ b/src/engine/SCons/Platform/os2.py @@ -31,7 +31,7 @@ selection method. # __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import win32 +from . import win32 def generate(env): if 'ENV' not in env: diff --git a/src/engine/SCons/Platform/sunos.py b/src/engine/SCons/Platform/sunos.py index d23d65c5..057fddfa 100644 --- a/src/engine/SCons/Platform/sunos.py +++ b/src/engine/SCons/Platform/sunos.py @@ -32,7 +32,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import posix +from . import posix def generate(env): posix.generate(env) diff --git a/src/engine/SCons/Platform/win32.py b/src/engine/SCons/Platform/win32.py index 5f20685c..1e4fb2a8 100644 --- a/src/engine/SCons/Platform/win32.py +++ b/src/engine/SCons/Platform/win32.py @@ -61,16 +61,21 @@ else: parallel_msg = None import builtins - - _builtin_file = builtins.file + builtin_file = getattr(builtins, 'file', None) is not None + + if builtin_file: + _builtin_file = builtins.file + + class _scons_file(_builtin_file): + def __init__(self, *args, **kw): + _builtin_file.__init__(self, *args, **kw) + win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()), + win32con.HANDLE_FLAG_INHERIT, 0) + + builtins.file = _scons_file + _builtin_open = builtins.open - class _scons_file(_builtin_file): - def __init__(self, *args, **kw): - _builtin_file.__init__(self, *args, **kw) - win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()), - win32con.HANDLE_FLAG_INHERIT, 0) - def _scons_open(*args, **kw): fp = _builtin_open(*args, **kw) win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), @@ -78,7 +83,6 @@ else: 0) return fp - builtins.file = _scons_file builtins.open = _scons_open try: @@ -155,7 +159,7 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): try: args = [sh, '/C', escape(' '.join(args)) ] ret = spawnve(os.P_WAIT, sh, args, env) - except OSError, e: + except OSError as e: # catch any error try: ret = exitvalmap[e[0]] @@ -183,7 +187,7 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr): def exec_spawn(l, env): try: result = spawnve(os.P_WAIT, l[0], l, env) - except OSError, e: + except OSError as e: try: result = exitvalmap[e[0]] sys.stderr.write("scons: %s: %s\n" % (l[0], e[1])) diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py index 7a8a0c21..be0b9c17 100644 --- a/src/engine/SCons/SConf.py +++ b/src/engine/SCons/SConf.py @@ -25,6 +25,7 @@ Autoconf-like configuration support. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -239,7 +240,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask): # Earlier versions of Python don't have sys.excepthook... def excepthook(type, value, tb): traceback.print_tb(tb) - print type, value + print(type, value) excepthook(*self.exc_info()) return SCons.Taskmaster.Task.failed(self) @@ -318,7 +319,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask): env_decider=env.decide_source): env_decider(dependency, target, prev_ni) return True - if env.decide_source.func_code is not force_build.func_code: + if env.decide_source.__code__ is not force_build.__code__: env.Decider(force_build) env['PSTDOUT'] = env['PSTDERR'] = s try: @@ -332,7 +333,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask): except SystemExit: exc_value = sys.exc_info()[1] raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code) - except Exception, e: + except Exception as e: for t in self.targets: binfo = t.get_binfo() binfo.__class__ = SConfBuildInfo diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py index 1c4b4010..4ce5f5c2 100644 --- a/src/engine/SCons/SConfTests.py +++ b/src/engine/SCons/SConfTests.py @@ -62,7 +62,7 @@ class SConfTestCase(unittest.TestCase): # We try to reset scons' state (including all global variables) import SCons.SConsign SCons.SConsign.write() # simulate normal scons-finish - for n in sys.modules.keys(): + for n in list(sys.modules.keys()): if n.split('.')[0] == 'SCons' and n[:12] != 'SCons.compat': m = sys.modules[n] if isinstance(m, ModuleType): diff --git a/src/engine/SCons/SConsign.py b/src/engine/SCons/SConsign.py index 6555fcb8..ab8e297a 100644 --- a/src/engine/SCons/SConsign.py +++ b/src/engine/SCons/SConsign.py @@ -26,6 +26,7 @@ Writing and reading information to the .sconsign file or files. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -84,7 +85,7 @@ def Get_DataBase(dir): DB_sync_list.append(db) return db, "c" except TypeError: - print "DataBase =", DataBase + print("DataBase =", DataBase) raise def Reset(): @@ -215,7 +216,7 @@ class DB(Base): raise TypeError except KeyboardInterrupt: raise - except Exception, e: + except Exception as e: SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, "Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.tpath, e)) for key, entry in self.entries.items(): @@ -274,7 +275,7 @@ class Dir(Base): raise TypeError if dir: - for key, entry in self.entries.items(): + for key, entry in list(self.entries.items()): entry.convert_from_sconsign(dir, key) class DirFile(Dir): @@ -340,7 +341,7 @@ class DirFile(Dir): if fname != self.sconsign: try: mode = os.stat(self.sconsign)[0] - os.chmod(self.sconsign, 0666) + os.chmod(self.sconsign, 0o666) os.unlink(self.sconsign) except (IOError, OSError): # Try to carry on in the face of either OSError diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py index 3311a095..74b01a4c 100644 --- a/src/engine/SCons/Scanner/C.py +++ b/src/engine/SCons/Scanner/C.py @@ -59,7 +59,7 @@ class SConsCPPScanner(SCons.cpp.PreProcessor): def read_file(self, file): try: fp = open(str(file.rfile())) - except EnvironmentError, e: + except EnvironmentError as e: self.missing.append((file, self.current_file)) return '' else: diff --git a/src/engine/SCons/Scanner/ProgTests.py b/src/engine/SCons/Scanner/ProgTests.py index 144addb1..a5c89565 100644 --- a/src/engine/SCons/Scanner/ProgTests.py +++ b/src/engine/SCons/Scanner/ProgTests.py @@ -247,7 +247,7 @@ def suite(): assert deps_match(deps, ['d1/l2.lib', 'd1/d2/l3.lib']), map(str, deps) suite.addTest(ProgramScannerTestCase4()) \n""" - exec code + exec(code) return suite if __name__ == "__main__": diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py index 24965346..e34dcada 100644 --- a/src/engine/SCons/Scanner/ScannerTests.py +++ b/src/engine/SCons/Scanner/ScannerTests.py @@ -236,7 +236,7 @@ class BaseTestCase(unittest.TestCase): def test___cmp__(self): """Test the Scanner.Base class __cmp__() method""" s = SCons.Scanner.Base(self.func, "Cmp") - assert cmp(s, None) + assert s != None def test_hash(self): """Test the Scanner.Base class __hash__() method""" diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py index 562a361e..5700fe92 100644 --- a/src/engine/SCons/Scanner/__init__.py +++ b/src/engine/SCons/Scanner/__init__.py @@ -221,12 +221,12 @@ class Base(object): nodes.append(l) return nodes - def __cmp__(self, other): + def __eq__(self, other): try: - return cmp(self.__dict__, other.__dict__) + return self.__dict__ == other.__dict__ except AttributeError: # other probably doesn't have a __dict__ - return cmp(self.__dict__, other) + return self.__dict__ == other def __hash__(self): return id(self) @@ -324,7 +324,7 @@ class Classic(Current): def __init__(self, name, suffixes, path_variable, regex, *args, **kw): - self.cre = re.compile(regex, re.M) + self.cre = re.compile(SCons.Util.to_bytes(regex), re.M) def _scan(node, env, path=(), self=self): node = node.rfile() @@ -393,6 +393,7 @@ class ClassicCPP(Classic): the contained filename in group 1. """ def find_include(self, include, source_dir, path): + include = list (map (SCons.Util.to_str, include)) if include[0] == '"': paths = (source_dir,) + tuple(path) else: @@ -404,7 +405,7 @@ class ClassicCPP(Classic): return n, i def sort_key(self, include): - return SCons.Node.FS._my_normcase(' '.join(include)) + return SCons.Node.FS._my_normcase(b' '.join(include)) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Script/Interactive.py b/src/engine/SCons/Script/Interactive.py index ffb50962..0b28f1a8 100644 --- a/src/engine/SCons/Script/Interactive.py +++ b/src/engine/SCons/Script/Interactive.py @@ -19,6 +19,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -129,12 +130,12 @@ class SConsInteractiveCmd(cmd.Cmd): self.shell_variable = 'SHELL' def default(self, argv): - print "*** Unknown command: %s" % argv[0] + print("*** Unknown command: %s" % argv[0]) def onecmd(self, line): line = line.strip() if not line: - print self.lastcmd + print(self.lastcmd) return self.emptyline() self.lastcmd = line if line[0] == '!': @@ -274,7 +275,7 @@ class SConsInteractiveCmd(cmd.Cmd): return self.do_build(['build', '--clean'] + argv[1:]) def do_EOF(self, argv): - print + print() self.do_exit(argv) def _do_one_help(self, arg): @@ -357,7 +358,7 @@ class SConsInteractiveCmd(cmd.Cmd): # Doing the right thing with an argument list currently # requires different shell= values on Windows and Linux. p = subprocess.Popen(argv, shell=(sys.platform=='win32')) - except EnvironmentError, e: + except EnvironmentError as e: sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror)) else: p.wait() diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 93380fb1..79064880 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -10,6 +10,8 @@ some other module. If it's specific to the "scons" script invocation, it goes here. """ +from __future__ import print_function + unsupported_python_version = (2, 3, 0) deprecated_python_version = (2, 7, 0) @@ -229,7 +231,7 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask): self.exception_set() self.do_failed() else: - print "scons: Nothing to be done for `%s'." % t + print("scons: Nothing to be done for `%s'." % t) SCons.Taskmaster.OutOfDateTask.executed(self) else: SCons.Taskmaster.OutOfDateTask.executed(self) @@ -298,8 +300,8 @@ class BuildTask(SCons.Taskmaster.OutOfDateTask): if self.options.debug_includes: tree = t.render_include_tree() if tree: - print - print tree + print() + print(tree) SCons.Taskmaster.OutOfDateTask.postprocess(self) def make_ready(self): @@ -334,10 +336,10 @@ class CleanTask(SCons.Taskmaster.AlwaysTask): else: errstr = "Path '%s' exists but isn't a file or directory." raise SCons.Errors.UserError(errstr % (pathstr)) - except SCons.Errors.UserError, e: - print e - except (IOError, OSError), e: - print "scons: Could not remove '%s':" % pathstr, e.strerror + except SCons.Errors.UserError as e: + print(e) + except (IOError, OSError) as e: + print("scons: Could not remove '%s':" % pathstr, e.strerror) def show(self): target = self.targets[0] @@ -356,13 +358,13 @@ class CleanTask(SCons.Taskmaster.AlwaysTask): for t in self.targets: try: removed = t.remove() - except OSError, e: + except OSError as e: # An OSError may indicate something like a permissions # issue, an IOError would indicate something like # the file not existing. In either case, print a # message and keep going to try to remove as many # targets aa possible. - print "scons: Could not remove '%s':" % str(t), e.strerror + print("scons: Could not remove '%s':" % str(t), e.strerror) else: if removed: display("Removed " + str(t)) @@ -603,7 +605,7 @@ def _scons_internal_error(): """Handle all errors but user errors. Print out a message telling the user what to do in this case and print a normal trace. """ - print 'internal error' + print('internal error') traceback.print_exc() sys.exit(2) @@ -718,7 +720,7 @@ def _load_site_scons_dir(topdir, site_dir_name=None): # the error checking makes it longer. try: m = sys.modules['SCons.Script'] - except Exception, e: + except Exception as e: fmt = 'cannot import site_init.py: missing SCons.Script module %s' raise SCons.Errors.InternalError(fmt % repr(e)) try: @@ -731,10 +733,10 @@ def _load_site_scons_dir(topdir, site_dir_name=None): site_m[k] = m.__dict__[k] # This is the magic. - exec fp in site_m + exec(fp, site_m) except KeyboardInterrupt: raise - except Exception, e: + except Exception as e: fmt = '*** Error loading site_init file %s:\n' sys.stderr.write(fmt % repr(site_init_file)) raise @@ -744,7 +746,7 @@ def _load_site_scons_dir(topdir, site_dir_name=None): m.__dict__[k] = site_m[k] except KeyboardInterrupt: raise - except ImportError, e: + except ImportError as e: fmt = '*** cannot import site init file %s:\n' sys.stderr.write(fmt % repr(site_init_file)) raise @@ -796,7 +798,7 @@ def _load_all_site_scons_dirs(topdir, verbose=None): dirs=sysdirs + [topdir] for d in dirs: if verbose: # this is used by unit tests. - print "Loading site dir ", d + print("Loading site dir ", d) _load_site_scons_dir(d) def test_load_all_site_scons_dirs(d): @@ -988,7 +990,7 @@ def _main(parser): try: for script in scripts: SCons.Script._SConscript._SConscript(fs, script) - except SCons.Errors.StopError, e: + except SCons.Errors.StopError as e: # We had problems reading an SConscript file, such as it # couldn't be copied in to the VariantDir. Since we're just # reading SConscript files and haven't started building @@ -1045,8 +1047,8 @@ def _main(parser): # SConscript files. Give them the options usage. raise SConsPrintHelpException else: - print help_text - print "Use scons -H for help about command-line options." + print(help_text) + print("Use scons -H for help about command-line options.") exit_status = 0 return @@ -1084,7 +1086,7 @@ def _main(parser): nodes = _build_targets(fs, options, targets, target_top) if not nodes: revert_io() - print 'Found nothing to build' + print('Found nothing to build') exit_status = 2 def _build_targets(fs, options, targets, target_top): @@ -1346,7 +1348,7 @@ def main(): parts.append("__COPYRIGHT__") version = ''.join(parts) - import SConsOptions + from . import SConsOptions parser = SConsOptions.Parser(version) values = SConsOptions.SConsValues(parser.get_default_values()) @@ -1357,23 +1359,23 @@ def main(): _exec_main(parser, values) finally: revert_io() - except SystemExit, s: + except SystemExit as s: if s: exit_status = s except KeyboardInterrupt: print("scons: Build interrupted.") sys.exit(2) - except SyntaxError, e: + except SyntaxError as e: _scons_syntax_error(e) except SCons.Errors.InternalError: _scons_internal_error() - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: _scons_user_error(e) except SConsPrintHelpException: parser.print_help() exit_status = 0 - except SCons.Errors.BuildError, e: - print e + except SCons.Errors.BuildError as e: + print(e) exit_status = e.exitstatus except: # An exception here is likely a builtin Python exception Python @@ -1409,10 +1411,10 @@ def main(): else: ct = last_command_end - first_command_start scons_time = total_time - sconscript_time - ct - print "Total build time: %f seconds"%total_time - print "Total SConscript file execution time: %f seconds"%sconscript_time - print "Total SCons execution time: %f seconds"%scons_time - print "Total command execution time: %f seconds"%ct + print("Total build time: %f seconds"%total_time) + print("Total SConscript file execution time: %f seconds"%sconscript_time) + print("Total SCons execution time: %f seconds"%scons_time) + print("Total command execution time: %f seconds"%ct) sys.exit(exit_status) diff --git a/src/engine/SCons/Script/SConsOptions.py b/src/engine/SCons/Script/SConsOptions.py index d7262a9d..1250e6b0 100644 --- a/src/engine/SCons/Script/SConsOptions.py +++ b/src/engine/SCons/Script/SConsOptions.py @@ -161,7 +161,7 @@ class SConsValues(optparse.Values): elif name == 'diskcheck': try: value = diskcheck_convert(value) - except ValueError, v: + except ValueError as v: raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v) if 'diskcheck' not in self.__dict__: # No --diskcheck= option was specified on the command line. @@ -709,7 +709,7 @@ def Parser(version): def opt_diskcheck(option, opt, value, parser): try: diskcheck_value = diskcheck_convert(value) - except ValueError, e: + except ValueError as e: raise OptionValueError("`%s' is not a valid diskcheck type" % e) setattr(parser.values, option.dest, diskcheck_value) @@ -876,7 +876,7 @@ def Parser(version): tree_options = ["all", "derived", "prune", "status"] def opt_tree(option, opt, value, parser, tree_options=tree_options): - import Main + from . import Main tp = Main.TreePrinter() for o in value.split(','): if o == 'all': diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index bd515d25..3ee9464d 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -26,7 +26,6 @@ files. # 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. -from __future__ import division __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -113,7 +112,7 @@ def compute_exports(exports): retval[export] = loc[export] except KeyError: retval[export] = glob[export] - except KeyError, x: + except KeyError as x: raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x) return retval @@ -145,7 +144,7 @@ def Return(*vars, **kw): for var in fvars: for v in var.split(): retval.append(call_stack[-1].globals[v]) - except KeyError, x: + except KeyError as x: raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x) if len(retval) == 1: @@ -174,7 +173,7 @@ def _SConscript(fs, *files, **kw): try: SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1 if fn == "-": - exec sys.stdin in call_stack[-1].globals + exec(sys.stdin, call_stack[-1].globals) else: if isinstance(fn, SCons.Node.Node): f = fn @@ -257,7 +256,8 @@ def _SConscript(fs, *files, **kw): pass try: try: - exec _file_ in call_stack[-1].globals + exec(compile(_file_.read(), _file_.name, 'exec'), + call_stack[-1].globals) except SConscriptReturn: pass finally: @@ -282,7 +282,7 @@ def _SConscript(fs, *files, **kw): rdir._create() # Make sure there's a directory there. try: os.chdir(rdir.get_abspath()) - except OSError, e: + except OSError as e: # We still couldn't chdir there, so raise the error, # but only if actions are being executed. # @@ -467,15 +467,15 @@ class SConsEnvironment(SCons.Environment.Base): scons_ver_string = '%d.%d.%d' % (major, minor, revision) else: scons_ver_string = '%d.%d' % (major, minor) - print "SCons %s or greater required, but you have SCons %s" % \ - (scons_ver_string, SCons.__version__) + print("SCons %s or greater required, but you have SCons %s" % \ + (scons_ver_string, SCons.__version__)) sys.exit(2) def EnsurePythonVersion(self, major, minor): """Exit abnormally if the Python version is not late enough.""" if sys.version_info < (major, minor): v = sys.version.split()[0] - print "Python %d.%d or greater required, but you have Python %s" %(major,minor,v) + print("Python %d.%d or greater required, but you have Python %s" %(major,minor,v)) sys.exit(2) def Exit(self, value=0): @@ -514,7 +514,7 @@ class SConsEnvironment(SCons.Environment.Base): globals[v] = exports[v] else: globals[v] = global_exports[v] - except KeyError,x: + except KeyError as x: raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x) def SConscript(self, *ls, **kw): diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index bb7b632a..e9e8b718 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -66,7 +66,7 @@ if "--debug=memoizer" in _args: except SCons.Warnings.Warning: # Some warning was thrown. Arrange for it to be displayed # or not after warnings are configured. - import Main + from . import Main exc_type, exc_value, tb = sys.exc_info() Main.delayed_warnings.append((exc_type, exc_value)) del _args @@ -85,7 +85,7 @@ import SCons.Util import SCons.Variables import SCons.Defaults -import Main +from . import Main main = Main.main @@ -128,7 +128,7 @@ GetBuildFailures = Main.GetBuildFailures #repositories = Main.repositories # -import SConscript +from . import SConscript _SConscript = SConscript call_stack = _SConscript.call_stack @@ -364,7 +364,7 @@ GlobalDefaultBuilders = [ ] for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders: - exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name)) + exec ("%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))) del name # There are a handful of variables that used to live in the diff --git a/src/engine/SCons/Subst.py b/src/engine/SCons/Subst.py index 318d7d97..43f2e1fd 100644 --- a/src/engine/SCons/Subst.py +++ b/src/engine/SCons/Subst.py @@ -446,7 +446,7 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={ s = eval(key, self.gvars, lvars) except KeyboardInterrupt: raise - except Exception, e: + except Exception as e: if e.__class__ in AllowableExceptions: return '' raise_exception(e, lvars['TARGETS'], s) @@ -661,7 +661,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv s = eval(key, self.gvars, lvars) except KeyboardInterrupt: raise - except Exception, e: + except Exception as e: if e.__class__ in AllowableExceptions: return raise_exception(e, lvars['TARGETS'], s) diff --git a/src/engine/SCons/SubstTests.py b/src/engine/SCons/SubstTests.py index 6f2eb3fe..2b93e885 100644 --- a/src/engine/SCons/SubstTests.py +++ b/src/engine/SCons/SubstTests.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -243,14 +244,14 @@ class SubstTestCase(unittest.TestCase): expect = convert(expect) try: result = function(input, env, **kwargs) - except Exception, e: + except Exception as e: fmt = " input %s generated %s (%s)" - print fmt % (repr(input), e.__class__.__name__, repr(e)) + print(fmt % (repr(input), e.__class__.__name__, repr(e))) failed = failed + 1 else: if result != expect: - if failed == 0: print - print " input %s => %s did not match %s" % (repr(input), repr(result), repr(expect)) + if failed == 0: print() + print(" input %s => %s did not match %s" % (repr(input), repr(result), repr(expect))) failed = failed + 1 del cases[:2] fmt = "%d %s() cases failed" @@ -462,18 +463,18 @@ class scons_subst_TestCase(SubstTestCase): input, eraw, ecmd, esig = subst_cases[:4] result = scons_subst(input, env, mode=SUBST_RAW, gvars=gvars) if result != eraw: - if failed == 0: print - print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw)) + if failed == 0: print() + print(" input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))) failed = failed + 1 result = scons_subst(input, env, mode=SUBST_CMD, gvars=gvars) if result != ecmd: - if failed == 0: print - print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd)) + if failed == 0: print() + print(" input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))) failed = failed + 1 result = scons_subst(input, env, mode=SUBST_SIG, gvars=gvars) if result != esig: - if failed == 0: print - print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig)) + if failed == 0: print() + print(" input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))) failed = failed + 1 del subst_cases[:4] assert failed == 0, "%d subst() mode cases failed" % failed @@ -516,7 +517,7 @@ class scons_subst_TestCase(SubstTestCase): class Foo(object): pass scons_subst('${foo.bar}', env, gvars={'foo':Foo()}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = [ "AttributeError `bar' trying to evaluate `${foo.bar}'", "AttributeError `Foo instance has no attribute 'bar'' trying to evaluate `${foo.bar}'", @@ -532,7 +533,7 @@ class scons_subst_TestCase(SubstTestCase): env = DummyEnv(self.loc) try: scons_subst('$foo.bar.3.0', env) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = [ # Python 2.3, 2.4 "SyntaxError `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'", @@ -548,7 +549,7 @@ class scons_subst_TestCase(SubstTestCase): env = DummyEnv(self.loc) try: scons_subst("${NONE[2]}", env, gvars={'NONE':None}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = [ # Python 2.3, 2.4 "TypeError `unsubscriptable object' trying to evaluate `${NONE[2]}'", @@ -567,7 +568,7 @@ class scons_subst_TestCase(SubstTestCase): def func(a, b, c): pass scons_subst("${func(1)}", env, gvars={'func':func}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = [ # Python 2.3, 2.4, 2.5 "TypeError `func() takes exactly 3 arguments (1 given)' trying to evaluate `${func(1)}'" @@ -948,18 +949,18 @@ class scons_subst_list_TestCase(SubstTestCase): input, eraw, ecmd, esig = subst_list_cases[:4] result = scons_subst_list(input, env, mode=SUBST_RAW, gvars=gvars) if result != eraw: - if failed == 0: print - print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw)) + if failed == 0: print() + print(" input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))) failed = failed + 1 result = scons_subst_list(input, env, mode=SUBST_CMD, gvars=gvars) if result != ecmd: - if failed == 0: print - print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd)) + if failed == 0: print() + print(" input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))) failed = failed + 1 result = scons_subst_list(input, env, mode=SUBST_SIG, gvars=gvars) if result != esig: - if failed == 0: print - print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig)) + if failed == 0: print() + print(" input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))) failed = failed + 1 del subst_list_cases[:4] assert failed == 0, "%d subst() mode cases failed" % failed @@ -971,7 +972,7 @@ class scons_subst_list_TestCase(SubstTestCase): class Foo(object): pass scons_subst_list('${foo.bar}', env, gvars={'foo':Foo()}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = [ "AttributeError `bar' trying to evaluate `${foo.bar}'", "AttributeError `Foo instance has no attribute 'bar'' trying to evaluate `${foo.bar}'", @@ -987,7 +988,7 @@ class scons_subst_list_TestCase(SubstTestCase): env = DummyEnv() try: scons_subst_list('$foo.bar.3.0', env) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = [ "SyntaxError `invalid syntax' trying to evaluate `$foo.bar.3.0'", "SyntaxError `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'", @@ -1095,8 +1096,8 @@ class scons_subst_once_TestCase(unittest.TestCase): input, key, expect = cases[:3] result = scons_subst_once(input, env, key) if result != expect: - if failed == 0: print - print " input %s (%s) => %s did not match %s" % (repr(input), repr(key), repr(result), repr(expect)) + if failed == 0: print() + print(" input %s (%s) => %s did not match %s" % (repr(input), repr(key), repr(result), repr(expect))) failed = failed + 1 del cases[:3] assert failed == 0, "%d subst() cases failed" % failed diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 5de1cda5..00147b2c 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -19,6 +19,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __doc__ = """ Generic Taskmaster module for the SCons build engine. @@ -107,7 +108,7 @@ fmt = "%(considered)3d "\ def dump_stats(): for n in sorted(StatsNodes, key=lambda a: str(a)): - print (fmt % n.stats.__dict__) + str(n) + print((fmt % n.stats.__dict__) + str(n)) @@ -191,13 +192,13 @@ class Task(object): executor.prepare() for t in executor.get_action_targets(): if print_prepare: - print "Preparing target %s..."%t + print("Preparing target %s..."%t) for s in t.side_effects: - print "...with side-effect %s..."%s + print("...with side-effect %s..."%s) t.prepare() for s in t.side_effects: if print_prepare: - print "...Preparing side-effect %s..."%s + print("...Preparing side-effect %s..."%s) s.prepare() def get_target(self): @@ -256,7 +257,7 @@ class Task(object): raise except SCons.Errors.BuildError: raise - except Exception, e: + except Exception as e: buildError = SCons.Errors.convert_to_BuildError(e) buildError.node = self.targets[0] buildError.exc_info = sys.exc_info() @@ -402,7 +403,7 @@ class Task(object): t.disambiguate().make_ready() is_up_to_date = not t.has_builder() or \ (not t.always_build and t.is_up_to_date()) - except EnvironmentError, e: + except EnvironmentError as e: raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename) if not is_up_to_date: @@ -531,13 +532,9 @@ class Task(object): Raises a pending exception that was recorded while getting a Task ready for execution. """ - exc = self.exc_info()[:] - try: - exc_type, exc_value, exc_traceback = exc - except ValueError: - exc_type, exc_value = exc - exc_traceback = None - raise exc_type, exc_value, exc_traceback + + import six + six.reraise(*self.exc_info()) class AlwaysTask(Task): def needs_execute(self): @@ -810,7 +807,7 @@ class Taskmaster(object): self.ready_exc = (SCons.Errors.ExplicitExit, e) if T: T.write(self.trace_message(' SystemExit')) return node - except Exception, e: + except Exception as e: # We had a problem just trying to figure out the # children (like a child couldn't be linked in to a # VariantDir, or a Scanner threw something). Arrange to diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index 1d819924..e795f5c1 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -697,7 +697,7 @@ class TaskmasterTestCase(unittest.TestCase): tm = SCons.Taskmaster.Taskmaster([n3]) try: t = tm.next_task() - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == "Dependency cycle: n3 -> n1 -> n2 -> n3", str(e) else: assert 'Did not catch expected UserError' @@ -851,7 +851,7 @@ class TaskmasterTestCase(unittest.TestCase): exc_caught = None try: t.prepare() - except MyException, e: + except MyException as e: exc_caught = 1 except: pass @@ -904,7 +904,7 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() try: t.prepare() - except Exception, e: + except Exception as e: assert str(e) == "Executor.prepare() exception", e else: raise AssertionError("did not catch expected exception") @@ -958,7 +958,7 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() try: t.execute() - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: assert e.node == n4, e.node assert e.errstr == "OtherError : ", e.errstr assert len(e.exc_info) == 3, e.exc_info diff --git a/src/engine/SCons/Tool/386asm.py b/src/engine/SCons/Tool/386asm.py index 8acc55f4..51738ebc 100644 --- a/src/engine/SCons/Tool/386asm.py +++ b/src/engine/SCons/Tool/386asm.py @@ -37,7 +37,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" from SCons.Tool.PharLapCommon import addPharLapPaths import SCons.Util -as_module = __import__('as', globals(), locals(), []) +as_module = __import__('as', globals(), locals(), [], 1) def generate(env): """Add Builders and construction variables for ar to an Environment.""" diff --git a/src/engine/SCons/Tool/FortranCommon.py b/src/engine/SCons/Tool/FortranCommon.py index 4c5730cf..088c717c 100644 --- a/src/engine/SCons/Tool/FortranCommon.py +++ b/src/engine/SCons/Tool/FortranCommon.py @@ -26,6 +26,7 @@ Stuff for processing Fortran, common to all fortran dialects. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -61,7 +62,7 @@ def isfortran(env, source): def _fortranEmitter(target, source, env): node = source[0].rfile() if not node.exists() and not node.is_derived(): - print "Could not locate " + str(node.name) + print("Could not locate " + str(node.name)) return ([], []) mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" cre = re.compile(mod_regex,re.M) @@ -167,7 +168,7 @@ def add_fortran_to_env(env): except KeyError: FortranSuffixes = ['.f', '.for', '.ftn'] - #print "Adding %s to fortran suffixes" % FortranSuffixes + #print("Adding %s to fortran suffixes" % FortranSuffixes) try: FortranPPSuffixes = env['FORTRANPPFILESUFFIXES'] except KeyError: @@ -191,7 +192,7 @@ def add_f77_to_env(env): except KeyError: F77Suffixes = ['.f77'] - #print "Adding %s to f77 suffixes" % F77Suffixes + #print("Adding %s to f77 suffixes" % F77Suffixes) try: F77PPSuffixes = env['F77PPFILESUFFIXES'] except KeyError: diff --git a/src/engine/SCons/Tool/GettextCommon.py b/src/engine/SCons/Tool/GettextCommon.py index cd2f306c..ea81f0d1 100644 --- a/src/engine/SCons/Tool/GettextCommon.py +++ b/src/engine/SCons/Tool/GettextCommon.py @@ -196,7 +196,7 @@ class _POFileBuilder(BuilderBase): import SCons.Util import SCons.Node linguas_files = None - if env.has_key('LINGUAS_FILE') and env['LINGUAS_FILE']: + 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). @@ -341,7 +341,7 @@ class RPaths(object): def _init_po_files(target, source, env): """ Action function for `POInit` builder. """ nop = lambda target, source, env : 0 - if env.has_key('POAUTOINIT'): + if 'POAUTOINIT' in env: autoinit = env['POAUTOINIT'] else: autoinit = False @@ -365,7 +365,7 @@ def _init_po_files(target, source, env): ############################################################################# def _detect_xgettext(env): """ Detects *xgettext(1)* binary """ - if env.has_key('XGETTEXT'): + if 'XGETTEXT' in env: return env['XGETTEXT'] xgettext = env.Detect('xgettext'); if xgettext: @@ -380,7 +380,7 @@ def _xgettext_exists(env): ############################################################################# def _detect_msginit(env): """ Detects *msginit(1)* program. """ - if env.has_key('MSGINIT'): + if 'MSGINIT' in env: return env['MSGINIT'] msginit = env.Detect('msginit'); if msginit: @@ -395,7 +395,7 @@ def _msginit_exists(env): ############################################################################# def _detect_msgmerge(env): """ Detects *msgmerge(1)* program. """ - if env.has_key('MSGMERGE'): + if 'MSGMERGE' in env: return env['MSGMERGE'] msgmerge = env.Detect('msgmerge'); if msgmerge: @@ -410,7 +410,7 @@ def _msgmerge_exists(env): ############################################################################# def _detect_msgfmt(env): """ Detects *msgmfmt(1)* program. """ - if env.has_key('MSGFMT'): + if 'MSGFMT' in env: return env['MSGFMT'] msgfmt = env.Detect('msgfmt'); if msgfmt: diff --git a/src/engine/SCons/Tool/MSCommon/common.py b/src/engine/SCons/Tool/MSCommon/common.py index ccfe7396..4a913104 100644 --- a/src/engine/SCons/Tool/MSCommon/common.py +++ b/src/engine/SCons/Tool/MSCommon/common.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -38,7 +39,7 @@ import SCons.Util logfile = os.environ.get('SCONS_MSCOMMON_DEBUG') if logfile == '-': def debug(x): - print x + print(x) elif logfile: try: import logging @@ -114,11 +115,11 @@ def normalize_env(env, keys, force=False): normenv = {} if env: for k in env.keys(): - normenv[k] = copy.deepcopy(env[k]).encode('mbcs') + normenv[k] = copy.deepcopy(env[k]) for k in keys: if k in os.environ and (force or not k in normenv): - normenv[k] = os.environ[k].encode('mbcs') + normenv[k] = os.environ[k] # This shouldn't be necessary, since the default environment should include system32, # but keep this here to be safe, since it's needed to find reg.exe which the MSVC @@ -211,7 +212,6 @@ def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")): for p in plist: # Do not add empty paths (when a var ends with ;) if p: - p = p.encode('mbcs') # XXX: For some reason, VC98 .bat file adds "" around the PATH # values, and it screws up the environment later, so we strip # it. diff --git a/src/engine/SCons/Tool/MSCommon/netframework.py b/src/engine/SCons/Tool/MSCommon/netframework.py index 6124e5b4..1a6478f6 100644 --- a/src/engine/SCons/Tool/MSCommon/netframework.py +++ b/src/engine/SCons/Tool/MSCommon/netframework.py @@ -28,7 +28,7 @@ __doc__ = """ import os import re -from common import read_reg, debug +from .common import read_reg, debug # Original value recorded by dcournapeau _FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot' @@ -40,7 +40,7 @@ def find_framework_root(): try: froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT) debug("Found framework install root in registry: %s" % froot) - except WindowsError, e: + except WindowsError as e: debug("Could not read reg key %s" % _FRAMEWORKDIR_HKEY_ROOT) return None diff --git a/src/engine/SCons/Tool/MSCommon/sdk.py b/src/engine/SCons/Tool/MSCommon/sdk.py index 2bf5eef8..f71035b5 100644 --- a/src/engine/SCons/Tool/MSCommon/sdk.py +++ b/src/engine/SCons/Tool/MSCommon/sdk.py @@ -33,7 +33,7 @@ import os import SCons.Errors import SCons.Util -import common +from . import common debug = common.debug @@ -80,7 +80,7 @@ class SDKDefinition(object): try: sdk_dir = common.read_reg(hkey) - except WindowsError, e: + except WindowsError as e: debug('find_sdk_dir(): no SDK registry key %s' % repr(hkey)) return None @@ -299,7 +299,7 @@ def get_cur_sdk_dir_from_reg(): try: val = common.read_reg(_CURINSTALLED_SDK_HKEY_ROOT) debug("Found current sdk dir in registry: %s" % val) - except WindowsError, e: + except WindowsError as e: debug("Did not find current sdk in registry") return None @@ -350,7 +350,7 @@ def mssdk_setup_env(env): debug('sdk.py:mssdk_setup_env thinks msvs_version is None') return msvs_version = env.subst(msvs_version) - import vs + from . import vs msvs = vs.get_vs_by_version(msvs_version) debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs) if not msvs: diff --git a/src/engine/SCons/Tool/MSCommon/vc.py b/src/engine/SCons/Tool/MSCommon/vc.py index 68ebbd3a..dbfada71 100644 --- a/src/engine/SCons/Tool/MSCommon/vc.py +++ b/src/engine/SCons/Tool/MSCommon/vc.py @@ -42,11 +42,11 @@ from string import digits as string_digits import SCons.Warnings -import common +from . import common debug = common.debug -import sdk +from . import sdk get_installed_sdks = sdk.get_installed_sdks @@ -120,14 +120,14 @@ def get_host_target(env): try: host = _ARCH_TO_CANONICAL[host_platform.lower()] - except KeyError, e: + except KeyError as e: msg = "Unrecognized host architecture %s" raise ValueError(msg % repr(host_platform)) try: target = _ARCH_TO_CANONICAL[target_platform.lower()] - except KeyError, e: - all_archs = str(_ARCH_TO_CANONICAL.keys()) + except KeyError as e: + all_archs = str(list(_ARCH_TO_CANONICAL.keys())) raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs)) return (host, target,req_target_platform) @@ -175,7 +175,7 @@ def msvc_version_to_maj_min(msvc_version): maj = int(t[0]) min = int(t[1]) return maj, min - except ValueError, e: + except ValueError as e: raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) def is_host_target_supported(host_target, msvc_version): @@ -224,7 +224,7 @@ def find_vc_pdir(msvc_version): key = root + key try: comps = common.read_reg(key) - except WindowsError, e: + except WindowsError as e: debug('find_vc_dir(): no VC registry key %s' % repr(key)) else: debug('find_vc_dir(): found VC in registry: %s' % comps) @@ -297,7 +297,7 @@ def get_installed_vcs(): installed_versions.append(ver) else: debug('find_vc_pdir return None for ver %s' % ver) - except VisualCException, e: + except VisualCException as e: debug('did not find VC %s: caught exception %s' % (ver, str(e))) return installed_versions @@ -401,7 +401,7 @@ def msvc_find_valid_batch_script(env,version): try: (vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp) debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script)) - except VisualCException, e: + except VisualCException as e: msg = str(e) debug('Caught exception while looking for batch file (%s)' % msg) warn_msg = "VC version %s not installed. " + \ @@ -416,7 +416,7 @@ def msvc_find_valid_batch_script(env,version): if vc_script: try: d = script_env(vc_script, args=arg) - except BatchFileExecutionError, e: + except BatchFileExecutionError as e: debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e)) vc_script=None continue @@ -424,7 +424,7 @@ def msvc_find_valid_batch_script(env,version): debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script)) try: d = script_env(sdk_script,args=[]) - except BatchFileExecutionError,e: + except BatchFileExecutionError as e: debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e)) continue elif not vc_script and not sdk_script: diff --git a/src/engine/SCons/Tool/MSCommon/vs.py b/src/engine/SCons/Tool/MSCommon/vs.py index 2ec403b6..68e108a8 100644 --- a/src/engine/SCons/Tool/MSCommon/vs.py +++ b/src/engine/SCons/Tool/MSCommon/vs.py @@ -31,7 +31,7 @@ import os import SCons.Errors import SCons.Util -from common import debug, \ +from .common import debug, \ get_output, \ is_win64, \ normalize_env, \ @@ -85,7 +85,7 @@ class VisualStudio(object): key = root + key try: comps = read_reg(key) - except WindowsError, e: + except WindowsError as e: debug('find_vs_dir_by_reg(): no VS registry key %s' % repr(key)) else: debug('find_vs_dir_by_reg(): found VS in registry: %s' % comps) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index c09f8e48..d30159d9 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -34,6 +34,7 @@ tool definition. # 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. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -113,8 +114,8 @@ class Tool(object): finally: if file: file.close() - except ImportError, e: - if str(e)!="No module named %s"%self.name: + except ImportError as e: + if not str(e).startswith ("No module"): raise SCons.Errors.EnvironmentError(e) try: import zipimport @@ -125,7 +126,7 @@ class Tool(object): try: importer = zipimport.zipimporter(aPath) return importer.load_module(self.name) - except ImportError, e: + except ImportError as e: pass finally: sys.path = oldpythonpath @@ -143,8 +144,8 @@ class Tool(object): if file: file.close() return module - except ImportError, e: - if str(e)!="No module named %s"%self.name: + except ImportError as e: + if not str(e).startswith("No module"): raise SCons.Errors.EnvironmentError(e) try: import zipimport @@ -152,10 +153,10 @@ class Tool(object): module = importer.load_module(full_name) setattr(SCons.Tool, self.name, module) return module - except ImportError, e: + except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.EnvironmentError(m) - except ImportError, e: + except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.EnvironmentError(m) @@ -254,7 +255,7 @@ def VersionShLibLinkNames(version, libname, env): suffix_re = re.escape('.' + version + shlib_suffix) linkname = re.sub(suffix_re, shlib_suffix, libname) if Verbose: - print "VersionShLibLinkNames: linkname = ",linkname + print("VersionShLibLinkNames: linkname = ",linkname) linknames.append(linkname) elif platform == 'posix': if sys.platform.startswith('openbsd'): @@ -266,7 +267,7 @@ def VersionShLibLinkNames(version, libname, env): # First linkname has no version number linkname = re.sub(suffix_re, shlib_suffix, libname) if Verbose: - print "VersionShLibLinkNames: linkname = ",linkname + print("VersionShLibLinkNames: linkname = ",linkname) linknames.append(linkname) versionparts = version.split('.') major_name = linkname + "." + versionparts[0] @@ -275,7 +276,7 @@ def VersionShLibLinkNames(version, libname, env): #for linkname in [major_name, minor_name]: for linkname in [major_name, ]: if Verbose: - print "VersionShLibLinkNames: linkname ",linkname, ", target ",libname + print("VersionShLibLinkNames: linkname ",linkname, ", target ",libname) linknames.append(linkname) # note: no Windows case here (win32 or cygwin); # MSVC doesn't support this type of versioned shared libs. @@ -298,10 +299,10 @@ symlinks for the platform we are on""" shlib_suffix = env.subst('$SHLIBSUFFIX') shlink_flags = SCons.Util.CLVar(env.subst('$SHLINKFLAGS')) if Verbose: - print "VersionShLib: libname = ",libname - print "VersionShLib: platform = ",platform - print "VersionShLib: shlib_suffix = ",shlib_suffix - print "VersionShLib: target = ",str(target[0]) + print("VersionShLib: libname = ",libname) + print("VersionShLib: platform = ",platform) + print("VersionShLib: shlib_suffix = ",shlib_suffix) + print("VersionShLib: target = ",str(target[0])) if version: # set the shared library link flags @@ -316,7 +317,7 @@ symlinks for the platform we are on""" soname = re.sub(suffix_re, shlib_suffix, libname) + '.' + major shlink_flags += [ '-Wl,-soname=%s' % soname ] if Verbose: - print " soname ",soname,", shlink_flags ",shlink_flags + print(" soname ",soname,", shlink_flags ",shlink_flags) elif platform == 'cygwin': shlink_flags += [ '-Wl,-Bsymbolic', '-Wl,--out-implib,${TARGET.base}.a' ] @@ -325,7 +326,7 @@ symlinks for the platform we are on""" '-compatibility_version', '%s' % version, '-undefined', 'dynamic_lookup' ] if Verbose: - print "VersionShLib: shlink_flags = ",shlink_flags + print("VersionShLib: shlink_flags = ",shlink_flags) envlink = env.Clone() envlink['SHLINKFLAGS'] = shlink_flags else: @@ -338,7 +339,7 @@ symlinks for the platform we are on""" libname = target[0].path linknames = VersionShLibLinkNames(version, libname, env) if Verbose: - print "VerShLib: linknames ",linknames + print("VerShLib: linknames ",linknames) # Here we just need the file name w/o path as the target of the link lib_ver = target[0].name # make symlink of adjacent names in linknames @@ -351,7 +352,7 @@ symlinks for the platform we are on""" pass os.symlink(os.path.basename(linkname),lastlinkname) if Verbose: - print "VerShLib: made sym link of %s -> %s" % (lastlinkname,linkname) + print("VerShLib: made sym link of %s -> %s" % (lastlinkname,linkname)) lastlinkname = linkname # finish chain of sym links with link to the actual library if len(linknames)>0: @@ -361,7 +362,7 @@ symlinks for the platform we are on""" pass os.symlink(lib_ver,lastlinkname) if Verbose: - print "VerShLib: made sym link of %s -> %s" % (linkname, lib_ver) + print("VerShLib: made sym link of %s -> %s" % (linkname, lib_ver)) return result # Fix http://scons.tigris.org/issues/show_bug.cgi?id=2903 : diff --git a/src/engine/SCons/Tool/aixcc.py b/src/engine/SCons/Tool/aixcc.py index 9668f799..b1da31e4 100644 --- a/src/engine/SCons/Tool/aixcc.py +++ b/src/engine/SCons/Tool/aixcc.py @@ -36,7 +36,7 @@ import os.path import SCons.Platform.aix -import cc +from . import cc packages = ['vac.C', 'ibmcxx.cmp'] diff --git a/src/engine/SCons/Tool/aixf77.py b/src/engine/SCons/Tool/aixf77.py index a667e843..21786ee0 100644 --- a/src/engine/SCons/Tool/aixf77.py +++ b/src/engine/SCons/Tool/aixf77.py @@ -36,7 +36,7 @@ import os.path #import SCons.Platform.aix -import f77 +from . import f77 # It would be good to look for the AIX F77 package the same way we're now # looking for the C and C++ packages. This should be as easy as supplying diff --git a/src/engine/SCons/Tool/aixlink.py b/src/engine/SCons/Tool/aixlink.py index 35125220..fc65afb9 100644 --- a/src/engine/SCons/Tool/aixlink.py +++ b/src/engine/SCons/Tool/aixlink.py @@ -37,8 +37,8 @@ import os.path import SCons.Util -import aixcc -import link +from . import aixcc +from . import link cplusplus = __import__('c++', globals(), locals(), []) diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py index 19390982..ba955a4e 100644 --- a/src/engine/SCons/Tool/applelink.py +++ b/src/engine/SCons/Tool/applelink.py @@ -37,7 +37,7 @@ import SCons.Util # Even though the Mac is based on the GNU toolchain, it doesn't understand # the -rpath option, so we use the "link" tool instead of "gnulink". -import link +from . import link def generate(env): """Add Builders and construction variables for applelink to an diff --git a/src/engine/SCons/Tool/cvf.py b/src/engine/SCons/Tool/cvf.py index 2a28e6a9..da2c910a 100644 --- a/src/engine/SCons/Tool/cvf.py +++ b/src/engine/SCons/Tool/cvf.py @@ -29,7 +29,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import fortran +from . import fortran compilers = ['f90'] diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py index 87716cf9..1685d7f9 100644 --- a/src/engine/SCons/Tool/cyglink.py +++ b/src/engine/SCons/Tool/cyglink.py @@ -11,7 +11,7 @@ selection method. import SCons.Action import SCons.Util -import gnulink +from . import gnulink def shlib_generator(target, source, env, for_signature): cmd = SCons.Util.CLVar(['$SHLINK']) diff --git a/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py b/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py index c0706023..e7b8cfa9 100644 --- a/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py +++ b/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/docbook.py @@ -1,5 +1,6 @@ # docbook.py: extension module # $Id: docbook.py 8353 2009-03-17 16:57:50Z mzjn $ +from __future__ import print_function import sys import string @@ -82,7 +83,7 @@ def adjustColumnWidths(ctx, nodeset): relParts.append(relPart) absParts.append(pixels) - col = col.next + col = col.__next__ # Ok, now we have the relative widths and absolute widths in # two parallel arrays. @@ -116,7 +117,7 @@ def adjustColumnWidths(ctx, nodeset): pixelWidth = convertLength(tableWidth) if pixelWidth <= absTotal: - print "Table is wider than table width" + print("Table is wider than table width") else: pixelWidth = pixelWidth - absTotal @@ -151,7 +152,7 @@ def adjustColumnWidths(ctx, nodeset): col.setProp("width", widths[count]) count = count+1 - col = col.next + col = col.__next__ return nodeset @@ -163,10 +164,10 @@ def convertLength(length): m = re.search('([+-]?[\d\.]+)(\S+)', length) if m != None and m.lastindex > 1: unit = pixelsPerInch - if unitHash.has_key(m.group(2)): + if m.group(2) in unitHash: unit = unitHash[m.group(2)] else: - print "Unrecognized length: " + m.group(2) + print("Unrecognized length: " + m.group(2)) pixels = unit * float(m.group(1)) else: diff --git a/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/xslt.py b/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/xslt.py index c712f65f..77ca0de6 100644 --- a/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/xslt.py +++ b/src/engine/SCons/Tool/docbook/docbook-xsl-1.76.1/extensions/xslt.py @@ -1,5 +1,6 @@ #!/usr/bin/python -u # $Id: xslt.py 8353 2009-03-17 16:57:50Z mzjn $ +from __future__ import print_function import sys import libxml2 @@ -18,7 +19,7 @@ try: xmlfile = sys.argv[1] xslfile = sys.argv[2] except IndexError: - print usage + print(usage) sys.exit(1) def quote(astring): @@ -38,12 +39,12 @@ try: while (sys.argv[count]): try: name, value = sys.argv[count].split("=", 2) - if params.has_key(name): - print "Warning: '%s' re-specified; replacing value" % name + if name in params: + print("Warning: '%s' re-specified; replacing value" % name) params[name] = quote(value) except ValueError: - print "Invalid parameter specification: '" + sys.argv[count] + "'" - print usage + print("Invalid parameter specification: '" + sys.argv[count] + "'") + print(usage) sys.exit(1) count = count+1 except IndexError: @@ -70,7 +71,7 @@ result = style.applyStylesheet(doc, params) if outfile: style.saveResultToFilename(outfile, result, 0) else: - print result + print(result) # Free things up style.freeStylesheet() diff --git a/src/engine/SCons/Tool/dvipdf.py b/src/engine/SCons/Tool/dvipdf.py index 7c41e9c2..374b9c58 100644 --- a/src/engine/SCons/Tool/dvipdf.py +++ b/src/engine/SCons/Tool/dvipdf.py @@ -100,7 +100,7 @@ def generate(env): if DVIPDFAction is None: DVIPDFAction = SCons.Action.Action(DviPdfFunction, strfunction = DviPdfStrFunction) - import pdf + from . import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] diff --git a/src/engine/SCons/Tool/f03.py b/src/engine/SCons/Tool/f03.py index 3aab1c04..6c309715 100644 --- a/src/engine/SCons/Tool/f03.py +++ b/src/engine/SCons/Tool/f03.py @@ -36,7 +36,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Defaults import SCons.Tool import SCons.Util -import fortran +from . import fortran from SCons.Tool.FortranCommon import add_all_to_env, add_f03_to_env compilers = ['f03'] diff --git a/src/engine/SCons/Tool/f95.py b/src/engine/SCons/Tool/f95.py index 5ce5e570..5baa31ee 100644 --- a/src/engine/SCons/Tool/f95.py +++ b/src/engine/SCons/Tool/f95.py @@ -36,7 +36,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Defaults import SCons.Tool import SCons.Util -import fortran +from . import fortran from SCons.Tool.FortranCommon import add_all_to_env, add_f95_to_env compilers = ['f95'] diff --git a/src/engine/SCons/Tool/filesystem.py b/src/engine/SCons/Tool/filesystem.py index 31c8abc0..3b8ee4c8 100644 --- a/src/engine/SCons/Tool/filesystem.py +++ b/src/engine/SCons/Tool/filesystem.py @@ -66,7 +66,7 @@ def generate(env): try: env['BUILDERS']['CopyTo'] env['BUILDERS']['CopyAs'] - except KeyError, e: + except KeyError as e: global copyToBuilder if copyToBuilder is None: copyToBuilder = SCons.Builder.Builder( diff --git a/src/engine/SCons/Tool/g++.py b/src/engine/SCons/Tool/g++.py index e4da5fe2..0e1c181a 100644 --- a/src/engine/SCons/Tool/g++.py +++ b/src/engine/SCons/Tool/g++.py @@ -40,8 +40,7 @@ import subprocess import SCons.Tool import SCons.Util -cplusplus = __import__('c++', globals(), locals(), []) - +cplusplus = __import__(__package__+'.c++', globals(), locals(), ['*']) compilers = ['g++'] def generate(env): @@ -75,7 +74,7 @@ def generate(env): #line = pipe.stdout.read().strip() #if line: # env['CXXVERSION'] = line - line = pipe.stdout.readline() + line = SCons.Util.to_str (pipe.stdout.readline()) match = re.search(r'[0-9]+(\.[0-9]+)+', line) if match: env['CXXVERSION'] = match.group(0) diff --git a/src/engine/SCons/Tool/gas.py b/src/engine/SCons/Tool/gas.py index 28f84db7..d01bd60c 100644 --- a/src/engine/SCons/Tool/gas.py +++ b/src/engine/SCons/Tool/gas.py @@ -33,7 +33,10 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -as_module = __import__('as', globals(), locals(), []) +try: + as_module = __import__('as', globals(), locals(), []) +except: + as_module = __import__(__package__+'.as', globals(), locals(), ['*']) assemblers = ['as', 'gas'] diff --git a/src/engine/SCons/Tool/gcc.py b/src/engine/SCons/Tool/gcc.py index 71f60a3e..72f9bfd6 100644 --- a/src/engine/SCons/Tool/gcc.py +++ b/src/engine/SCons/Tool/gcc.py @@ -33,7 +33,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import cc +from . import cc import os import re import subprocess @@ -65,7 +65,7 @@ def generate(env): #line = pipe.stdout.read().strip() #if line: # env['CCVERSION'] = line - line = pipe.stdout.readline() + line = SCons.Util.to_str (pipe.stdout.readline()) match = re.search(r'[0-9]+(\.[0-9]+)+', line) if match: env['CCVERSION'] = match.group(0) diff --git a/src/engine/SCons/Tool/gfortran.py b/src/engine/SCons/Tool/gfortran.py index 4f3e7e46..7b05e683 100644 --- a/src/engine/SCons/Tool/gfortran.py +++ b/src/engine/SCons/Tool/gfortran.py @@ -36,7 +36,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -import fortran +from . import fortran def generate(env): """Add Builders and construction variables for gfortran to an diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py index bf71270f..ea8d7bd1 100644 --- a/src/engine/SCons/Tool/gnulink.py +++ b/src/engine/SCons/Tool/gnulink.py @@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -import link +from . import link linkers = ['g++', 'gcc'] diff --git a/src/engine/SCons/Tool/gs.py b/src/engine/SCons/Tool/gs.py index 6e31ee27..443ace26 100644 --- a/src/engine/SCons/Tool/gs.py +++ b/src/engine/SCons/Tool/gs.py @@ -62,12 +62,12 @@ def generate(env): if GhostscriptAction is None: GhostscriptAction = SCons.Action.Action('$GSCOM', '$GSCOMSTR') - import pdf + from . import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] bld.add_action('.ps', GhostscriptAction) - except ImportError, e: + except ImportError as e: pass gsbuilder = SCons.Builder.Builder(action = SCons.Action.Action('$GSCOM', '$GSCOMSTR')) diff --git a/src/engine/SCons/Tool/hpcc.py b/src/engine/SCons/Tool/hpcc.py index 30f49648..51d2e380 100644 --- a/src/engine/SCons/Tool/hpcc.py +++ b/src/engine/SCons/Tool/hpcc.py @@ -34,7 +34,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -import cc +from . import cc def generate(env): """Add Builders and construction variables for aCC & cc to an Environment.""" diff --git a/src/engine/SCons/Tool/hplink.py b/src/engine/SCons/Tool/hplink.py index 17dbe057..10ef30ba 100644 --- a/src/engine/SCons/Tool/hplink.py +++ b/src/engine/SCons/Tool/hplink.py @@ -37,7 +37,7 @@ import os.path import SCons.Util -import link +from . import link ccLinker = None diff --git a/src/engine/SCons/Tool/icc.py b/src/engine/SCons/Tool/icc.py index db156422..11ea075f 100644 --- a/src/engine/SCons/Tool/icc.py +++ b/src/engine/SCons/Tool/icc.py @@ -33,7 +33,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import cc +from . import cc def generate(env): """Add Builders and construction variables for the OS/2 to an Environment.""" diff --git a/src/engine/SCons/Tool/ifl.py b/src/engine/SCons/Tool/ifl.py index 30b3672e..865d2baa 100644 --- a/src/engine/SCons/Tool/ifl.py +++ b/src/engine/SCons/Tool/ifl.py @@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Defaults from SCons.Scanner.Fortran import FortranScan -from FortranCommon import add_all_to_env +from .FortranCommon import add_all_to_env def generate(env): """Add Builders and construction variables for ifl to an Environment.""" diff --git a/src/engine/SCons/Tool/ifort.py b/src/engine/SCons/Tool/ifort.py index 4b2fd658..638bd12d 100644 --- a/src/engine/SCons/Tool/ifort.py +++ b/src/engine/SCons/Tool/ifort.py @@ -36,7 +36,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Defaults from SCons.Scanner.Fortran import FortranScan -from FortranCommon import add_all_to_env +from .FortranCommon import add_all_to_env def generate(env): """Add Builders and construction variables for ifort to an Environment.""" diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py index 0c81d05d..0d75765f 100644 --- a/src/engine/SCons/Tool/install.py +++ b/src/engine/SCons/Tool/install.py @@ -29,6 +29,7 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -82,21 +83,21 @@ def scons_copytree(src, dst, symlinks=False): else: shutil.copy2(srcname, dstname) # XXX What about devices, sockets etc.? - except (IOError, os.error), why: + except (IOError, os.error) as why: errors.append((srcname, dstname, str(why))) # catch the CopytreeError from the recursive copytree so that we can # continue with other files - except CopytreeError, err: + except CopytreeError as err: errors.extend(err.args[0]) try: shutil.copystat(src, dst) except WindowsError: # can't copy file access times on Windows pass - except OSError, why: + except OSError as why: errors.extend((src, dst, str(why))) if errors: - raise CopytreeError, errors + raise CopytreeError(errors) # @@ -174,7 +175,7 @@ def versionedLibVersion(dest, env): version_File = version_re.findall(versioned_re.findall(libname)[-1])[-1] if Verbose: - print "install: version_File ", version_File + print("install: version_File ", version_File) # result is False if we did not find a versioned shared library name, so return and empty list if not result: return (None, libname, install_dir) @@ -188,7 +189,7 @@ def versionedLibVersion(dest, env): if version != version_File: #raise SCons.Errors.UserError("SHLIBVERSION '%s' does not match the version # '%s' in the filename" % (version, version_File) ) - print "SHLIBVERSION '%s' does not match the version # '%s' in the filename, proceeding based on file name" % (version, version_File) + print("SHLIBVERSION '%s' does not match the version # '%s' in the filename, proceeding based on file name" % (version, version_File)) version = version_File return (version, libname, install_dir) @@ -202,7 +203,7 @@ def versionedLibLinks(dest, source, env): # libname includes the version number if one was given linknames = SCons.Tool.VersionShLibLinkNames(version,libname,env) if Verbose: - print "versionedLibLinks: linknames ",linknames + print("versionedLibLinks: linknames ",linknames) # Here we just need the file name w/o path as the target of the link lib_ver = libname # make symlink of adjacent names in linknames @@ -210,7 +211,7 @@ def versionedLibLinks(dest, source, env): linkname = linknames[count] fulllinkname = os.path.join(install_dir, linkname) if Verbose: - print "full link name ",fulllinkname + print("full link name ",fulllinkname) if count > 0: try: os.remove(lastlinkname) @@ -218,7 +219,7 @@ def versionedLibLinks(dest, source, env): pass os.symlink(os.path.basename(fulllinkname),lastlinkname) if Verbose: - print "versionedLibLinks: made sym link of %s -> %s" % (lastlinkname,os.path.basename(fulllinkname)) + print("versionedLibLinks: made sym link of %s -> %s" % (lastlinkname,os.path.basename(fulllinkname))) lastlinkname = fulllinkname # finish chain of sym links with link to the actual library if len(linknames)>0: @@ -228,7 +229,7 @@ def versionedLibLinks(dest, source, env): pass os.symlink(lib_ver,lastlinkname) if Verbose: - print "versionedLibLinks: made sym link of %s -> %s" % (lib_ver,lastlinkname) + print("versionedLibLinks: made sym link of %s -> %s" % (lib_ver,lastlinkname)) return def installFunc(target, source, env): @@ -298,7 +299,7 @@ def add_versioned_targets_to_INSTALLED_FILES(target, source, env): Verbose = False _INSTALLED_FILES.extend(target) if Verbose: - print "ver lib emitter ",repr(target) + print("ver lib emitter ",repr(target)) # see if we have a versioned shared library, if so generate side effects version, libname, install_dir = versionedLibVersion(target[0].path, env) @@ -307,13 +308,13 @@ def add_versioned_targets_to_INSTALLED_FILES(target, source, env): linknames = SCons.Tool.VersionShLibLinkNames(version,libname,env) for linkname in linknames: if Verbose: - print "make side effect of %s" % os.path.join(install_dir, linkname) + print("make side effect of %s" % os.path.join(install_dir, linkname)) fulllinkname = os.path.join(install_dir, linkname) env.SideEffect(fulllinkname,target[0]) env.Clean(target[0],fulllinkname) _INSTALLED_FILES.append(fulllinkname) if Verbose: - print "installed list ", _INSTALLED_FILES + print("installed list ", _INSTALLED_FILES) _UNIQUE_INSTALLED_FILES = None return (target, source) diff --git a/src/engine/SCons/Tool/intelc.py b/src/engine/SCons/Tool/intelc.py index 42f8e745..da5f592a 100644 --- a/src/engine/SCons/Tool/intelc.py +++ b/src/engine/SCons/Tool/intelc.py @@ -30,7 +30,7 @@ selection method. # 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. -from __future__ import division +from __future__ import division, print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -206,17 +206,16 @@ def get_all_compiler_versions(): # Registry points to nonexistent dir. Ignore this # version. value = get_intel_registry_value('ProductDir', subkey, 'IA32') - except MissingRegistryError, e: + except MissingRegistryError as e: # Registry key is left dangling (potentially # after uninstalling). - print \ - "scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \ + print("scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \ "scons: *** It seems that the compiler was uninstalled and that the registry\n" \ - "scons: *** was not cleaned up properly.\n" % subkey + "scons: *** was not cleaned up properly.\n" % subkey) else: - print "scons: *** Ignoring "+str(value) + print("scons: *** Ignoring "+str(value)) i = i + 1 except EnvironmentError: @@ -424,8 +423,8 @@ def generate(env, version=None, abi=None, topdir=None, verbose=0): bindir="bin" libdir="lib" if verbose: - print "Intel C compiler: using version %s (%g), abi %s, in '%s/%s'"%\ - (repr(version), linux_ver_normalize(version),abi,topdir,bindir) + print("Intel C compiler: using version %s (%g), abi %s, in '%s/%s'"%\ + (repr(version), linux_ver_normalize(version),abi,topdir,bindir)) if is_linux: # Show the actual compiler version by running the compiler. os.system('%s/%s/icc --version'%(topdir,bindir)) diff --git a/src/engine/SCons/Tool/latex.py b/src/engine/SCons/Tool/latex.py index 1c71743a..f30356b2 100644 --- a/src/engine/SCons/Tool/latex.py +++ b/src/engine/SCons/Tool/latex.py @@ -55,10 +55,10 @@ def generate(env): env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) - import dvi + from . import dvi dvi.generate(env) - import pdf + from . import pdf pdf.generate(env) bld = env['BUILDERS']['DVI'] diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py index 3f20fe0e..c7c67907 100644 --- a/src/engine/SCons/Tool/link.py +++ b/src/engine/SCons/Tool/link.py @@ -30,6 +30,7 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -42,7 +43,7 @@ import SCons.Warnings from SCons.Tool.FortranCommon import isfortran -cplusplus = __import__('c++', globals(), locals(), []) +cplusplus = __import__(__package__+'.c++', globals(), locals(), ['*']) issued_mixed_link_warning = False @@ -81,7 +82,7 @@ def shlib_emitter(target, source, env): env.SideEffect(name, target[0]) env.Clean(target[0], name) if Verbose: - print "shlib_emitter: add side effect - ",name + print("shlib_emitter: add side effect - ",name) except KeyError: version = None return (target, source) @@ -104,16 +105,16 @@ def shlib_emitter_names(target, source, env): # generate library name with the version number version_name = target[0].name + '.' + version if Verbose: - print "shlib_emitter_names: target is ", version_name - print "shlib_emitter_names: side effect: ", name + print("shlib_emitter_names: target is ", version_name) + print("shlib_emitter_names: side effect: ", name) # add version_name to list of names to be a Side effect version_names.append(version_name) if Verbose: - print "shlib_emitter_names: versionparts ",versionparts + print("shlib_emitter_names: versionparts ",versionparts) for ver in versionparts[0:-1]: name = name + '.' + ver if Verbose: - print "shlib_emitter_names: side effect: ", name + print("shlib_emitter_names: side effect: ", name) # add name to list of names to be a Side effect version_names.append(name) elif platform == 'darwin': @@ -123,8 +124,8 @@ def shlib_emitter_names(target, source, env): suffix_re = re.escape(shlib_suffix) version_name = re.sub(suffix_re, '.' + version + shlib_suffix, name) if Verbose: - print "shlib_emitter_names: target is ", version_name - print "shlib_emitter_names: side effect: ", name + print("shlib_emitter_names: target is ", version_name) + print("shlib_emitter_names: side effect: ", name) # add version_name to list of names to be a Side effect version_names.append(version_name) elif platform == 'cygwin': @@ -134,8 +135,8 @@ def shlib_emitter_names(target, source, env): suffix_re = re.escape(shlib_suffix) version_name = re.sub(suffix_re, '-' + re.sub('\.', '-', version) + shlib_suffix, name) if Verbose: - print "shlib_emitter_names: target is ", version_name - print "shlib_emitter_names: side effect: ", name + print("shlib_emitter_names: target is ", version_name) + print("shlib_emitter_names: side effect: ", name) # add version_name to list of names to be a Side effect version_names.append(version_name) diff --git a/src/engine/SCons/Tool/midl.py b/src/engine/SCons/Tool/midl.py index 64b927a0..7a59e334 100644 --- a/src/engine/SCons/Tool/midl.py +++ b/src/engine/SCons/Tool/midl.py @@ -39,7 +39,7 @@ import SCons.Defaults import SCons.Scanner.IDL import SCons.Util -from MSCommon import msvc_exists +from .MSCommon import msvc_exists def midl_emitter(target, source, env): """Produces a list of outputs from the MIDL compiler""" diff --git a/src/engine/SCons/Tool/msgfmt.py b/src/engine/SCons/Tool/msgfmt.py index 352ba775..4fe6afd2 100644 --- a/src/engine/SCons/Tool/msgfmt.py +++ b/src/engine/SCons/Tool/msgfmt.py @@ -41,7 +41,7 @@ class _MOFileBuilder(BuilderBase): import SCons.Util from SCons.Tool.GettextCommon import _read_linguas_from_files linguas_files = None - if env.has_key('LINGUAS_FILE') and env['LINGUAS_FILE'] is not None: + if 'LINGUAS_FILE' in env and env['LINGUAS_FILE'] is not None: linguas_files = env['LINGUAS_FILE'] # This should prevent from endless recursion. env['LINGUAS_FILE'] = None diff --git a/src/engine/SCons/Tool/msginit.py b/src/engine/SCons/Tool/msginit.py index 5e9c0e4c..39f460d9 100644 --- a/src/engine/SCons/Tool/msginit.py +++ b/src/engine/SCons/Tool/msginit.py @@ -35,7 +35,7 @@ def _optional_no_translator_flag(env): """ Return '--no-translator' flag if we run *msginit(1)* in non-interactive mode.""" import SCons.Util - if env.has_key('POAUTOINIT'): + if 'POAUTOINIT' in env: autoinit = env['POAUTOINIT'] else: autoinit = False @@ -66,7 +66,7 @@ def _POInitBuilderWrapper(env, target=None, source=_null, **kw): if source is _null: if 'POTDOMAIN' in kw: domain = kw['POTDOMAIN'] - elif env.has_key('POTDOMAIN'): + elif 'POTDOMAIN' in env: domain = env['POTDOMAIN'] else: domain = 'messages' diff --git a/src/engine/SCons/Tool/msgmerge.py b/src/engine/SCons/Tool/msgmerge.py index f3710ab3..11d7b48e 100644 --- a/src/engine/SCons/Tool/msgmerge.py +++ b/src/engine/SCons/Tool/msgmerge.py @@ -58,7 +58,7 @@ def _POUpdateBuilderWrapper(env, target=None, source=_null, **kw): if source is _null: if 'POTDOMAIN' in kw: domain = kw['POTDOMAIN'] - elif env.has_key('POTDOMAIN') and env['POTDOMAIN']: + elif 'POTDOMAIN' in env and env['POTDOMAIN']: domain = env['POTDOMAIN'] else: domain = 'messages' diff --git a/src/engine/SCons/Tool/mslib.py b/src/engine/SCons/Tool/mslib.py index 8a4af57d..df8d877e 100644 --- a/src/engine/SCons/Tool/mslib.py +++ b/src/engine/SCons/Tool/mslib.py @@ -39,7 +39,7 @@ import SCons.Tool.msvs import SCons.Tool.msvc import SCons.Util -from MSCommon import msvc_exists, msvc_setup_env_once +from .MSCommon import msvc_exists, msvc_setup_env_once def generate(env): """Add Builders and construction variables for lib to an Environment.""" diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py index 40f112b6..f30c1d34 100644 --- a/src/engine/SCons/Tool/mslink.py +++ b/src/engine/SCons/Tool/mslink.py @@ -30,6 +30,7 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -44,7 +45,7 @@ import SCons.Tool.msvc import SCons.Tool.msvs import SCons.Util -from MSCommon import msvc_setup_env_once, msvc_exists +from .MSCommon import msvc_setup_env_once, msvc_exists def pdbGenerator(env, target, source, for_signature): try: @@ -183,7 +184,7 @@ def prog_emitter(target, source, env): # MSVC 11 and above need the PCH object file to be added to the link line, # otherwise you get link error LNK2011. pchobj = SCons.Util.splitext(str(env['PCH']))[0] + '.obj' - # print "prog_emitter, version %s, appending pchobj %s"%(version_num, pchobj) + # print("prog_emitter, version %s, appending pchobj %s"%(version_num, pchobj)) if pchobj not in extrasources: extrasources.append(pchobj) @@ -195,7 +196,7 @@ def RegServerFunc(target, source, env): if ret: raise SCons.Errors.UserError("Unable to register %s" % target[0]) else: - print "Registered %s sucessfully" % target[0] + print("Registered %s sucessfully" % target[0]) return ret return 0 @@ -212,10 +213,10 @@ def embedManifestDllCheck(target, source, env): if os.path.exists(manifestSrc): ret = (embedManifestDllAction) ([target[0]],None,env) if ret: - raise SCons.Errors.UserError, "Unable to embed manifest into %s" % (target[0]) + raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0])) return ret else: - print '(embed: no %s.manifest found; not embedding.)'%str(target[0]) + print('(embed: no %s.manifest found; not embedding.)'%str(target[0])) return 0 def embedManifestExeCheck(target, source, env): @@ -226,10 +227,10 @@ def embedManifestExeCheck(target, source, env): if os.path.exists(manifestSrc): ret = (embedManifestExeAction) ([target[0]],None,env) if ret: - raise SCons.Errors.UserError, "Unable to embed manifest into %s" % (target[0]) + raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0])) return ret else: - print '(embed: no %s.manifest found; not embedding.)'%str(target[0]) + print('(embed: no %s.manifest found; not embedding.)'%str(target[0])) return 0 embedManifestDllCheckAction = SCons.Action.Action(embedManifestDllCheck, None) diff --git a/src/engine/SCons/Tool/mssdk.py b/src/engine/SCons/Tool/mssdk.py index 6103f30b..f3730021 100644 --- a/src/engine/SCons/Tool/mssdk.py +++ b/src/engine/SCons/Tool/mssdk.py @@ -33,7 +33,7 @@ It will usually be imported through the generic SCons.Tool.Tool() selection method. """ -from MSCommon import mssdk_exists, \ +from .MSCommon import mssdk_exists, \ mssdk_setup_env def generate(env): diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py index d42c2570..0bc296f4 100644 --- a/src/engine/SCons/Tool/msvc.py +++ b/src/engine/SCons/Tool/msvc.py @@ -47,7 +47,7 @@ import SCons.Util import SCons.Warnings import SCons.Scanner.RC -from MSCommon import msvc_exists, msvc_setup_env_once +from .MSCommon import msvc_exists, msvc_setup_env_once CSuffixes = ['.c', '.C'] CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py index 06ce4861..370af9a1 100644 --- a/src/engine/SCons/Tool/msvs.py +++ b/src/engine/SCons/Tool/msvs.py @@ -29,6 +29,7 @@ selection method. # 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. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -51,7 +52,7 @@ import SCons.PathList import SCons.Util import SCons.Warnings -from MSCommon import msvc_exists, msvc_setup_env_once +from .MSCommon import msvc_exists, msvc_setup_env_once from SCons.Defaults import processDefines ############################################################################## @@ -351,7 +352,7 @@ class _DSPGenerator(object): config.platform = 'Win32' self.configs[variant] = config - print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'" + print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") for i in range(len(variants)): AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs) @@ -551,7 +552,7 @@ class _GenerateV6DSP(_DSPGenerator): def Build(self): try: self.file = open(self.dspabs,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() @@ -861,7 +862,7 @@ class _GenerateV7DSP(_DSPGenerator): def Build(self): try: self.file = open(self.dspabs,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() @@ -1029,7 +1030,7 @@ class _GenerateV10DSP(_DSPGenerator): self.filtersabs = self.dspabs + '.filters' try: self.filters_file = open(self.filtersabs, 'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.filtersabs + '" for writing:' + str(detail)) self.filters_file.write('<?xml version="1.0" encoding="utf-8"?>\n' @@ -1158,12 +1159,12 @@ class _GenerateV10DSP(_DSPGenerator): '\t</ItemGroup>\n' % str(self.sconscript)) def Parse(self): - print "_GenerateV10DSP.Parse()" + print("_GenerateV10DSP.Parse()") def Build(self): try: self.file = open(self.dspabs, 'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() @@ -1242,7 +1243,7 @@ class _GenerateV7DSW(_DSWGenerator): config.platform = 'Win32' self.configs[variant] = config - print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'" + print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") if 'variant' not in env: raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ @@ -1424,7 +1425,7 @@ class _GenerateV7DSW(_DSWGenerator): def Build(self): try: self.file = open(self.dswfile,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) else: self.PrintSolution() @@ -1473,7 +1474,7 @@ class _GenerateV6DSW(_DSWGenerator): def Build(self): try: self.file = open(self.dswfile,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) else: self.PrintWorkspace() @@ -1530,8 +1531,8 @@ def GenerateProject(target, source, env): if not dspfile is builddspfile: try: bdsp = open(str(builddspfile), "w+") - except IOError, detail: - print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n' + except IOError as detail: + print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') raise bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath()) @@ -1546,8 +1547,8 @@ def GenerateProject(target, source, env): try: bdsw = open(str(builddswfile), "w+") - except IOError, detail: - print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n' + except IOError as detail: + print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') raise bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath()) diff --git a/src/engine/SCons/Tool/msvsTests.py b/src/engine/SCons/Tool/msvsTests.py index 2f4f302a..9334bac0 100644 --- a/src/engine/SCons/Tool/msvsTests.py +++ b/src/engine/SCons/Tool/msvsTests.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -748,7 +749,7 @@ if __name__ == "__main__": ] for test_class in test_classes: - print "TEST: ", test_class.__doc__ + print("TEST: ", test_class.__doc__) back_osenv = copy.deepcopy(os.environ) try: # XXX: overriding the os.environ is bad, but doing it diff --git a/src/engine/SCons/Tool/packaging/__init__.py b/src/engine/SCons/Tool/packaging/__init__.py index 95311a2b..345ec87e 100644 --- a/src/engine/SCons/Tool/packaging/__init__.py +++ b/src/engine/SCons/Tool/packaging/__init__.py @@ -120,7 +120,7 @@ def Package(env, target=None, source=None, **kw): try: file,path,desc=imp.find_module(type, __path__) return imp.load_module(type, file, path, desc) - except ImportError, e: + except ImportError as e: raise EnvironmentError("packager %s not available: %s"%(type,str(e))) packagers=list(map(load_packager, PACKAGETYPE)) @@ -141,7 +141,7 @@ def Package(env, target=None, source=None, **kw): if 'PACKAGEROOT' not in kw: kw['PACKAGEROOT'] = default_name%kw - except KeyError, e: + except KeyError as e: raise SCons.Errors.UserError( "Missing Packagetag '%s'"%e.args[0] ) # setup the source files @@ -157,10 +157,10 @@ def Package(env, target=None, source=None, **kw): assert( len(target) == 0 ) - except KeyError, e: + except KeyError as e: raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ % (e.args[0],packager.__name__) ) - except TypeError, e: + except TypeError as e: # this exception means that a needed argument for the packager is # missing. As our packagers get their "tags" as named function # arguments we need to find out which one is missing. diff --git a/src/engine/SCons/Tool/packaging/msi.py b/src/engine/SCons/Tool/packaging/msi.py index fe78c9c9..49c28ca1 100644 --- a/src/engine/SCons/Tool/packaging/msi.py +++ b/src/engine/SCons/Tool/packaging/msi.py @@ -216,7 +216,7 @@ def build_wxsfile(target, source, env): if 'CHANGE_SPECFILE' in env: env['CHANGE_SPECFILE'](target, source) - except KeyError, e: + except KeyError as e: raise SCons.Errors.UserError( '"%s" package field for MSI is missing.' % e.args[0] ) # diff --git a/src/engine/SCons/Tool/packaging/rpm.py b/src/engine/SCons/Tool/packaging/rpm.py index 07857d18..a9e0fa2e 100644 --- a/src/engine/SCons/Tool/packaging/rpm.py +++ b/src/engine/SCons/Tool/packaging/rpm.py @@ -107,7 +107,7 @@ def collectintargz(target, source, env): try: #tarball = env['SOURCE_URL'].split('/')[-1] tarball = env['SOURCE_URL'].split('/')[-1] - except KeyError, e: + except KeyError as e: raise SCons.Errors.UserError( "Missing PackageTag '%s' for RPM packager" % e.args[0] ) tarball = src_targz.package(env, source=sources, target=tarball, @@ -143,7 +143,7 @@ def build_specfile(target, source, env): if 'CHANGE_SPECFILE' in env: env['CHANGE_SPECFILE'](target, source) - except KeyError, e: + except KeyError as e: raise SCons.Errors.UserError( '"%s" package field for RPM is missing.' % e.args[0] ) @@ -331,7 +331,7 @@ class SimpleTagCompiler(object): for key, replacement in domestic: try: str = str + replacement % values[key] - except KeyError, e: + except KeyError as e: if self.mandatory: raise e @@ -344,7 +344,7 @@ class SimpleTagCompiler(object): int_values_for_key = [(get_country_code(t[0]),t[1]) for t in x] for v in int_values_for_key: str = str + replacement % v - except KeyError, e: + except KeyError as e: if self.mandatory: raise e diff --git a/src/engine/SCons/Tool/pdflatex.py b/src/engine/SCons/Tool/pdflatex.py index 922e718a..fbffb239 100644 --- a/src/engine/SCons/Tool/pdflatex.py +++ b/src/engine/SCons/Tool/pdflatex.py @@ -62,7 +62,7 @@ def generate(env): env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) - import pdf + from . import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] diff --git a/src/engine/SCons/Tool/pdftex.py b/src/engine/SCons/Tool/pdftex.py index 30c56afb..e9a0bda0 100644 --- a/src/engine/SCons/Tool/pdftex.py +++ b/src/engine/SCons/Tool/pdftex.py @@ -85,7 +85,7 @@ def generate(env): env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) - import pdf + from . import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] diff --git a/src/engine/SCons/Tool/qt.py b/src/engine/SCons/Tool/qt.py index 716c7d52..723c39cc 100644 --- a/src/engine/SCons/Tool/qt.py +++ b/src/engine/SCons/Tool/qt.py @@ -31,6 +31,7 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -130,12 +131,12 @@ class _Automoc(object): if not obj.has_builder(): # binary obj file provided if debug: - print "scons: qt: '%s' seems to be a binary. Discarded." % str(obj) + print("scons: qt: '%s' seems to be a binary. Discarded." % str(obj)) continue cpp = obj.sources[0] if not splitext(str(cpp))[1] in cxx_suffixes: if debug: - print "scons: qt: '%s' is no cxx file. Discarded." % str(cpp) + print("scons: qt: '%s' is no cxx file. Discarded." % str(cpp)) # c or fortran source continue #cpp_contents = comment.sub('', cpp.get_text_contents()) @@ -148,12 +149,12 @@ class _Automoc(object): h = find_file(hname, (cpp.get_dir(),), env.File) if h: if debug: - print "scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp)) + print("scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp))) #h_contents = comment.sub('', h.get_text_contents()) h_contents = h.get_text_contents() break if not h and debug: - print "scons: qt: no header for '%s'." % (str(cpp)) + print("scons: qt: no header for '%s'." % (str(cpp))) if h and q_object_search.search(h_contents): # h file with the Q_OBJECT macro found -> add moc_cpp moc_cpp = env.Moc(h) @@ -161,14 +162,14 @@ class _Automoc(object): out_sources.append(moc_o) #moc_cpp.target_scanner = SCons.Defaults.CScan if debug: - print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp)) + print("scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp))) if cpp and q_object_search.search(cpp_contents): # cpp file with Q_OBJECT macro found -> add moc # (to be included in cpp) moc = env.Moc(cpp) env.Ignore(moc, moc) if debug: - print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc)) + print("scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))) #moc.source_scanner = SCons.Defaults.CScan # restore the original env attributes (FIXME) objBuilder.env = objBuilderEnv diff --git a/src/engine/SCons/Tool/rpmutils.py b/src/engine/SCons/Tool/rpmutils.py index e20d53bc..3eeed1df 100644 --- a/src/engine/SCons/Tool/rpmutils.py +++ b/src/engine/SCons/Tool/rpmutils.py @@ -34,6 +34,7 @@ exact syntax. # 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. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -501,7 +502,7 @@ def updateRpmDicts(rpmrc, pyfile): key = tokens[0] if key in sections: # Have we met this section before? - if not data.has_key(tokens[0]): + if tokens[0] not in data: # No, so insert it data[key] = {} # Insert data @@ -519,7 +520,7 @@ def updateRpmDicts(rpmrc, pyfile): if l.startswith('# Start of rpmrc dictionaries'): pm = 1 # Write data sections to single dictionaries - for key, entries in data.iteritems(): + for key, entries in data.items(): out.write("%s = {\n" % key) for arch in sorted(entries.keys()): out.write(" '%s' : ['%s'],\n" % (arch, "','".join(entries[arch]))) @@ -529,7 +530,7 @@ def updateRpmDicts(rpmrc, pyfile): pass def usage(): - print "rpmutils.py rpmrc.in rpmutils.py" + print("rpmutils.py rpmrc.in rpmutils.py") def main(): import sys diff --git a/src/engine/SCons/Tool/sgicc.py b/src/engine/SCons/Tool/sgicc.py index 662eb7dd..94a04976 100644 --- a/src/engine/SCons/Tool/sgicc.py +++ b/src/engine/SCons/Tool/sgicc.py @@ -33,7 +33,7 @@ selection method. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import cc +from . import cc def generate(env): """Add Builders and construction variables for gcc to an Environment.""" diff --git a/src/engine/SCons/Tool/sgilink.py b/src/engine/SCons/Tool/sgilink.py index 6244141e..b1e7921e 100644 --- a/src/engine/SCons/Tool/sgilink.py +++ b/src/engine/SCons/Tool/sgilink.py @@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -import link +from . import link linkers = ['CC', 'cc'] diff --git a/src/engine/SCons/Tool/suncc.py b/src/engine/SCons/Tool/suncc.py index 458538b4..4651219b 100644 --- a/src/engine/SCons/Tool/suncc.py +++ b/src/engine/SCons/Tool/suncc.py @@ -34,7 +34,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -import cc +from . import cc def generate(env): """ diff --git a/src/engine/SCons/Tool/sunf77.py b/src/engine/SCons/Tool/sunf77.py index d05ce541..20d18938 100644 --- a/src/engine/SCons/Tool/sunf77.py +++ b/src/engine/SCons/Tool/sunf77.py @@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -from FortranCommon import add_all_to_env +from .FortranCommon import add_all_to_env compilers = ['sunf77', 'f77'] diff --git a/src/engine/SCons/Tool/sunf90.py b/src/engine/SCons/Tool/sunf90.py index 93b89c00..ce1697c3 100644 --- a/src/engine/SCons/Tool/sunf90.py +++ b/src/engine/SCons/Tool/sunf90.py @@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -from FortranCommon import add_all_to_env +from .FortranCommon import add_all_to_env compilers = ['sunf90', 'f90'] diff --git a/src/engine/SCons/Tool/sunf95.py b/src/engine/SCons/Tool/sunf95.py index c09026ca..218569c0 100644 --- a/src/engine/SCons/Tool/sunf95.py +++ b/src/engine/SCons/Tool/sunf95.py @@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Util -from FortranCommon import add_all_to_env +from .FortranCommon import add_all_to_env compilers = ['sunf95', 'f95'] diff --git a/src/engine/SCons/Tool/sunlink.py b/src/engine/SCons/Tool/sunlink.py index 5996a301..af133929 100644 --- a/src/engine/SCons/Tool/sunlink.py +++ b/src/engine/SCons/Tool/sunlink.py @@ -37,7 +37,7 @@ import os.path import SCons.Util -import link +from . import link ccLinker = None diff --git a/src/engine/SCons/Tool/swig.py b/src/engine/SCons/Tool/swig.py index d51a386a..5d2264c3 100644 --- a/src/engine/SCons/Tool/swig.py +++ b/src/engine/SCons/Tool/swig.py @@ -131,7 +131,7 @@ def _get_swig_version(env): stdout = subprocess.PIPE) if pipe.wait() != 0: return - out = pipe.stdout.read() + out = SCons.Util.to_str (pipe.stdout.read()) match = re.search(r'SWIG Version\s+(\S+)$', out, re.MULTILINE) if match: return match.group(1) diff --git a/src/engine/SCons/Tool/tex.py b/src/engine/SCons/Tool/tex.py index 5f24df0a..dac98b7f 100644 --- a/src/engine/SCons/Tool/tex.py +++ b/src/engine/SCons/Tool/tex.py @@ -31,6 +31,7 @@ selection method. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -163,15 +164,15 @@ def FindFile(name,suffixes,paths,env,requireExt=False): if ext: name = name + ext if Verbose: - print " searching for '%s' with extensions: " % name,suffixes + print(" searching for '%s' with extensions: " % name,suffixes) for path in paths: testName = os.path.join(path,name) if Verbose: - print " look for '%s'" % testName + print(" look for '%s'" % testName) if os.path.isfile(testName): if Verbose: - print " found '%s'" % testName + print(" found '%s'" % testName) return env.fs.File(testName) else: name_ext = SCons.Util.splitext(testName)[1] @@ -182,14 +183,14 @@ def FindFile(name,suffixes,paths,env,requireExt=False): for suffix in suffixes: testNameExt = testName + suffix if Verbose: - print " look for '%s'" % testNameExt + print(" look for '%s'" % testNameExt) if os.path.isfile(testNameExt): if Verbose: - print " found '%s'" % testNameExt + print(" found '%s'" % testNameExt) return env.fs.File(testNameExt) if Verbose: - print " did not find '%s'" % name + print(" did not find '%s'" % name) return None def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None): @@ -249,7 +250,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None saved_hashes[suffix] = theNode.get_csig() if Verbose: - print "hashes: ",saved_hashes + print("hashes: ",saved_hashes) must_rerun_latex = True @@ -268,12 +269,12 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if saved_hashes[suffix] == new_md5: if Verbose: - print "file %s not changed" % (targetbase+suffix) + print("file %s not changed" % (targetbase+suffix)) return False # unchanged saved_hashes[suffix] = new_md5 must_rerun_latex = True if Verbose: - print "file %s changed, rerunning Latex, new hash = " % (targetbase+suffix), new_md5 + print("file %s changed, rerunning Latex, new hash = " % (targetbase+suffix), new_md5) return True # changed # generate the file name that latex will generate @@ -322,8 +323,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None bcffiles = list(dups.keys()) if Verbose: - print "auxfiles ",auxfiles - print "bcffiles ",bcffiles + print("auxfiles ",auxfiles) + print("bcffiles ",bcffiles) # Now decide if bibtex will need to be run. # The information that bibtex reads from the .aux file is @@ -339,7 +340,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None content = open(target_aux, "rb").read() if content.find("bibdata") != -1: if Verbose: - print "Need to run bibtex on ",auxfilename + print("Need to run bibtex on ",auxfilename) bibfile = env.fs.File(SCons.Util.splitext(target_aux)[0]) result = BibTeXAction(bibfile, bibfile, env) if result != 0: @@ -362,7 +363,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None content = open(target_bcf, "rb").read() if content.find("bibdata") != -1: if Verbose: - print "Need to run biber on ",bcffilename + print("Need to run biber on ",bcffilename) bibfile = env.fs.File(SCons.Util.splitext(target_bcf)[0]) result = BiberAction(bibfile, bibfile, env) if result != 0: @@ -373,7 +374,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if check_MD5(suffix_nodes['.idx'],'.idx') or (count == 1 and run_makeindex): # We must run makeindex if Verbose: - print "Need to run makeindex" + print("Need to run makeindex") idxfile = suffix_nodes['.idx'] result = MakeIndexAction(idxfile, idxfile, env) if result != 0: @@ -391,7 +392,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if check_MD5(suffix_nodes['.nlo'],'.nlo') or (count == 1 and run_nomenclature): # We must run makeindex if Verbose: - print "Need to run makeindex for nomenclature" + print("Need to run makeindex for nomenclature") nclfile = suffix_nodes['.nlo'] result = MakeNclAction(nclfile, nclfile, env) if result != 0: @@ -403,7 +404,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if check_MD5(suffix_nodes['.glo'],'.glo') or (count == 1 and run_glossaries) or (count == 1 and run_glossary): # We must run makeindex if Verbose: - print "Need to run makeindex for glossary" + print("Need to run makeindex for glossary") glofile = suffix_nodes['.glo'] result = MakeGlossaryAction(glofile, glofile, env) if result != 0: @@ -415,7 +416,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if check_MD5(suffix_nodes['.acn'],'.acn') or (count == 1 and run_acronyms): # We must run makeindex if Verbose: - print "Need to run makeindex for acronyms" + print("Need to run makeindex for acronyms") acrfile = suffix_nodes['.acn'] result = MakeAcronymsAction(acrfile, acrfile, env) if result != 0: @@ -428,7 +429,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if check_MD5(suffix_nodes[newglossary_suffix[ig][2]],newglossary_suffix[ig][2]) or (count == 1): # We must run makeindex if Verbose: - print "Need to run makeindex for newglossary" + print("Need to run makeindex for newglossary") newglfile = suffix_nodes[newglossary_suffix[ig][2]] MakeNewGlossaryAction = SCons.Action.Action("$MAKENEWGLOSSARY ${SOURCE.filebase}%s -s ${SOURCE.filebase}.ist -t ${SOURCE.filebase}%s -o ${SOURCE.filebase}%s" % (newglossary_suffix[ig][2],newglossary_suffix[ig][0],newglossary_suffix[ig][1]), "$MAKENEWGLOSSARYCOMSTR") @@ -442,26 +443,26 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None if warning_rerun_re.search(logContent): must_rerun_latex = True if Verbose: - print "rerun Latex due to latex or package rerun warning" + print("rerun Latex due to latex or package rerun warning") if rerun_citations_re.search(logContent): must_rerun_latex = True if Verbose: - print "rerun Latex due to 'Rerun to get citations correct' warning" + print("rerun Latex due to 'Rerun to get citations correct' warning") if undefined_references_re.search(logContent): must_rerun_latex = True if Verbose: - print "rerun Latex due to undefined references or citations" + print("rerun Latex due to undefined references or citations") if (count >= int(env.subst('$LATEXRETRIES')) and must_rerun_latex): - print "reached max number of retries on Latex ,",int(env.subst('$LATEXRETRIES')) + print("reached max number of retries on Latex ,",int(env.subst('$LATEXRETRIES'))) # end of while loop # rename Latex's output to what the target name is if not (str(target[0]) == resultfilename and os.path.isfile(resultfilename)): if os.path.isfile(resultfilename): - print "move %s to %s" % (resultfilename, str(target[0]), ) + print("move %s to %s" % (resultfilename, str(target[0]), )) shutil.move(resultfilename,str(target[0])) # Original comment (when TEXPICTS was not restored): @@ -515,27 +516,27 @@ def is_LaTeX(flist,env,abspath): else: env['ENV']['TEXINPUTS'] = savedpath if Verbose: - print "is_LaTeX search path ",paths - print "files to search :",flist + print("is_LaTeX search path ",paths) + print("files to search :",flist) # Now that we have the search path and file list, check each one for f in flist: if Verbose: - print " checking for Latex source ",str(f) + print(" checking for Latex source ",str(f)) content = f.get_text_contents() if LaTeX_re.search(content): if Verbose: - print "file %s is a LaTeX file" % str(f) + print("file %s is a LaTeX file" % str(f)) return 1 if Verbose: - print "file %s is not a LaTeX file" % str(f) + print("file %s is not a LaTeX file" % str(f)) # now find included files inc_files = [ ] inc_files.extend( include_re.findall(content) ) if Verbose: - print "files included by '%s': "%str(f),inc_files + print("files included by '%s': "%str(f),inc_files) # inc_files is list of file names as given. need to find them # using TEXINPUTS paths. @@ -545,7 +546,7 @@ def is_LaTeX(flist,env,abspath): # make this a list since is_LaTeX takes a list. fileList = [srcNode,] if Verbose: - print "FindFile found ",srcNode + print("FindFile found ",srcNode) if srcNode is not None: file_test = is_LaTeX(fileList, env, abspath) @@ -554,7 +555,7 @@ def is_LaTeX(flist,env,abspath): return file_test if Verbose: - print " done scanning ",str(f) + print(" done scanning ",str(f)) return 0 @@ -619,15 +620,15 @@ def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi content = theFile.get_text_contents() if Verbose: - print " scanning ",str(theFile) + print(" scanning ",str(theFile)) for i in range(len(file_tests_search)): if file_tests[i][0] is None: if Verbose: - print "scan i ",i," files_tests[i] ",file_tests[i], file_tests[i][1] + print("scan i ",i," files_tests[i] ",file_tests[i], file_tests[i][1]) file_tests[i][0] = file_tests_search[i].search(content) if Verbose and file_tests[i][0]: - print " found match for ",file_tests[i][1][-1] + print(" found match for ",file_tests[i][1][-1]) # for newglossary insert the suffixes in file_tests[i] if file_tests[i][0] and file_tests[i][1][-1] == 'newglossary': findresult = file_tests_search[i].findall(content) @@ -638,19 +639,19 @@ def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi suffix_list = ['.'+findresult[l][0],'.'+findresult[l][2],'.'+findresult[l][3] ] newglossary_suffix.append(suffix_list) if Verbose: - print " new suffixes for newglossary ",newglossary_suffix + print(" new suffixes for newglossary ",newglossary_suffix) incResult = includeOnly_re.search(content) if incResult: aux_files.append(os.path.join(targetdir, incResult.group(1))) if Verbose: - print "\include file names : ", aux_files + print("\include file names : ", aux_files) # recursively call this on each of the included files inc_files = [ ] inc_files.extend( include_re.findall(content) ) if Verbose: - print "files included by '%s': "%str(theFile),inc_files + print("files included by '%s': "%str(theFile),inc_files) # inc_files is list of file names as given. need to find them # using TEXINPUTS paths. @@ -659,7 +660,7 @@ def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi if srcNode is not None: file_tests = ScanFiles(srcNode, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir, aux_files) if Verbose: - print " done scanning ",str(theFile) + print(" done scanning ",str(theFile)) return file_tests def tex_emitter_core(target, source, env, graphics_extensions): @@ -689,7 +690,7 @@ def tex_emitter_core(target, source, env, graphics_extensions): env.SideEffect(logfilename,target[0]) env.SideEffect(flsfilename,target[0]) if Verbose: - print "side effect :",auxfilename,logfilename,flsfilename + print("side effect :",auxfilename,logfilename,flsfilename) env.Clean(target[0],auxfilename) env.Clean(target[0],logfilename) env.Clean(target[0],flsfilename) @@ -765,7 +766,7 @@ def tex_emitter_core(target, source, env, graphics_extensions): else: env['ENV']['TEXINPUTS'] = savedpath if Verbose: - print "search path ",paths + print("search path ",paths) # scan all sources for side effect files aux_files = [] @@ -774,7 +775,7 @@ def tex_emitter_core(target, source, env, graphics_extensions): for (theSearch,suffix_list) in file_tests: # add side effects if feature is present.If file is to be generated,add all side effects if Verbose and theSearch: - print "check side effects for ",suffix_list[-1] + print("check side effects for ",suffix_list[-1]) if (theSearch != None) or (not source[0].exists() ): file_list = [targetbase,] # for bibunit we need a list of files @@ -788,11 +789,11 @@ def tex_emitter_core(target, source, env, graphics_extensions): if suffix_list[-1] == 'multibib': for multibibmatch in multibib_re.finditer(content): if Verbose: - print "multibib match ",multibibmatch.group(1) + print("multibib match ",multibibmatch.group(1)) if multibibmatch != None: baselist = multibibmatch.group(1).split(',') if Verbose: - print "multibib list ", baselist + print("multibib list ", baselist) for i in range(len(baselist)): file_list.append(os.path.join(targetdir, baselist[i])) # now define the side effects @@ -800,14 +801,14 @@ def tex_emitter_core(target, source, env, graphics_extensions): for suffix in suffix_list[:-1]: env.SideEffect(file_name + suffix,target[0]) if Verbose: - print "side effect tst :",file_name + suffix, " target is ",str(target[0]) + print("side effect tst :",file_name + suffix, " target is ",str(target[0])) env.Clean(target[0],file_name + suffix) for aFile in aux_files: aFile_base = SCons.Util.splitext(aFile)[0] env.SideEffect(aFile_base + '.aux',target[0]) if Verbose: - print "side effect aux :",aFile_base + '.aux' + print("side effect aux :",aFile_base + '.aux') env.Clean(target[0],aFile_base + '.aux') # read fls file to get all other files that latex creates and will read on the next pass # remove files from list that we explicitly dealt with above @@ -820,7 +821,7 @@ def tex_emitter_core(target, source, env, graphics_extensions): out_files.remove(filename) env.SideEffect(out_files,target[0]) if Verbose: - print "side effect fls :",out_files + print("side effect fls :",out_files) env.Clean(target[0],out_files) return (target, source) @@ -840,7 +841,7 @@ def generate(env): generate_common(env) - import dvi + from . import dvi dvi.generate(env) bld = env['BUILDERS']['DVI'] diff --git a/src/engine/SCons/Tool/textfile.py b/src/engine/SCons/Tool/textfile.py index 8dc8f4b8..693b62b7 100644 --- a/src/engine/SCons/Tool/textfile.py +++ b/src/engine/SCons/Tool/textfile.py @@ -107,7 +107,7 @@ def _action(target, source, env): # write the file try: fd = open(target[0].get_path(), "wb") - except (OSError,IOError), e: + except (OSError,IOError) as e: raise SCons.Errors.UserError("Can't write target file %s" % target[0]) # separate lines by 'linesep' only if linesep is not empty lsep = None diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py index 64436b8e..f9375a20 100644 --- a/src/engine/SCons/Tool/xgettext.py +++ b/src/engine/SCons/Tool/xgettext.py @@ -23,6 +23,7 @@ Tool specific initialization of `xgettext` tool. # 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. +from six import u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -55,7 +56,7 @@ class _CmdRunner(object): 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)) + if self.err: sys.stderr.write(u(self.err)) return self.status def strfunction(self, target, source, env): @@ -153,7 +154,7 @@ from SCons.Builder import BuilderBase class _POTBuilder(BuilderBase): def _execute(self, env, target, source, *args): if not target: - if env.has_key('POTDOMAIN') and env['POTDOMAIN']: + if 'POTDOMAIN' in env and env['POTDOMAIN']: domain = env['POTDOMAIN'] else: domain = 'messages' @@ -175,7 +176,7 @@ def _scan_xgettext_from_files(target, source, env, files = None, path = None): files = [ files ] if path is None: - if env.has_key('XGETTEXTPATH'): + if 'XGETTEXTPATH' in env: path = env['XGETTEXTPATH'] else: path = [] @@ -222,7 +223,7 @@ def _pot_update_emitter(target, source, env): import SCons.Util import SCons.Node.FS - if env.has_key('XGETTEXTFROM'): + if 'XGETTEXTFROM' in env: xfrom = env['XGETTEXTFROM'] else: return target, source diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 822d5249..052b3fc9 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -23,6 +23,7 @@ Various utility functions go here. # 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. +from six import PY2, PY3, u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -32,11 +33,16 @@ import copy import re import types -from collections import UserDict, UserList, UserString +if PY3: + from collections import UserDict, UserList, UserString +else: + from UserDict import UserDict + from UserList import UserList + from UserString import UserString # Don't "from types import ..." these because we need to get at the # types module later to look for UnicodeType. -InstanceType = types.InstanceType +InstanceType = types.InstanceType if PY2 else None MethodType = types.MethodType FunctionType = types.FunctionType try: unicode @@ -114,6 +120,9 @@ class NodeList(UserList): def __nonzero__(self): return len(self.data) != 0 + def __bool__(self): + return self.__nonzero__() + def __str__(self): return ' '.join(map(str, self.data)) @@ -153,7 +162,7 @@ class DisplayEngine(object): return if append_newline: text = text + '\n' try: - sys.stdout.write(unicode(text)) + sys.stdout.write(u(text)) except IOError: # Stdout might be connected to a pipe that has been closed # by now. The most likely reason for the pipe being closed @@ -239,7 +248,7 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}): ' N = no clean\n' + ' H = no cache\n' + '\n') - sys.stdout.write(unicode(legend)) + sys.stdout.write(u(legend)) tags = ['['] tags.append(' E'[IDX(root.exists())]) @@ -303,11 +312,17 @@ SequenceTypes = (list, tuple, UserList) # Note that profiling data shows a speed-up when comparing # explicitely with str and unicode instead of simply comparing # with basestring. (at least on Python 2.5.1) -StringTypes = (str, unicode, UserString) +try: + StringTypes = (str, unicode, UserString) +except NameError: + StringTypes = (str, UserString) # Empirically, it is faster to check explicitely for str and # unicode than for basestring. -BaseStringTypes = (str, unicode) +try: + BaseStringTypes = (str, unicode) +except NameError: + BaseStringTypes = (str) def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes): return isinstance(obj, DictTypes) @@ -519,10 +534,10 @@ class Proxy(object): """Retrieve the entire wrapped object""" return self._subject - def __cmp__(self, other): + def __eq__(self, other): if issubclass(other.__class__, self._subject.__class__): - return cmp(self._subject, other) - return cmp(self.__dict__, other.__dict__) + return self._subject == other + return self.__dict__ == other.__dict__ class Delegate(object): """A Python Descriptor class that delegates attribute fetches @@ -718,7 +733,7 @@ else: # raised so as to not mask possibly serious disk or # network issues. continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: try: reject.index(f) except ValueError: @@ -1346,8 +1361,9 @@ def make_path_relative(path): def AddMethod(obj, function, name=None): """ - Adds either a bound method to an instance or an unbound method to - a class. If name is ommited the name of the specified function + Adds either a bound method to an instance or the function itself + (or an unbound method in Python 2) to a class. + If name is ommited the name of the specified function is used by default. Example: a = A() @@ -1360,26 +1376,32 @@ def AddMethod(obj, function, name=None): print a.listIndex(5) """ if name is None: - name = function.func_name + name = function.__name__ else: function = RenameFunction(function, name) if hasattr(obj, '__class__') and obj.__class__ is not type: # "obj" is an instance, so it gets a bound method. - setattr(obj, name, MethodType(function, obj, obj.__class__)) + if PY3: + method = MethodType(function, obj) + else: + method = MethodType(function, obj, obj.__class__) + setattr(obj, name, method) else: # "obj" is a class, so it gets an unbound method. - setattr(obj, name, MethodType(function, None, obj)) + if PY2: + function = MethodType(function, None, obj) + setattr(obj, name, function) def RenameFunction(function, name): """ Returns a function identical to the specified function, but with the specified name. """ - return FunctionType(function.func_code, - function.func_globals, + return FunctionType(function.__code__, + function.__globals__, name, - function.func_defaults) + function.__defaults__) md5 = False @@ -1401,7 +1423,7 @@ else: md5 = True def MD5signature(s): m = hashlib.md5() - m.update(str(s)) + m.update(to_bytes(str(s))) return m.hexdigest() def MD5filesignature(fname, chunksize=65536): @@ -1411,7 +1433,7 @@ else: blck = f.read(chunksize) if not blck: break - m.update(str(blck)) + m.update(to_bytes (str(blck))) f.close() return m.hexdigest() @@ -1463,6 +1485,8 @@ class Null(object): return "Null(0x%08X)" % id(self) def __nonzero__(self): return False + def __bool__(self): + return False def __getattr__(self, name): return self def __setattr__(self, name, value): @@ -1485,6 +1509,18 @@ class NullSeq(Null): del __revision__ +def to_bytes (s): + if isinstance (s, bytes) or bytes is str: + return s + else: + return bytes (s, 'utf-8') + +def to_str (s): + if bytes is str: + return s + else: + return str (s, 'utf-8') + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index b0c15c5d..3167b9da 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from six import u __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -220,7 +221,7 @@ class UtilTestCase(unittest.TestCase): assert not is_Dict(()) assert not is_Dict("") if HasUnicode: - exec "assert not is_Dict(u'')" + exec("assert not is_Dict(u'')") def test_is_List(self): assert is_List([]) @@ -236,12 +237,12 @@ class UtilTestCase(unittest.TestCase): assert not is_List({}) assert not is_List("") if HasUnicode: - exec "assert not is_List(u'')" + exec("assert not is_List(u'')") def test_is_String(self): assert is_String("") if HasUnicode: - exec "assert is_String(u'')" + exec("assert is_String(u'')") assert is_String(UserString('')) try: class mystr(str): @@ -267,7 +268,7 @@ class UtilTestCase(unittest.TestCase): assert not is_Tuple({}) assert not is_Tuple("") if HasUnicode: - exec "assert not is_Tuple(u'')" + exec("assert not is_Tuple(u'')") def test_to_String(self): """Test the to_String() method.""" @@ -314,10 +315,10 @@ class UtilTestCase(unittest.TestCase): os.mkdir(sub2_xxx_exe) test.write(sub3_xxx_exe, "\n") - os.chmod(sub3_xxx_exe, 0777) + os.chmod(sub3_xxx_exe, 0o777) test.write(sub4_xxx_exe, "\n") - os.chmod(sub4_xxx_exe, 0777) + os.chmod(sub4_xxx_exe, 0o777) env_path = os.environ['PATH'] @@ -682,7 +683,7 @@ bling fobj = io.StringIO(content) except TypeError: # Python 2.7 and beyond require unicode strings. - fobj = io.StringIO(unicode(content)) + fobj = io.StringIO(u(content)) lines = LogicalLines(fobj).readlines() assert lines == [ diff --git a/src/engine/SCons/Variables/PathVariableTests.py b/src/engine/SCons/Variables/PathVariableTests.py index 42667591..3d9d25c8 100644 --- a/src/engine/SCons/Variables/PathVariableTests.py +++ b/src/engine/SCons/Variables/PathVariableTests.py @@ -67,7 +67,7 @@ class PathVariableTestCase(unittest.TestCase): dne = test.workpath('does_not_exist') try: o.validator('X', dne, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == 'Path for option X does not exist: %s' % dne, e except: raise Exception("did not catch expected UserError") @@ -91,7 +91,7 @@ class PathVariableTestCase(unittest.TestCase): f = test.workpath('file') try: o.validator('X', f, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == 'Directory path for option X is a file: %s' % f, e except: raise Exception("did not catch expected UserError") @@ -99,7 +99,7 @@ class PathVariableTestCase(unittest.TestCase): dne = test.workpath('does_not_exist') try: o.validator('X', dne, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == 'Directory path for option X does not exist: %s' % dne, e except: raise Exception("did not catch expected UserError") @@ -124,7 +124,7 @@ class PathVariableTestCase(unittest.TestCase): f = test.workpath('file') try: o.validator('X', f, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == 'Path for option X is a file, not a directory: %s' % f, e except: raise Exception("did not catch expected UserError") @@ -148,7 +148,7 @@ class PathVariableTestCase(unittest.TestCase): d = test.workpath('d') try: o.validator('X', d, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == 'File path for option X does not exist: %s' % d, e except: raise Exception("did not catch expected UserError") @@ -156,7 +156,7 @@ class PathVariableTestCase(unittest.TestCase): dne = test.workpath('does_not_exist') try: o.validator('X', dne, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == 'File path for option X does not exist: %s' % dne, e except: raise Exception("did not catch expected UserError") @@ -200,7 +200,7 @@ class PathVariableTestCase(unittest.TestCase): dne = test.workpath('does_not_exist') try: o.validator('X', dne, {}) - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: expect = 'Path for option X does not exist: %s' % dne assert str(e) == expect, e else: @@ -219,7 +219,7 @@ class PathVariableTestCase(unittest.TestCase): try: o.validator('Y', 'value', {}) - except Exception, e: + except Exception as e: assert str(e) == 'my_validator() got called for Y, value!', e else: raise Exception("did not catch expected exception from my_validator()") diff --git a/src/engine/SCons/Variables/VariablesTests.py b/src/engine/SCons/Variables/VariablesTests.py index d2110c12..3888d19f 100644 --- a/src/engine/SCons/Variables/VariablesTests.py +++ b/src/engine/SCons/Variables/VariablesTests.py @@ -57,7 +57,7 @@ def check(key, value, env): def checkSave(file, expected): gdict = {} ldict = {} - exec open(file, 'rU').read() in gdict, ldict + exec(open(file, 'rU').read(), gdict, ldict) assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict) class VariablesTestCase(unittest.TestCase): diff --git a/src/engine/SCons/Variables/__init__.py b/src/engine/SCons/Variables/__init__.py index ede74803..1c8d834a 100644 --- a/src/engine/SCons/Variables/__init__.py +++ b/src/engine/SCons/Variables/__init__.py @@ -36,11 +36,11 @@ import SCons.Errors import SCons.Util import SCons.Warnings -from BoolVariable import BoolVariable # okay -from EnumVariable import EnumVariable # okay -from ListVariable import ListVariable # naja -from PackageVariable import PackageVariable # naja -from PathVariable import PathVariable # okay +from .BoolVariable import BoolVariable # okay +from .EnumVariable import EnumVariable # okay +from .ListVariable import ListVariable # naja +from .PackageVariable import PackageVariable # naja +from .PathVariable import PathVariable # okay class Variables(object): @@ -170,7 +170,7 @@ class Variables(object): sys.path.insert(0, dir) try: values['__name__'] = filename - exec open(filename, 'rU').read() in {}, values + exec(open(filename, 'rU').read(), {}, values) finally: if dir: del sys.path[0] @@ -206,7 +206,7 @@ class Variables(object): env[option.key] = option.converter(value) except TypeError: env[option.key] = option.converter(value, env) - except ValueError, x: + except ValueError as x: raise SCons.Errors.UserError('Error converting option: %s\n%s'%(option.key, x)) @@ -268,7 +268,7 @@ class Variables(object): finally: fh.close() - except IOError, x: + except IOError as x: raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) def GenerateHelpText(self, env, sort=None): diff --git a/src/engine/SCons/compat/__init__.py b/src/engine/SCons/compat/__init__.py index c870fbc4..6f1a7eec 100644 --- a/src/engine/SCons/compat/__init__.py +++ b/src/engine/SCons/compat/__init__.py @@ -87,7 +87,7 @@ def rename_module(new, old): rename_module('builtins', '__builtin__') -import _scons_builtins +from . import _scons_builtins try: diff --git a/src/engine/SCons/compat/_scons_subprocess.py b/src/engine/SCons/compat/_scons_subprocess.py index eebe53d3..e4ac777c 100644 --- a/src/engine/SCons/compat/_scons_subprocess.py +++ b/src/engine/SCons/compat/_scons_subprocess.py @@ -351,6 +351,8 @@ except that: """ +from __future__ import print_function +from six import integer_types import sys mswindows = (sys.platform == "win32") @@ -439,12 +441,12 @@ except TypeError: def is_int(obj): return isinstance(obj, type(1)) def is_int_or_long(obj): - return type(obj) in (type(1), type(1L)) + return type(obj) in (type(1), type(1)) else: def is_int(obj): return isinstance(obj, int) def is_int_or_long(obj): - return isinstance(obj, (int, long)) + return isinstance(obj, integer_types) try: types.StringTypes @@ -454,7 +456,7 @@ except AttributeError: except NameError: types.StringTypes = (str,) def is_string(obj): - return isinstance(obj, types.StringTypes) + return isinstance(obj, str) _active = [] @@ -802,7 +804,7 @@ class Popen(object): startupinfo.wShowWindow = SW_HIDE comspec = os.environ.get("COMSPEC", "cmd.exe") args = comspec + " /c " + args - if (GetVersion() >= 0x80000000L or + if (GetVersion() >= 0x80000000 or os.path.basename(comspec).lower() == "command.com"): # Win9x, or using command.com on NT. We need to # use the w9xpopen intermediate program. For more @@ -830,7 +832,7 @@ class Popen(object): env, cwd, startupinfo) - except pywintypes.error, e: + except pywintypes.error as e: # Translate pywintypes.error to WindowsError, which is # a subclass of OSError. FIXME: We should really # translate errno using _sys_errlist (or simliar), but @@ -1215,8 +1217,8 @@ def _demo_posix(): # Example 1: Simple redirection: Get process list # plist = Popen(["ps"], stdout=PIPE).communicate()[0] - print "Process list:" - print plist + print("Process list:") + print(plist) # # Example 2: Change uid before executing child @@ -1228,25 +1230,25 @@ def _demo_posix(): # # Example 3: Connecting several subprocesses # - print "Looking for 'hda'..." + print("Looking for 'hda'...") p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) - print repr(p2.communicate()[0]) + print(repr(p2.communicate()[0])) # # Example 4: Catch execution error # - print - print "Trying a weird file..." + print() + print("Trying a weird file...") try: - print Popen(["/this/path/does/not/exist"]).communicate() - except OSError, e: + print(Popen(["/this/path/does/not/exist"]).communicate()) + except OSError as e: if e.errno == errno.ENOENT: - print "The file didn't exist. I thought so..." - print "Child traceback:" - print e.child_traceback + print("The file didn't exist. I thought so...") + print("Child traceback:") + print(e.child_traceback) else: - print "Error", e.errno + print("Error", e.errno) else: sys.stderr.write( "Gosh. No error.\n" ) @@ -1255,15 +1257,15 @@ def _demo_windows(): # # Example 1: Connecting several subprocesses # - print "Looking for 'PROMPT' in set output..." + print("Looking for 'PROMPT' in set output...") p1 = Popen("set", stdout=PIPE, shell=True) p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE) - print repr(p2.communicate()[0]) + print(repr(p2.communicate()[0])) # # Example 2: Simple execution of program # - print "Executing calc..." + print("Executing calc...") p = Popen("calc") p.wait() diff --git a/src/engine/SCons/dblite.py b/src/engine/SCons/dblite.py index f4ba90a1..dbbd65db 100644 --- a/src/engine/SCons/dblite.py +++ b/src/engine/SCons/dblite.py @@ -1,5 +1,6 @@ # dblite.py module contributed by Ralf W. Grosse-Kunstleve. # Extended for Unicode by Steven Knight. +from __future__ import print_function import SCons.compat @@ -14,7 +15,7 @@ keep_all_files = 00000 ignore_corrupt_dbfiles = 0 def corruption_warning(filename): - print "Warning: Discarding corrupt database:", filename + print("Warning: Discarding corrupt database:", filename) try: unicode except NameError: @@ -23,13 +24,16 @@ except NameError: else: def is_string(s): return type(s) in (str, unicode) - +def is_bytes(s): + return isinstance (s, bytes) try: unicode('a') except NameError: def unicode(s): return s dblite_suffix = '.dblite' +if bytes is not str: + dblite_suffix += '.p3' tmp_suffix = '.tmp' class dblite(object): @@ -77,7 +81,7 @@ class dblite(object): statinfo = os.stat(self._file_name) self._chown_to = statinfo.st_uid self._chgrp_to = statinfo.st_gid - except OSError, e: + except OSError as e: # db file doesn't exist yet. # Check os.environ for SUDO_UID, use if set self._chown_to = int(os.environ.get('SUDO_UID', -1)) @@ -90,7 +94,7 @@ class dblite(object): else: try: f = self._open(self._file_name, "rb") - except IOError, e: + except IOError as e: if (self._flag != "c"): raise e self._open(self._file_name, "wb", self._mode) @@ -122,7 +126,7 @@ class dblite(object): # (e.g. from a previous run as root). We should still be able to # unlink() the file if the directory's writable, though, so ignore # any OSError exception thrown by the chmod() call. - try: self._os_chmod(self._file_name, 0777) + try: self._os_chmod(self._file_name, 0o777) except OSError: pass self._os_unlink(self._file_name) self._os_rename(self._tmp_name, self._file_name) @@ -148,10 +152,10 @@ class dblite(object): self._check_writable() if (not is_string(key)): raise TypeError("key `%s' must be a string but is %s" % (key, type(key))) - if (not is_string(value)): - raise TypeError("value `%s' must be a string but is %s" % (value, type(value))) + if (not is_bytes(value)): + raise TypeError("value `%s' must be a bytes but is %s" % (value, type(value))) self._dict[key] = value - self._needs_sync = 0001 + self._needs_sync = 0o001 def keys(self): return list(self._dict.keys()) @@ -171,7 +175,7 @@ class dblite(object): def __len__(self): return len(self._dict) -def open(file, flag=None, mode=0666): +def open(file, flag=None, mode=0o666): return dblite(file, flag, mode) def _exercise(): @@ -198,7 +202,7 @@ def _exercise(): assert db[unicode("ubar")] == unicode("ufoo") try: db.sync() - except IOError, e: + except IOError as e: assert str(e) == "Read-only database: tmp.dblite" else: raise RuntimeError("IOError expected.") @@ -208,13 +212,13 @@ def _exercise(): db.sync() try: db[(1,2)] = "tuple" - except TypeError, e: + except TypeError as e: assert str(e) == "key `(1, 2)' must be a string but is <type 'tuple'>", str(e) else: raise RuntimeError("TypeError exception expected") try: db["list"] = [1,2] - except TypeError, e: + except TypeError as e: assert str(e) == "value `[1, 2]' must be a string but is <type 'list'>", str(e) else: raise RuntimeError("TypeError exception expected") @@ -238,11 +242,10 @@ def _exercise(): os.unlink("tmp.dblite") try: db = open("tmp", "w") - except IOError, e: + except IOError as e: assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e) else: raise RuntimeError("IOError expected.") - print "OK" if (__name__ == "__main__"): _exercise() diff --git a/src/script/scons-time.py b/src/script/scons-time.py index 3b215f98..9737dfed 100644 --- a/src/script/scons-time.py +++ b/src/script/scons-time.py @@ -29,8 +29,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import division -from __future__ import nested_scopes +from __future__ import division, print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -109,8 +108,8 @@ def HACK_for_exec(cmd, *args): internal functions. ''' if not args: exec(cmd) - elif len(args) == 1: exec cmd in args[0] - else: exec cmd in args[0], args[1] + elif len(args) == 1: exec(cmd, args[0]) + else: exec(cmd, args[0], args[1]) class Plotter(object): def increment_size(self, largest): @@ -146,7 +145,7 @@ class Line(object): def print_label(self, inx, x, y): if self.label: - print 'set label %s "%s" at %s,%s right' % (inx, self.label, x, y) + print('set label %s "%s" at %s,%s right' % (inx, self.label, x, y)) def plot_string(self): if self.title: @@ -159,15 +158,15 @@ class Line(object): if fmt is None: fmt = self.fmt if self.comment: - print '# %s' % self.comment + print('# %s' % self.comment) for x, y in self.points: # If y is None, it usually represents some kind of break # in the line's index number. We might want to represent # this some way rather than just drawing the line straight # between the two points on either side. if not y is None: - print fmt % (x, y) - print 'e' + print(fmt % (x, y)) + print('e') def get_x_values(self): return [ p[0] for p in self.points ] @@ -253,8 +252,8 @@ class Gnuplotter(Plotter): return if self.title: - print 'set title "%s"' % self.title - print 'set key %s' % self.key_location + print('set title "%s"' % self.title) + print('set key %s' % self.key_location) min_y = self.get_min_y() max_y = self.max_graph_value(self.get_max_y()) @@ -269,7 +268,7 @@ class Gnuplotter(Plotter): inx += 1 plot_strings = [ self.plot_string(l) for l in self.lines ] - print 'plot ' + ', \\\n '.join(plot_strings) + print('plot ' + ', \\\n '.join(plot_strings)) for line in self.lines: line.print_points() @@ -540,7 +539,7 @@ class SConsTimer(object): header_fmt = ' '.join(['%12s'] * len(columns)) line_fmt = header_fmt + ' %s' - print header_fmt % columns + print(header_fmt % columns) for file in files: t = line_function(file, *args, **kw) @@ -550,7 +549,7 @@ class SConsTimer(object): if diff > 0: t += [''] * diff t.append(file_function(file)) - print line_fmt % tuple(t) + print(line_fmt % tuple(t)) def collect_results(self, files, function, *args, **kw): results = {} @@ -690,7 +689,7 @@ class SConsTimer(object): """ try: import pstats - except ImportError, e: + except ImportError as e: sys.stderr.write('%s: func: %s\n' % (self.name, e)) sys.stderr.write('%s This version of Python is missing the profiler.\n' % self.name_spaces) sys.stderr.write('%s Cannot use the "func" subcommand.\n' % self.name_spaces) @@ -751,7 +750,7 @@ class SConsTimer(object): return self.default(argv) try: return func(argv) - except TypeError, e: + except TypeError as e: sys.stderr.write("%s %s: %s\n" % (self.name, cmdName, e)) import traceback traceback.print_exc(file=sys.stderr) @@ -856,7 +855,7 @@ class SConsTimer(object): self.title = a if self.config_file: - exec open(self.config_file, 'rU').read() in self.__dict__ + exec(open(self.config_file, 'rU').read(), self.__dict__) if self.chdir: os.chdir(self.chdir) @@ -889,13 +888,13 @@ class SConsTimer(object): try: f, line, func, time = \ self.get_function_profile(file, function_name) - except ValueError, e: + except ValueError as e: sys.stderr.write("%s: func: %s: %s\n" % (self.name, file, e)) else: if f.startswith(cwd_): f = f[len(cwd_):] - print "%.3f %s:%d(%s)" % (time, f, line, func) + print("%.3f %s:%d(%s)" % (time, f, line, func)) elif format == 'gnuplot': @@ -1233,7 +1232,7 @@ class SConsTimer(object): sys.exit(1) if self.config_file: - exec open(self.config_file, 'rU').read() in self.__dict__ + exec(open(self.config_file, 'rU').read(), self.__dict__) if args: self.archive_list = args diff --git a/src/script/scons.py b/src/script/scons.py index 0c7b44cc..d0bb8123 100644 --- a/src/script/scons.py +++ b/src/script/scons.py @@ -56,11 +56,11 @@ import sys # engine modules if they're in either directory. -if sys.version_info >= (3,0,0): - msg = "scons: *** SCons version %s does not run under Python version %s.\n\ -Python 3 is not yet supported.\n" - sys.stderr.write(msg % (__version__, sys.version.split()[0])) - sys.exit(1) +## if sys.version_info >= (3,0,0): +## msg = "scons: *** SCons version %s does not run under Python version %s.\n\ +## Python 3 is not yet supported.\n" +## sys.stderr.write(msg % (__version__, sys.version.split()[0])) +## sys.exit(1) script_dir = sys.path[0] diff --git a/src/script/sconsign.py b/src/script/sconsign.py index e5e9d4f9..e99a7414 100644 --- a/src/script/sconsign.py +++ b/src/script/sconsign.py @@ -22,6 +22,9 @@ # 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. +from __future__ import print_function + +from six import PY2, PY3 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -171,7 +174,9 @@ sys.path = libs + sys.path import SCons.compat # so pickle will import cPickle instead -import whichdb +if PY2: + import whichdb +import dbm import time import pickle import imp @@ -189,8 +194,11 @@ def my_whichdb(filename): pass return _orig_whichdb(filename) -_orig_whichdb = whichdb.whichdb -whichdb.whichdb = my_whichdb +if PY3: + _orig_whichdb = dbm.whichdb +else: + _orig_whichdb = whichdb.whichdb +dbm.whichdb = my_whichdb def my_import(mname): if '.' in mname: @@ -310,14 +318,14 @@ def printfield(name, entry, prefix=""): outlist = field("implicit", entry, 0) if outlist: if Verbose: - print " implicit:" - print " " + outlist + print(" implicit:") + print(" " + outlist) outact = field("action", entry, 0) if outact: if Verbose: - print " action: " + outact + print(" action: " + outact) else: - print " " + outact + print(" " + outact) def printentries(entries, location): if Print_Entries: @@ -330,9 +338,9 @@ def printentries(entries, location): try: ninfo = entry.ninfo except AttributeError: - print name + ":" + print(name + ":") else: - print nodeinfo_string(name, entry.ninfo) + print(nodeinfo_string(name, entry.ninfo)) printfield(name, entry.binfo) else: for name in sorted(entries.keys()): @@ -340,9 +348,9 @@ def printentries(entries, location): try: ninfo = entry.ninfo except AttributeError: - print name + ":" + print(name + ":") else: - print nodeinfo_string(name, entry.ninfo) + print(nodeinfo_string(name, entry.ninfo)) printfield(name, entry.binfo) class Do_SConsignDB(object): @@ -361,7 +369,7 @@ class Do_SConsignDB(object): # .sconsign => .sconsign.dblite # .sconsign.dblite => .sconsign.dblite.dblite db = self.dbm.open(fname, "r") - except (IOError, OSError), e: + except (IOError, OSError) as e: print_e = e try: # That didn't work, so try opening the base name, @@ -375,7 +383,7 @@ class Do_SConsignDB(object): # suffix-mangling). try: open(fname, "r") - except (IOError, OSError), e: + except (IOError, OSError) as e: # Nope, that file doesn't even exist, so report that # fact back. print_e = e @@ -386,7 +394,7 @@ class Do_SConsignDB(object): except pickle.UnpicklingError: sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" % (self.dbm_name, fname)) return - except Exception, e: + except Exception as e: sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" % (self.dbm_name, fname, e)) return @@ -403,13 +411,13 @@ class Do_SConsignDB(object): self.printentries(dir, db[dir]) def printentries(self, dir, val): - print '=== ' + dir + ':' + print('=== ' + dir + ':') printentries(pickle.loads(val), dir) def Do_SConsignDir(name): try: fp = open(name, 'rb') - except (IOError, OSError), e: + except (IOError, OSError) as e: sys.stderr.write("sconsign: %s\n" % (e)) return try: @@ -419,7 +427,7 @@ def Do_SConsignDir(name): except pickle.UnpicklingError: sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s'\n" % (name)) return - except Exception, e: + except Exception as e: sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e)) return printentries(sconsign.entries, args[0]) @@ -471,13 +479,13 @@ for o, a in opts: dbm = my_import(dbm_name) except: sys.stderr.write("sconsign: illegal file format `%s'\n" % a) - print helpstr + print(helpstr) sys.exit(2) Do_Call = Do_SConsignDB(a, dbm) else: Do_Call = Do_SConsignDir elif o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-i', '--implicit'): Print_Flags['implicit'] = 1 @@ -497,7 +505,7 @@ if Do_Call: Do_Call(a) else: for a in args: - dbm_name = whichdb.whichdb(a) + dbm_name = dbm.whichdb(a) if dbm_name: Map_Module = {'SCons.dblite' : 'dblite'} dbm = my_import(dbm_name) diff --git a/src/setup.py b/src/setup.py index a8b59a32..2c75c601 100644 --- a/src/setup.py +++ b/src/setup.py @@ -46,14 +46,6 @@ man_pages = [ 'scons-time.1', ] -# Exit with error if trying to install with Python >= 3.0 -if sys.version_info >= (3,0,0): - msg = "scons: *** SCons does not run under Python version %s.\n\ -Python 3 and above are not yet supported.\n" - sys.stderr.write(msg % (sys.version.split()[0])) - sys.exit(1) - - # change to setup.py directory if it was executed from other dir (head, tail) = os.path.split(sys.argv[0]) if head: diff --git a/src/test_files.py b/src/test_files.py index 7d8e75e2..1eee11d9 100644 --- a/src/test_files.py +++ b/src/test_files.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -87,13 +88,13 @@ for directory, check_list in check.items(): no_result.append(directory) if missing: - print "Missing the following files:\n" - print "\t" + "\n\t".join(missing) + print("Missing the following files:\n") + print("\t" + "\n\t".join(missing)) test.fail_test(1) if no_result: - print "Cannot check files, the following have apparently not been built:" - print "\t" + "\n\t".join(no_result) + print("Cannot check files, the following have apparently not been built:") + print("\t" + "\n\t".join(no_result)) test.no_result(1) test.pass_test() diff --git a/src/test_interrupts.py b/src/test_interrupts.py index fb12e2ad..de3a0db0 100644 --- a/src/test_interrupts.py +++ b/src/test_interrupts.py @@ -129,9 +129,9 @@ for f in files: if expected_num != len(uncaught_this_file): uncaughtKeyboardInterrupt = 1 msg = "%s: expected %d uncaught interrupts, got %d:" - print msg % (f, expected_num, len(uncaught_this_file)) + print(msg % (f, expected_num, len(uncaught_this_file))) for line in uncaught_this_file: - print " File %s:%d: Uncaught KeyboardInterrupt!" % (f,line) + print(" File %s:%d: Uncaught KeyboardInterrupt!" % (f,line)) test.fail_test(uncaughtKeyboardInterrupt) diff --git a/src/test_pychecker.py b/src/test_pychecker.py index f87d303e..54d78fbf 100644 --- a/src/test_pychecker.py +++ b/src/test_pychecker.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -139,7 +140,7 @@ for file in files: mismatches.append(stderr) if mismatches: - print ''.join(mismatches[1:]) + print(''.join(mismatches[1:])) test.fail_test() test.pass_test() diff --git a/src/test_setup.py b/src/test_setup.py index 29d36bf3..edf0de53 100644 --- a/src/test_setup.py +++ b/src/test_setup.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -197,9 +198,9 @@ if not os.path.isdir(scons_version) and os.path.isfile(tar_gz): os.system("gunzip -c %s | tar xf -" % tar_gz) if not os.path.isdir(scons_version): - print "Cannot test package installation, found none of the following packages:" - print "\t" + tar_gz - print "\t" + zip + print("Cannot test package installation, found none of the following packages:") + print("\t" + tar_gz) + print("\t" + zip) test.no_result(1) # Verify that a virgin installation installs the version library, diff --git a/src/test_strings.py b/src/test_strings.py index 3288d5f6..297d59d4 100644 --- a/src/test_strings.py +++ b/src/test_strings.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -248,13 +249,13 @@ for collector in check_list: not_built.append(collector.directory) if missing_strings: - print "Found the following files with missing strings:" - print "\t" + "\n\t".join(missing_strings) + print("Found the following files with missing strings:") + print("\t" + "\n\t".join(missing_strings)) test.fail_test(1) if not_built: - print "Cannot check all strings, the following have apparently not been built:" - print "\t" + "\n\t".join(not_built) + print("Cannot check all strings, the following have apparently not been built:") + print("\t" + "\n\t".join(not_built)) test.no_result(1) test.pass_test() diff --git a/test/Actions/unicode-signature.py b/test/Actions/unicode-signature.py index 0d0c4694..d91bfa8c 100644 --- a/test/Actions/unicode-signature.py +++ b/test/Actions/unicode-signature.py @@ -35,12 +35,12 @@ import TestSCons test = TestSCons.TestSCons() -try: - unicode -except NameError: - import sys - msg = "Unicode not supported by Python version %s; skipping test\n" - test.skip_test(msg % sys.version[:3]) +## try: +## unicode +## except NameError: +## import sys +## msg = "Unicode not supported by Python version %s; skipping test\n" +## test.skip_test(msg % sys.version[:3]) test.write('SConstruct', """ fnode = File(u'foo.txt') diff --git a/test/AddOption/help.py b/test/AddOption/help.py index d50e5954..7b886cb9 100644 --- a/test/AddOption/help.py +++ b/test/AddOption/help.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -57,10 +58,10 @@ lines = test.stdout().split('\n') missing = [e for e in expected_lines if e not in lines] if missing: - print "====== STDOUT:" - print test.stdout() - print "====== Missing the following lines in the above AddOption() help output:" - print "\n".join(missing) + print("====== STDOUT:") + print(test.stdout()) + print("====== Missing the following lines in the above AddOption() help output:") + print("\n".join(missing)) test.fail_test() test.unlink('SConstruct') @@ -70,10 +71,10 @@ lines = test.stdout().split('\n') unexpected = [e for e in expected_lines if e in lines] if unexpected: - print "====== STDOUT:" - print test.stdout() - print "====== Unexpected lines in the above non-AddOption() help output:" - print "\n".join(unexpected) + print("====== STDOUT:") + print(test.stdout()) + print("====== Unexpected lines in the above non-AddOption() help output:") + print("\n".join(unexpected)) test.fail_test() test.pass_test() diff --git a/test/Batch/action-changed.py b/test/Batch/action-changed.py index dc2805a4..d0314324 100644 --- a/test/Batch/action-changed.py +++ b/test/Batch/action-changed.py @@ -54,7 +54,7 @@ sys.exit(0) """ test.write('build.py', build_py_contents % (python, 'one')) -os.chmod(test.workpath('build.py'), 0755) +os.chmod(test.workpath('build.py'), 0o755) test.write('SConstruct', """ env = Environment() @@ -81,7 +81,7 @@ test.must_match('f3.out', "one\nf3.in\n") test.up_to_date(arguments = '.') test.write('build.py', build_py_contents % (python, 'two')) -os.chmod(test.workpath('build.py'), 0755) +os.chmod(test.workpath('build.py'), 0o755) test.not_up_to_date(arguments = '.') diff --git a/test/Chmod.py b/test/Chmod.py index c00aea0f..8b5fbe00 100644 --- a/test/Chmod.py +++ b/test/Chmod.py @@ -87,19 +87,19 @@ test.write('f10', "f10\n") test.subdir('d11') test.subdir('d12') -os.chmod(test.workpath('f1'), 0444) -os.chmod(test.workpath('f1-File'), 0444) -os.chmod(test.workpath('d2'), 0555) -os.chmod(test.workpath('d2-Dir'), 0555) -os.chmod(test.workpath('f3'), 0444) -os.chmod(test.workpath('d4'), 0555) -os.chmod(test.workpath('f5'), 0444) -os.chmod(test.workpath('Chmod-f7.in'), 0444) -os.chmod(test.workpath('f7.out-Chmod'), 0444) -os.chmod(test.workpath('f9'), 0444) -os.chmod(test.workpath('f10'), 0444) -os.chmod(test.workpath('d11'), 0555) -os.chmod(test.workpath('d12'), 0555) +os.chmod(test.workpath('f1'), 0o444) +os.chmod(test.workpath('f1-File'), 0o444) +os.chmod(test.workpath('d2'), 0o555) +os.chmod(test.workpath('d2-Dir'), 0o555) +os.chmod(test.workpath('f3'), 0o444) +os.chmod(test.workpath('d4'), 0o555) +os.chmod(test.workpath('f5'), 0o444) +os.chmod(test.workpath('Chmod-f7.in'), 0o444) +os.chmod(test.workpath('f7.out-Chmod'), 0o444) +os.chmod(test.workpath('f9'), 0o444) +os.chmod(test.workpath('f10'), 0o444) +os.chmod(test.workpath('d11'), 0o555) +os.chmod(test.workpath('d12'), 0o555) expect = test.wrap_stdout(read_str = """\ Chmod("f1", 0666) @@ -123,68 +123,68 @@ cat(["f8.out"], ["f8.in"]) test.run(options = '-n', arguments = '.', stdout = expect) s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE]) -test.fail_test(s != 0555) +test.fail_test(s != 0o555) s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE]) -test.fail_test(s != 0555) +test.fail_test(s != 0o555) test.must_not_exist('bar.out') s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) s = stat.S_IMODE(os.stat(test.workpath('d4'))[stat.ST_MODE]) -test.fail_test(s != 0555) +test.fail_test(s != 0o555) s = stat.S_IMODE(os.stat(test.workpath('f5'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) test.must_not_exist('f6.out') test.must_not_exist('f7.out') s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) test.must_not_exist('f8.out') s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE]) -test.fail_test(s != 0444) +test.fail_test(s != 0o444) s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE]) -test.fail_test(s != 0555) +test.fail_test(s != 0o555) s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE]) -test.fail_test(s != 0555) +test.fail_test(s != 0o555) test.run() s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE]) -test.fail_test(s != 0777) +test.fail_test(s != 0o777) s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE]) -test.fail_test(s != 0777) +test.fail_test(s != 0o777) test.must_match('bar.out', "bar.in\n") s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) s = stat.S_IMODE(os.stat(test.workpath('d4'))[stat.ST_MODE]) -test.fail_test(s != 0777) +test.fail_test(s != 0o777) s = stat.S_IMODE(os.stat(test.workpath('f5'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) test.must_match('f6.out', "f6.in\n") test.must_match('f7.out', "f7.in\n") s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) test.must_match('f8.out', "f8.in\n") s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE]) -test.fail_test(s != 0666) +test.fail_test(s != 0o666) s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE]) -test.fail_test(s != 0777) +test.fail_test(s != 0o777) s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE]) -test.fail_test(s != 0777) +test.fail_test(s != 0o777) test.pass_test() diff --git a/test/Configure/ConfigureDryRunError.py b/test/Configure/ConfigureDryRunError.py index b4be67e2..fa85042c 100644 --- a/test/Configure/ConfigureDryRunError.py +++ b/test/Configure/ConfigureDryRunError.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -97,7 +98,7 @@ test.checkLogAndStdout( ["Checking for C library %s... " % lib, newLog = test.read(test.workpath('config.log')) if newLog != oldLog: - print "Unexpected update of log file within a dry run" + print("Unexpected update of log file within a dry run") test.fail_test() test.pass_test() diff --git a/test/Configure/config-h.py b/test/Configure/config-h.py index cda6c3b9..ed950552 100644 --- a/test/Configure/config-h.py +++ b/test/Configure/config-h.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -135,19 +136,19 @@ test.run(stdout=expected_stdout) config_h = test.read(test.workpath('config.h')) if expected_config_h != config_h: - print "Unexpected config.h" - print "Expected: " - print "---------------------------------------------------------" - print repr(expected_config_h) - print "---------------------------------------------------------" - print "Found: " - print "---------------------------------------------------------" - print repr(config_h) - print "---------------------------------------------------------" - print "Stdio: " - print "---------------------------------------------------------" - print test.stdout() - print "---------------------------------------------------------" + print("Unexpected config.h") + print("Expected: ") + print("---------------------------------------------------------") + print(repr(expected_config_h)) + print("---------------------------------------------------------") + print("Found: ") + print("---------------------------------------------------------") + print(repr(config_h)) + print("---------------------------------------------------------") + print("Stdio: ") + print("---------------------------------------------------------") + print(test.stdout()) + print("---------------------------------------------------------") test.fail_test() expected_read_str = re.sub(r'\b((yes)|(no))\b', @@ -162,19 +163,19 @@ test.run(stdout=expected_stdout) config_h = test.read(test.workpath('config.h')) if expected_config_h != config_h: - print "Unexpected config.h" - print "Expected: " - print "---------------------------------------------------------" - print repr(expected_config_h) - print "---------------------------------------------------------" - print "Found: " - print "---------------------------------------------------------" - print repr(config_h) - print "---------------------------------------------------------" - print "Stdio: " - print "---------------------------------------------------------" - print test.stdout() - print "---------------------------------------------------------" + print("Unexpected config.h") + print("Expected: ") + print("---------------------------------------------------------") + print(repr(expected_config_h)) + print("---------------------------------------------------------") + print("Found: ") + print("---------------------------------------------------------") + print(repr(config_h)) + print("---------------------------------------------------------") + print("Stdio: ") + print("---------------------------------------------------------") + print(test.stdout()) + print("---------------------------------------------------------") test.fail_test() test.pass_test() diff --git a/test/Configure/implicit-cache.py b/test/Configure/implicit-cache.py index 0f04b1e4..1a9ff343 100644 --- a/test/Configure/implicit-cache.py +++ b/test/Configure/implicit-cache.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -93,11 +94,11 @@ test.run_sconsign('-d .sconf_temp -e conftest_0.c --raw .sconsign.dblite') new_sconsign_dblite = test.stdout() if old_sconsign_dblite != new_sconsign_dblite: - print ".sconsign.dblite did not match:" - print "FIRST RUN ==========" - print old_sconsign_dblite - print "SECOND RUN ==========" - print new_sconsign_dblite + print(".sconsign.dblite did not match:") + print("FIRST RUN ==========") + print(old_sconsign_dblite) + print("SECOND RUN ==========") + print(new_sconsign_dblite) test.fail_test() test.pass_test() diff --git a/test/Copy-Action.py b/test/Copy-Action.py index 51635c51..ded158a7 100644 --- a/test/Copy-Action.py +++ b/test/Copy-Action.py @@ -84,8 +84,8 @@ test.subdir('d5') test.write(['d5', 'f12.in'], "f12.in\n") test.write('f 13.in', "f 13.in\n") -os.chmod('f1.in', 0646) -os.chmod('f4.in', 0644) +os.chmod('f1.in', 0o646) +os.chmod('f4.in', 0o644) test.sleep() diff --git a/test/Deprecated/Options/Options.py b/test/Deprecated/Options/Options.py index 8116a636..61a12f3f 100644 --- a/test/Deprecated/Options/Options.py +++ b/test/Deprecated/Options/Options.py @@ -237,7 +237,7 @@ opts.Save('options.saved', env) def checkSave(file, expected): gdict = {} ldict = {} - exec open(file, 'rU').read() in gdict, ldict + exec(open(file, 'rU').read(), gdict, ldict) assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict) # First test with no command line options diff --git a/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py b/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py index 28b87616..29597363 100644 --- a/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py +++ b/test/Deprecated/SourceCode/BitKeeper/BitKeeper.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -67,7 +68,7 @@ test.subdir('BK', 'import', ['import', 'sub']) # Test using BitKeeper to fetch from SCCS/s.file files. sccs = test.where_is('sccs') if not sccs: - print "Could not find SCCS, skipping sub-test of BitKeeper using SCCS files." + print("Could not find SCCS, skipping sub-test of BitKeeper using SCCS files.") else: test.subdir('work1', ['work1', 'SCCS'], @@ -167,9 +168,9 @@ sub/fff.in 1.1 -> 1.2: 1 lines rcs = test.where_is('rcs') ci = test.where_is('ci') if not rcs: - print "Could not find RCS,\nskipping sub-test of BitKeeper using RCS files." + print("Could not find RCS,\nskipping sub-test of BitKeeper using RCS files.") elif not ci: - print "Could not find the RCS ci command,\nskipping sub-test of BitKeeper using RCS files." + print("Could not find the RCS ci command,\nskipping sub-test of BitKeeper using RCS files.") else: test.subdir('work2', ['work2', 'RCS'], diff --git a/test/Deprecated/SourceCode/Subversion.py b/test/Deprecated/SourceCode/Subversion.py index a97c86f2..7d45a8ca 100644 --- a/test/Deprecated/SourceCode/Subversion.py +++ b/test/Deprecated/SourceCode/Subversion.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -50,7 +51,7 @@ svnadmin = test.where_is('svnadmin') if not svn: test.skip_test("Could not find 'svnadmin'; skipping test(s).\n") -print "Short-circuiting this test until we support Subversion" +print("Short-circuiting this test until we support Subversion") test.pass_test() test.subdir('Subversion', 'import', ['import', 'sub'], 'work1', 'work2') diff --git a/test/GetBuildFailures/parallel.py b/test/GetBuildFailures/parallel.py index b7576af6..e746d531 100644 --- a/test/GetBuildFailures/parallel.py +++ b/test/GetBuildFailures/parallel.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function """ Verify that a failed build action with -j works as expected. @@ -102,8 +103,8 @@ error_45 = f4_error + f5_error error_54 = f5_error + f4_error if test.stderr() not in [error_45, error_54]: - print "Did not find the following output in list of expected strings:" - print test.stderr(), + print("Did not find the following output in list of expected strings:") + print(test.stderr(), end=' ') test.fail_test() # We jump through hoops above to try to make sure that the individual @@ -121,8 +122,8 @@ failed_45 = f4_failed + f5_failed failed_54 = f5_failed + f4_failed if test.stdout() not in [failed_45, failed_54]: - print "Did not find the following output in list of expected strings:" - print test.stdout(), + print("Did not find the following output in list of expected strings:") + print(test.stdout(), end=' ') test.fail_test() test.must_match(test.workpath('f3'), 'f3.in\n') diff --git a/test/Glob/glob-libpath.py b/test/Glob/glob-libpath.py index b09aab95..08780904 100644 --- a/test/Glob/glob-libpath.py +++ b/test/Glob/glob-libpath.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -77,10 +78,10 @@ test.write(['src', 'util', 'util.cpp'], """int i=0; test.run(arguments = '-Q .') if not test.match_re_dotall(test.stdout(), r".*(-L|/LIBPATH:)build[/\\]util.*"): - print repr(test.stdout())+" should contain -Lbuild/util or /LIBPATH:build\\util" + print(repr(test.stdout())+" should contain -Lbuild/util or /LIBPATH:build\\util") test.fail_test() if test.match_re_dotall(test.stdout(), r".*(-L|/LIBPATH:)src[/\\]util.*"): - print repr(test.stdout())+" should not contain -Lsrc/util or /LIBPATH:src\\util" + print(repr(test.stdout())+" should not contain -Lsrc/util or /LIBPATH:src\\util") test.fail_test() test.pass_test() diff --git a/test/Install/Install.py b/test/Install/Install.py index adadfd96..d66660ba 100644 --- a/test/Install/Install.py +++ b/test/Install/Install.py @@ -129,7 +129,7 @@ test.must_match(['work', 'f2.out'], "f2.in\n") # if a target can not be unlinked before building it: test.write(['work', 'f1.in'], "f1.in again again\n") -os.chmod(test.workpath('work', 'export'), 0555) +os.chmod(test.workpath('work', 'export'), 0o555) f = open(f1_out, 'rb') diff --git a/test/Interactive/version.py b/test/Interactive/version.py index 96ce51ed..d0f362ac 100644 --- a/test/Interactive/version.py +++ b/test/Interactive/version.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ @@ -72,7 +73,7 @@ expect2 = r"""scons>>> SCons by Steven Knight et al\.: stdout = test.stdout() + '\n' if not test.match_re(stdout, expect1) and not test.match_re(stdout, expect2): - print repr(stdout) + print(repr(stdout)) test.fail_test() diff --git a/test/Java/multi-step.py b/test/Java/multi-step.py index a8efcd46..44ebd317 100644 --- a/test/Java/multi-step.py +++ b/test/Java/multi-step.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -557,7 +558,7 @@ test.must_exist(['buildout', 'jni', 'SampleTest.java']) # it doesn't exist. p = test.workpath('buildout', 'jni', 'SampleTest.class') if not os.path.exists(p): - print 'Warning: %s does not exist' % p + print('Warning: %s does not exist' % p) test.up_to_date(arguments = '.') diff --git a/test/MSVC/batch-longlines.py b/test/MSVC/batch-longlines.py index ef7233b1..c584abac 100644 --- a/test/MSVC/batch-longlines.py +++ b/test/MSVC/batch-longlines.py @@ -1,61 +1,61 @@ -#!/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 operation of Visual C/C++ batch builds with long lines.
-
-Only runs on Windows.
-"""
-
-import TestSCons
-
-test = TestSCons.TestSCons()
-
-test.skip_if_not_msvc()
-
-_python_ = TestSCons._python_
-
-for i in xrange(1,200):
- test.write('source-file-with-quite-a-long-name-maybe-unrealistic-but-who-cares-%05d.cxx'%i,
- '/* source file %d */\nint var%d;\n'%(i,i))
-
-test.write('SConstruct', """
-env = Environment(tools=['msvc', 'mslink'],
- MSVC_BATCH=ARGUMENTS.get('MSVC_BATCH'))
-env.SharedLibrary('mylib', Glob('source*.cxx'))
-""" % locals())
-
-test.run(arguments = 'MSVC_BATCH=1 .')
-
-test.must_exist('mylib.dll')
-
-test.pass_test()
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
+#!/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 operation of Visual C/C++ batch builds with long lines. + +Only runs on Windows. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.skip_if_not_msvc() + +_python_ = TestSCons._python_ + +for i in range(1,200): + test.write('source-file-with-quite-a-long-name-maybe-unrealistic-but-who-cares-%05d.cxx'%i, + '/* source file %d */\nint var%d;\n'%(i,i)) + +test.write('SConstruct', """ +env = Environment(tools=['msvc', 'mslink'], + MSVC_BATCH=ARGUMENTS.get('MSVC_BATCH')) +env.SharedLibrary('mylib', Glob('source*.cxx')) +""" % locals()) + +test.run(arguments = 'MSVC_BATCH=1 .') + +test.must_exist('mylib.dll') + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/MSVC/msvc.py b/test/MSVC/msvc.py index c68fb45f..a70ed67f 100644 --- a/test/MSVC/msvc.py +++ b/test/MSVC/msvc.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -181,9 +182,9 @@ slow = time.time() - start # using precompiled headers should be faster limit = slow*0.90 if fast >= limit: - print "Using precompiled headers was not fast enough:" - print "slow.obj: %.3fs" % slow - print "fast.obj: %.3fs (expected less than %.3fs)" % (fast, limit) + print("Using precompiled headers was not fast enough:") + print("slow.obj: %.3fs" % slow) + print("fast.obj: %.3fs (expected less than %.3fs)" % (fast, limit)) test.fail_test() # Modifying resource.h should cause both the resource and precompiled header to be rebuilt: diff --git a/test/QT/copied-env.py b/test/QT/copied-env.py index efa91be6..39891439 100644 --- a/test/QT/copied-env.py +++ b/test/QT/copied-env.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -70,8 +71,8 @@ moc_MyForm = [x for x in test.stdout().split('\n') if x.find('moc_MyForm') != -1 MYLIB_IMPL = [x for x in moc_MyForm if x.find('MYLIB_IMPL') != -1] if not MYLIB_IMPL: - print "Did not find MYLIB_IMPL on moc_MyForm compilation line:" - print test.stdout() + print("Did not find MYLIB_IMPL on moc_MyForm compilation line:") + print(test.stdout()) test.fail_test() test.pass_test() diff --git a/test/QT/warnings.py b/test/QT/warnings.py index a861b24b..a1cf221f 100644 --- a/test/QT/warnings.py +++ b/test/QT/warnings.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -59,8 +60,8 @@ scons: warning: Generated moc file 'aaa.moc' is not included by 'aaa.cpp' """ + TestSCons.file_expr if not re.search(match12, test.stderr()): - print "Did not find expected regular expression in stderr:" - print test.stderr() + print("Did not find expected regular expression in stderr:") + print(test.stderr()) test.fail_test() os.environ['QTDIR'] = test.QT diff --git a/test/SConsignFile/use-dbhash.py b/test/SConsignFile/use-dbhash.py index 45e3e36f..bd9b7996 100644 --- a/test/SConsignFile/use-dbhash.py +++ b/test/SConsignFile/use-dbhash.py @@ -35,7 +35,7 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() try: - import dbhash + import dbm.bsd except ImportError: test.skip_test('No dbhash in this version of Python; skipping test.\n') diff --git a/test/SConsignFile/use-dbm.py b/test/SConsignFile/use-dbm.py index 75f088dc..90983b30 100644 --- a/test/SConsignFile/use-dbm.py +++ b/test/SConsignFile/use-dbm.py @@ -35,7 +35,7 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() try: - import dbm + import dbm.ndbm except ImportError: test.skip_test('No dbm in this version of Python; skipping test.\n') diff --git a/test/SConsignFile/use-dumbdbm.py b/test/SConsignFile/use-dumbdbm.py index 9d48fe5d..84f1dd44 100644 --- a/test/SConsignFile/use-dumbdbm.py +++ b/test/SConsignFile/use-dumbdbm.py @@ -35,7 +35,7 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() try: - import dumbdbm + import dbm.dumb except ImportError: test.skip_test('No dumbdbm in this version of Python; skipping test.\n') diff --git a/test/SConsignFile/use-gdbm.py b/test/SConsignFile/use-gdbm.py index 1eb36452..a7e4f59e 100644 --- a/test/SConsignFile/use-gdbm.py +++ b/test/SConsignFile/use-gdbm.py @@ -35,7 +35,7 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() try: - import gdbm + import dbm.gnu except ImportError: test.skip_test('No gdbm in this version of Python; skipping test.\n') diff --git a/test/SHELL.py b/test/SHELL.py index 93ed0b13..faee27fe 100644 --- a/test/SHELL.py +++ b/test/SHELL.py @@ -64,7 +64,7 @@ ofp.close() sys.exit(0) """ % locals()) -os.chmod(my_shell, 0755) +os.chmod(my_shell, 0o755) test.write('SConstruct', """\ env = Environment(SHELL = r'%(my_shell)s') diff --git a/test/Scanner/generated.py b/test/Scanner/generated.py index 845111ce..82206c2e 100644 --- a/test/Scanner/generated.py +++ b/test/Scanner/generated.py @@ -317,8 +317,8 @@ def write_out(file, dict): class CScannerCounter(object): def __init__(self, original_CScanner, *args, **kw): self.original_CScanner = original_CScanner - def __cmp__(self, *args, **kw): - return self.original_CScanner.__cmp__(*args, **kw) + def __eq__(self, *args, **kw): + return self.original_CScanner.__eq__(*args, **kw) def __hash__(self, *args, **kw): return self.original_CScanner.__hash__(*args, **kw) def __str__(self, *args, **kw): diff --git a/test/Scanner/unicode.py b/test/Scanner/unicode.py index 55e22bdd..2737f7db 100644 --- a/test/Scanner/unicode.py +++ b/test/Scanner/unicode.py @@ -35,12 +35,12 @@ _python_ = TestSCons._python_ test = TestSCons.TestSCons() -try: - unicode -except NameError: - import sys - msg = "Unicode not supported by Python version %s; skipping test\n" - test.skip_test(msg % sys.version[:3]) +## try: +## unicode +## except NameError: +## import sys +## msg = "Unicode not supported by Python version %s; skipping test\n" +## test.skip_test(msg % sys.version[:3]) import codecs @@ -102,28 +102,28 @@ include utf16be.k foo.k 1 line 4 """) -contents = unicode("""\ +contents = (u"""\ ascii.k 1 line 1 include ascii.inc ascii.k 1 line 3 """) test.write('ascii.k', contents.encode('ascii')) -contents = unicode("""\ +contents = (u"""\ utf8.k 1 line 1 include utf8.inc utf8.k 1 line 3 """) test.write('utf8.k', codecs.BOM_UTF8 + contents.encode('utf-8')) -contents = unicode("""\ +contents = (u"""\ utf16le.k 1 line 1 include utf16le.inc utf16le.k 1 line 3 """) test.write('utf16le.k', codecs.BOM_UTF16_LE + contents.encode('utf-16-le')) -contents = unicode("""\ +contents = (u"""\ utf16be.k 1 line 1 include utf16be.inc utf16be.k 1 line 3 diff --git a/test/TEMPFILEPREFIX.py b/test/TEMPFILEPREFIX.py index f9b3240f..8e756afb 100644 --- a/test/TEMPFILEPREFIX.py +++ b/test/TEMPFILEPREFIX.py @@ -45,7 +45,7 @@ print sys.argv echo_py = test.workpath('echo.py') st = os.stat(echo_py) -os.chmod(echo_py, st[stat.ST_MODE]|0111) +os.chmod(echo_py, st[stat.ST_MODE]|0o111) test.write('SConstruct', """ import os diff --git a/test/TEX/TEX.py b/test/TEX/TEX.py index 24d4bdd4..b7496903 100644 --- a/test/TEX/TEX.py +++ b/test/TEX/TEX.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -173,14 +174,14 @@ Run \texttt{latex}, then \texttt{bibtex}, then \texttt{latex} twice again \cite{ reruns = [x for x in output_lines if x.find('latex -interaction=nonstopmode -recorder rerun.tex') != -1] if len(reruns) != 2: - print "Expected 2 latex calls, got %s:" % len(reruns) - print '\n'.join(reruns) + print("Expected 2 latex calls, got %s:" % len(reruns)) + print('\n'.join(reruns)) test.fail_test() bibtex = [x for x in output_lines if x.find('bibtex bibtex-test') != -1] if len(bibtex) != 1: - print "Expected 1 bibtex call, got %s:" % len(bibtex) - print '\n'.join(bibtex) + print("Expected 1 bibtex call, got %s:" % len(bibtex)) + print('\n'.join(bibtex)) test.fail_test() test.pass_test() diff --git a/test/Value.py b/test/Value.py index f3ad4582..7abe7588 100644 --- a/test/Value.py +++ b/test/Value.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -81,7 +82,7 @@ open(sys.argv[-1],'wb').write(" ".join(sys.argv[1:-2])) # to make sure there's no difference in behavior. for source_signature in ['MD5', 'timestamp-newer']: - print "Testing Value node with source signatures:", source_signature + print("Testing Value node with source signatures:", source_signature) test.write('SConstruct', SConstruct_content % locals()) diff --git a/test/Variables/Variables.py b/test/Variables/Variables.py index 454e32e4..d0bf4320 100644 --- a/test/Variables/Variables.py +++ b/test/Variables/Variables.py @@ -231,7 +231,7 @@ opts.Save('variables.saved', env) def checkSave(file, expected): gdict = {} ldict = {} - exec open(file, 'rU').read() in gdict, ldict + exec(open(file, 'rU').read(), gdict, ldict) assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict) # First test with no command line variables diff --git a/test/WhereIs.py b/test/WhereIs.py index dc127b62..07c3f6c4 100644 --- a/test/WhereIs.py +++ b/test/WhereIs.py @@ -45,10 +45,10 @@ if sys.platform != 'win32': os.mkdir(sub2_xxx_exe) test.write(sub3_xxx_exe, "\n") -os.chmod(sub3_xxx_exe, 0777) +os.chmod(sub3_xxx_exe, 0o777) test.write(sub4_xxx_exe, "\n") -os.chmod(sub4_xxx_exe, 0777) +os.chmod(sub4_xxx_exe, 0o777) env_path = os.environ['PATH'] diff --git a/test/Win32/bad-drive.py b/test/Win32/bad-drive.py index f2a55b8c..4d0d6e9c 100644 --- a/test/Win32/bad-drive.py +++ b/test/Win32/bad-drive.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function """ This test verifies (on Windows systems) that we fail gracefully and @@ -50,8 +51,8 @@ for i in range(len(uppercase)-1, -1, -1): break if bad_drive is None: - print "All drive letters appear to be in use." - print "Cannot test SCons handling of invalid Windows drive letters." + print("All drive letters appear to be in use.") + print("Cannot test SCons handling of invalid Windows drive letters.") test.no_result(1); test.write('SConstruct', """ diff --git a/test/Win32/default-drive.py b/test/Win32/default-drive.py index f427a203..31253e45 100644 --- a/test/Win32/default-drive.py +++ b/test/Win32/default-drive.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function """ This test verifies (on Windows systems) that specifying an @@ -59,7 +60,7 @@ test.write(['src', 'file.in'], "src/file.in\n") build_file_out = test.workpath('build', 'file.out') -print os.path.splitdrive(build_file_out)[1] +print(os.path.splitdrive(build_file_out)[1]) test.run(chdir = 'src', arguments = os.path.splitdrive(build_file_out)[1]) diff --git a/test/ZIP/ZIP.py b/test/ZIP/ZIP.py index af2450b5..f2acad89 100644 --- a/test/ZIP/ZIP.py +++ b/test/ZIP/ZIP.py @@ -47,7 +47,7 @@ def zipfile_contains(zipfilename, names): for name in names: try: info=zf.getinfo(name) - except KeyError, e: # name not found + except KeyError as e: # name not found zf.close() return False return True diff --git a/test/ZIP/ZIPROOT.py b/test/ZIP/ZIPROOT.py index 96747a7a..f3e4496b 100644 --- a/test/ZIP/ZIPROOT.py +++ b/test/ZIP/ZIPROOT.py @@ -1,98 +1,98 @@ -#!/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__"
-
-import os
-import stat
-
-import TestSCons
-
-_python_ = TestSCons._python_
-
-test = TestSCons.TestSCons()
-
-import zipfile
-
-def zipfile_contains(zipfilename, names):
- """Returns True if zipfilename contains all the names, False otherwise."""
- zf=zipfile.ZipFile(zipfilename, 'r')
- if type(names)==type(''):
- names=[names]
- for name in names:
- try:
- info=zf.getinfo(name)
- except KeyError, e: # name not found
- zf.close()
- return False
- return True
-
-def zipfile_files(fname):
- """Returns all the filenames in zip file fname."""
- zf = zipfile.ZipFile(fname, 'r')
- return [x.filename for x in zf.infolist()]
-
-test.subdir('sub1')
-test.subdir(['sub1', 'sub2'])
-
-test.write('SConstruct', """
-env = Environment(tools = ['zip'])
-env.Zip(target = 'aaa.zip', source = ['sub1/file1'], ZIPROOT='sub1')
-env.Zip(target = 'bbb.zip', source = ['sub1/file2', 'sub1/sub2/file2'], ZIPROOT='sub1')
-""" % locals())
-
-test.write(['sub1', 'file1'], "file1\n")
-test.write(['sub1', 'file2'], "file2a\n")
-test.write(['sub1', 'sub2', 'file2'], "file2b\n")
-
-test.run(arguments = 'aaa.zip', stderr = None)
-
-test.must_exist('aaa.zip')
-
-# TEST: Zip file should contain 'file1', not 'sub1/file1', because of ZIPROOT.
-zf=zipfile.ZipFile('aaa.zip', 'r')
-test.fail_test(zf.testzip() is not None)
-zf.close()
-
-files=zipfile_files('aaa.zip')
-test.fail_test(zipfile_files('aaa.zip') != ['file1'],
- message='Zip file aaa.zip has wrong files: %s'%repr(files))
-
-###
-
-test.run(arguments = 'bbb.zip', stderr = None)
-
-test.must_exist('bbb.zip')
-
-# TEST: Zip file should contain 'sub2/file2', not 'sub1/sub2/file2', because of ZIPROOT.
-zf=zipfile.ZipFile('bbb.zip', 'r')
-test.fail_test(zf.testzip() is not None)
-zf.close()
-
-files=zipfile_files('bbb.zip')
-test.fail_test(zipfile_files('bbb.zip') != ['file2', 'sub2/file2'],
- message='Zip file bbb.zip has wrong files: %s'%repr(files))
-
-
-test.pass_test()
+#!/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__" + +import os +import stat + +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +import zipfile + +def zipfile_contains(zipfilename, names): + """Returns True if zipfilename contains all the names, False otherwise.""" + zf=zipfile.ZipFile(zipfilename, 'r') + if type(names)==type(''): + names=[names] + for name in names: + try: + info=zf.getinfo(name) + except KeyError as e: # name not found + zf.close() + return False + return True + +def zipfile_files(fname): + """Returns all the filenames in zip file fname.""" + zf = zipfile.ZipFile(fname, 'r') + return [x.filename for x in zf.infolist()] + +test.subdir('sub1') +test.subdir(['sub1', 'sub2']) + +test.write('SConstruct', """ +env = Environment(tools = ['zip']) +env.Zip(target = 'aaa.zip', source = ['sub1/file1'], ZIPROOT='sub1') +env.Zip(target = 'bbb.zip', source = ['sub1/file2', 'sub1/sub2/file2'], ZIPROOT='sub1') +""" % locals()) + +test.write(['sub1', 'file1'], "file1\n") +test.write(['sub1', 'file2'], "file2a\n") +test.write(['sub1', 'sub2', 'file2'], "file2b\n") + +test.run(arguments = 'aaa.zip', stderr = None) + +test.must_exist('aaa.zip') + +# TEST: Zip file should contain 'file1', not 'sub1/file1', because of ZIPROOT. +zf=zipfile.ZipFile('aaa.zip', 'r') +test.fail_test(zf.testzip() is not None) +zf.close() + +files=zipfile_files('aaa.zip') +test.fail_test(zipfile_files('aaa.zip') != ['file1'], + message='Zip file aaa.zip has wrong files: %s'%repr(files)) + +### + +test.run(arguments = 'bbb.zip', stderr = None) + +test.must_exist('bbb.zip') + +# TEST: Zip file should contain 'sub2/file2', not 'sub1/sub2/file2', because of ZIPROOT. +zf=zipfile.ZipFile('bbb.zip', 'r') +test.fail_test(zf.testzip() is not None) +zf.close() + +files=zipfile_files('bbb.zip') +test.fail_test(zipfile_files('bbb.zip') != ['file2', 'sub2/file2'], + message='Zip file bbb.zip has wrong files: %s'%repr(files)) + + +test.pass_test() diff --git a/test/gnutools.py b/test/gnutools.py index e1b7e42b..b0ebc1c0 100644 --- a/test/gnutools.py +++ b/test/gnutools.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -118,7 +119,7 @@ def testObject(test, obj, expect): line1 = contents.split('\n')[0] actual = ' '.join(line1.split()) if not expect == actual: - print "%s: %s != %s\n" % (obj, repr(expect), repr(actual)) + print("%s: %s != %s\n" % (obj, repr(expect), repr(actual))) test.fail_test() if sys.platform in ('win32', 'cygwin'): diff --git a/test/import.py b/test/import.py index ef5ee614..d1e1ecf4 100644 --- a/test/import.py +++ b/test/import.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -185,8 +186,8 @@ for tool in tools: matched = 1 break if not matched: - print "Failed importing '%s', stderr:" % tool - print stderr + print("Failed importing '%s', stderr:" % tool) + print(stderr) failures.append(tool) test.fail_test(len(failures)) diff --git a/test/long-lines/signature.py b/test/long-lines/signature.py index bc5d11a9..ce38bec8 100644 --- a/test/long-lines/signature.py +++ b/test/long-lines/signature.py @@ -51,7 +51,7 @@ fp.write('FILEFLAG=%s\\n' % args[2]) fp.write('TIMESTAMP=%s\\n' % args[3]) """) -os.chmod(build_py, 0755) +os.chmod(build_py, 0o755) test.write('SConstruct', """\ arg = 'a_long_ignored_argument' diff --git a/test/option--random.py b/test/option--random.py index a9b9b9d8..357cf2ec 100644 --- a/test/option--random.py +++ b/test/option--random.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -66,7 +67,7 @@ tries = 0 max_tries = 10 while test.stdout() == non_random_output: if tries >= max_tries: - print "--random generated the non-random output %s times!" % max_tries + print("--random generated the non-random output %s times!" % max_tries) test.fail_test() tries = tries + 1 test.run(arguments = '-n -Q --random') @@ -84,7 +85,7 @@ tries = 0 max_tries = 10 while test.stdout() == non_random_output: if tries >= max_tries: - print "--random generated the non-random output %s times!" % max_tries + print("--random generated the non-random output %s times!" % max_tries) test.fail_test() tries = tries + 1 test.run(arguments = '-n -Q --random') diff --git a/test/option-v.py b/test/option-v.py index f3eb61ce..4a67df03 100644 --- a/test/option-v.py +++ b/test/option-v.py @@ -21,6 +21,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -53,13 +54,13 @@ expect2 = r"""SCons by Steven Knight et al.: test.run(arguments = '-v') stdout = test.stdout() if not test.match_re(stdout, expect1) and not test.match_re(stdout, expect2): - print stdout + print(stdout) test.fail_test() test.run(arguments = '--version') stdout = test.stdout() if not test.match_re(stdout, expect1) and not test.match_re(stdout, expect2): - print stdout + print(stdout) test.fail_test() test.pass_test() diff --git a/test/option/debug-count.py b/test/option/debug-count.py index 3f8a23c0..ce790861 100644 --- a/test/option/debug-count.py +++ b/test/option/debug-count.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -74,10 +75,10 @@ for args in ['-h --debug=count', '--debug=count']: missing = [o for o in objects if find_object_count(o, stdout) is None] if missing: - print "Missing the following object lines from '%s' output:" % args - print "\t", ' '.join(missing) - print "STDOUT ==========" - print stdout + print("Missing the following object lines from '%s' output:" % args) + print("\t", ' '.join(missing)) + print("STDOUT ==========") + print(stdout) test.fail_test(1) expect_warning = """ diff --git a/test/option/debug-time.py b/test/option/debug-time.py index 198d71df..7dd17fe7 100644 --- a/test/option/debug-time.py +++ b/test/option/debug-time.py @@ -20,7 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import division +from __future__ import division, print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -164,7 +164,7 @@ outside of the 15%% tolerance. """ % locals()) if failures or warnings: - print '\n'.join([test.stdout()] + failures + warnings) + print('\n'.join([test.stdout()] + failures + warnings)) if failures: test.fail_test(1) @@ -172,7 +172,7 @@ test.run(arguments = "--debug=time . SLEEP=0") command_time = get_command_time(test.stdout()) if command_time != 0.0: - print "Up-to-date run received non-zero command time of %s" % command_time + print("Up-to-date run received non-zero command time of %s" % command_time) test.fail_test() @@ -201,14 +201,14 @@ outside of the 1%% tolerance. """ % locals()) if failures: - print '\n'.join([test.stdout()] + failures) + print('\n'.join([test.stdout()] + failures)) test.fail_test(1) test.run(arguments = "-j4 --debug=time . SLEEP=1") command_time = get_command_time(test.stdout()) if command_time != 0.0: - print "Up-to-date run received non-zero command time of %s" % command_time + print("Up-to-date run received non-zero command time of %s" % command_time) test.fail_test() diff --git a/test/option/help-options.py b/test/option/help-options.py index 45bbfa0d..e14eff20 100644 --- a/test/option/help-options.py +++ b/test/option/help-options.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" @@ -60,8 +61,8 @@ options = [x[-1] == ',' and x[:-1] or x for x in options] lowered = [x.lower() for x in options] ordered = sorted(lowered) if lowered != ordered: - print "lowered =", lowered - print "sorted =", ordered + print("lowered =", lowered) + print("sorted =", ordered) test.fail_test() test.pass_test() diff --git a/test/option/profile.py b/test/option/profile.py index d53c6900..97f84dbc 100644 --- a/test/option/profile.py +++ b/test/option/profile.py @@ -21,6 +21,8 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from six import u + __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys @@ -36,7 +38,7 @@ else: # when we drop support for Python 2.6. class StringIO(_StringIO): def write(self, s): - _StringIO.write(self, unicode(s)) + _StringIO.write(self, u(s)) import TestSCons diff --git a/test/scons-time/run/config/python.py b/test/scons-time/run/config/python.py index 6cf965b0..57b732d8 100644 --- a/test/scons-time/run/config/python.py +++ b/test/scons-time/run/config/python.py @@ -53,7 +53,7 @@ for arg in sys.argv[1:]: print 'my_python.py: %s' % profile """) -os.chmod(my_python_py, 0755) +os.chmod(my_python_py, 0o755) test.run(arguments = 'run -f config foo.tar.gz') diff --git a/test/scons-time/run/option/python.py b/test/scons-time/run/option/python.py index a28e23fb..70feb70a 100644 --- a/test/scons-time/run/option/python.py +++ b/test/scons-time/run/option/python.py @@ -49,7 +49,7 @@ for arg in sys.argv[1:]: sys.stdout.write('my_python.py: %s\\n' % profile) """) -os.chmod(my_python_py, 0755) +os.chmod(my_python_py, 0o755) test.run(arguments = 'run --python %s foo.tar.gz' % my_python_py) diff --git a/test/sconsign/nonwritable.py b/test/sconsign/nonwritable.py index 913dcf16..5ae55bbc 100644 --- a/test/sconsign/nonwritable.py +++ b/test/sconsign/nonwritable.py @@ -78,7 +78,7 @@ test.write(['work1', 'foo.in'], "work1/foo.in\n") test.write(work1__sconsign_dblite, "") -os.chmod(work1__sconsign_dblite, 0444) +os.chmod(work1__sconsign_dblite, 0o444) test.run(chdir='work1', arguments='.') @@ -95,7 +95,7 @@ test.write(['work2', 'foo.in'], "work2/foo.in\n") pickle.dump({}, open(work2_sub1__sconsign, 'wb'), 1) pickle.dump({}, open(work2_sub2__sconsign, 'wb'), 1) -os.chmod(work2_sub1__sconsign, 0444) +os.chmod(work2_sub1__sconsign, 0o444) test.run(chdir='work2', arguments='.') diff --git a/test/sconsign/script/SConsignFile.py b/test/sconsign/script/SConsignFile.py index a9f79f41..71a7e6dc 100644 --- a/test/sconsign/script/SConsignFile.py +++ b/test/sconsign/script/SConsignFile.py @@ -86,8 +86,8 @@ output.write(input.read()) sys.exit(0) """) -test.chmod(fake_cc_py, 0755) -test.chmod(fake_link_py, 0755) +test.chmod(fake_cc_py, 0o755) +test.chmod(fake_link_py, 0o755) # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are diff --git a/test/sconsign/script/Signatures.py b/test/sconsign/script/Signatures.py index cfd2a7f9..5babe676 100644 --- a/test/sconsign/script/Signatures.py +++ b/test/sconsign/script/Signatures.py @@ -105,8 +105,8 @@ output.write(input.read()) sys.exit(0) """) -test.chmod(fake_cc_py, 0755) -test.chmod(fake_link_py, 0755) +test.chmod(fake_cc_py, 0o755) +test.chmod(fake_link_py, 0o755) test.write('SConstruct', """ SConsignFile(None) diff --git a/test/sconsign/script/no-SConsignFile.py b/test/sconsign/script/no-SConsignFile.py index 829d650e..70b18c83 100644 --- a/test/sconsign/script/no-SConsignFile.py +++ b/test/sconsign/script/no-SConsignFile.py @@ -94,8 +94,8 @@ output.write(input.read()) sys.exit(0) """) -test.chmod(fake_cc_py, 0755) -test.chmod(fake_link_py, 0755) +test.chmod(fake_cc_py, 0o755) +test.chmod(fake_link_py, 0o755) # Note: We don't use os.path.join() representations of the file names # in the expected output because paths in the .sconsign files are diff --git a/test/site_scons/sysdirs.py b/test/site_scons/sysdirs.py index c05ef676..87f448da 100644 --- a/test/site_scons/sysdirs.py +++ b/test/site_scons/sysdirs.py @@ -1,71 +1,72 @@ -#!/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__"
-
-import TestSCons
-
-"""
-Verify site_scons system dirs are getting loaded.
-Uses an internal test fixture to get at the site_scons dirs.
-
-TODO: it would be great to test if it can actually load site_scons
-files from the system dirs, but the test harness can't put files in
-those dirs (which may not even exist on a build system).
-"""
-
-test = TestSCons.TestSCons()
-
-test.write('SConstruct', """
-import SCons.Script
-SCons.Script.Main.test_load_all_site_scons_dirs(Dir('.').path)
-""")
-
-test.run(arguments = '-Q .')
-
-import SCons.Platform
-platform = SCons.Platform.platform_default()
-if platform in ('win32', 'cygwin'):
- dir_to_check_for='Application Data'
-elif platform in ('darwin'):
- dir_to_check_for='Library'
-else:
- dir_to_check_for='.scons'
-
-if 'Loading site dir' not in test.stdout():
- print test.stdout()
- test.fail_test()
-if dir_to_check_for not in test.stdout():
- print test.stdout()
- test.fail_test()
-
-test.pass_test()
-
-# end of file
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
+#!/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. +# +from __future__ import print_function + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons + +""" +Verify site_scons system dirs are getting loaded. +Uses an internal test fixture to get at the site_scons dirs. + +TODO: it would be great to test if it can actually load site_scons +files from the system dirs, but the test harness can't put files in +those dirs (which may not even exist on a build system). +""" + +test = TestSCons.TestSCons() + +test.write('SConstruct', """ +import SCons.Script +SCons.Script.Main.test_load_all_site_scons_dirs(Dir('.').path) +""") + +test.run(arguments = '-Q .') + +import SCons.Platform +platform = SCons.Platform.platform_default() +if platform in ('win32', 'cygwin'): + dir_to_check_for='Application Data' +elif platform in ('darwin'): + dir_to_check_for='Library' +else: + dir_to_check_for='.scons' + +if 'Loading site dir' not in test.stdout(): + print(test.stdout()) + test.fail_test() +if dir_to_check_for not in test.stdout(): + print(test.stdout()) + test.fail_test() + +test.pass_test() + +# end of file + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/test/spaces.py b/test/spaces.py index db1ae975..13090474 100644 --- a/test/spaces.py +++ b/test/spaces.py @@ -36,7 +36,7 @@ if sys.platform == 'win32': else: test.write('duplicate a file.sh', 'cp foo.in foo.out\n') copy = test.workpath('duplicate a file.sh') - os.chmod(test.workpath('duplicate a file.sh'), 0777) + os.chmod(test.workpath('duplicate a file.sh'), 0o777) test.write('SConstruct', r''' diff --git a/test/subdivide.py b/test/subdivide.py index 2978e08b..44402c90 100644 --- a/test/subdivide.py +++ b/test/subdivide.py @@ -76,8 +76,8 @@ for s in sys.argv[2:]: ofp.write(open(s, 'rb').read()) """) -test.chmod(fake_cc_py, 0755) -test.chmod(fake_link_py, 0755) +test.chmod(fake_cc_py, 0o755) +test.chmod(fake_link_py, 0o755) test.write('SConstruct', """\ SConsignFile(None) diff --git a/timings/ElectricCloud/TimeSCons-run.py b/timings/ElectricCloud/TimeSCons-run.py index be75d121..130d9167 100644 --- a/timings/ElectricCloud/TimeSCons-run.py +++ b/timings/ElectricCloud/TimeSCons-run.py @@ -20,6 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function """ This configuration comes from the following blog article: @@ -87,7 +88,7 @@ test.run(program=test.workpath('genscons.pl'), arguments=' '.join(arguments)) # This print is nott for debugging, leave it alone! # We want to display the output from genscons.pl's generation the build # configuration, so the buildbot logs contain more info. -print test.stdout() +print(test.stdout()) test.main(chdir='sconsbld') diff --git a/www/gen_sched_table.py b/www/gen_sched_table.py index e67f0d74..85b1b817 100755 --- a/www/gen_sched_table.py +++ b/www/gen_sched_table.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import print_function import sys import datetime @@ -6,13 +7,13 @@ import datetime months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] -print '<table width="100%">' +print('<table width="100%">') def row(*cells, **kw): td = kw.get('tr','td') - print ' <tr>' + print(' <tr>') for cell in cells: - print ' <%s>%s</%s>' % (td,cell,td) - print ' </tr>' + print(' <%s>%s</%s>' % (td,cell,td)) + print(' </tr>') row('Estimated date', 'Type', 'Comments', tr = 'th') if len(sys.argv) > 1: @@ -30,7 +31,7 @@ for line in f: incr,type,desc = line[1:].strip().split(None,2) now = now + datetime.timedelta(int(incr)) else: - print 'dunna understand code', line[0] + print('dunna understand code', line[0]) sys.exit(1) #name = current + '.d' + str(now).replace('-','') date = '%s-%s-%s' % (now.day,months[now.month-1],now.year) @@ -41,7 +42,7 @@ for line in f: else: category = current = type row(date, category, desc) -print '</table>' +print('</table>') # Local Variables: # tab-width:4 |