summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2017-05-08 19:43:25 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2017-05-08 19:43:25 (GMT)
commit1976be7b15db2b89bf7c6361ea28806824c9c399 (patch)
tree0c8c5591ff3c06456615358417a9688dc6231699
parent8c13f3194dc2e59c0322021630032441793b6d94 (diff)
parent6b86f7db0794b07ad5023fa96b041590a89a8d77 (diff)
downloadSCons-1976be7b15db2b89bf7c6361ea28806824c9c399.zip
SCons-1976be7b15db2b89bf7c6361ea28806824c9c399.tar.gz
SCons-1976be7b15db2b89bf7c6361ea28806824c9c399.tar.bz2
merge
-rw-r--r--QMTest/TestCmd.py22
-rw-r--r--QMTest/TestSCons.py49
-rw-r--r--SConstruct36
-rwxr-xr-xruntest.py1
-rw-r--r--src/CHANGES.txt15
-rw-r--r--src/engine/MANIFEST.in3
-rw-r--r--src/engine/SCons/Defaults.py8
-rw-r--r--src/engine/SCons/Node/FS.py84
-rw-r--r--src/engine/SCons/Node/FSTests.py33
-rw-r--r--src/engine/SCons/Node/Python.py17
-rw-r--r--src/engine/SCons/Node/PythonTests.py6
-rw-r--r--src/engine/SCons/Platform/darwin.py4
-rw-r--r--src/engine/SCons/SConf.py8
-rw-r--r--src/engine/SCons/SConfTests.py45
-rw-r--r--src/engine/SCons/Scanner/LaTeX.py5
-rw-r--r--src/engine/SCons/Script/Main.py10
-rw-r--r--src/engine/SCons/Script/SConscript.py7
-rw-r--r--src/engine/SCons/Sig.py63
-rw-r--r--src/engine/SCons/Taskmaster.py10
-rw-r--r--src/engine/SCons/Tool/GettextCommon.py650
-rw-r--r--src/engine/SCons/Tool/__init__.py1
-rw-r--r--src/engine/SCons/Tool/applelink.py8
-rw-r--r--src/engine/SCons/Tool/docbook/__init__.py15
-rw-r--r--src/engine/SCons/Tool/link.py4
-rw-r--r--src/engine/SCons/Tool/msvs.xml10
-rw-r--r--src/engine/SCons/Tool/textfile.py6
-rw-r--r--src/engine/SCons/Tool/xgettext.py544
-rw-r--r--src/engine/SCons/Util.py18
-rw-r--r--src/script/sconsign.py5
-rw-r--r--test/CPPDEFINES/append.py18
-rw-r--r--test/CPPDEFINES/pkg-config.py18
-rw-r--r--test/D/MixedDAndC/sconstest-dmd.py10
-rw-r--r--test/Deprecated/Sig.py68
-rw-r--r--test/Errors/InternalError.py2
-rw-r--r--test/GetBuildFailures/option-k.py2
-rw-r--r--test/GetBuildFailures/parallel.py2
-rw-r--r--test/LINK/VersionedLib-VariantDir.py10
-rw-r--r--test/LINK/VersionedLib-j2.py5
-rw-r--r--test/LINK/VersionedLib-subdir.py5
-rw-r--r--test/LINK/VersionedLib.py6
-rw-r--r--test/MSVS/vs-10.0-scc-files.py4
-rw-r--r--test/MSVS/vs-11.0-scc-files.py4
-rw-r--r--test/MSVS/vs-14.0-scc-files.py4
-rw-r--r--test/MSVS/vs-7.0-scc-files.py4
-rw-r--r--test/MSVS/vs-7.1-scc-files.py4
-rw-r--r--test/MSVS/vs-8.0-scc-files.py4
-rw-r--r--test/MSVS/vs-9.0-scc-files.py4
-rw-r--r--test/Progress/TARGET.py4
-rw-r--r--test/Progress/spinner.py5
-rw-r--r--test/SConsignFile/use-dbm.py12
-rw-r--r--test/SWIG/recursive-includes-cpp.py4
-rw-r--r--test/Subst/TypeError.py4
-rw-r--r--test/TEX/auxiliaries.py4
-rw-r--r--test/diskcheck.py24
-rw-r--r--test/gettext/POTUpdate/UserExamples.py40
-rw-r--r--test/gettext/POUpdate/UserExamples.py36
-rw-r--r--test/gettext/Translate/UserExamples.py28
-rw-r--r--test/leaky-handles.py3
-rw-r--r--test/option--max-drift.py4
-rw-r--r--test/option--tree.py24
-rw-r--r--test/option-j.py2
-rw-r--r--test/packaging/use-builddir.py2
-rw-r--r--test/redirection.py17
-rw-r--r--test/scons-time/run/option/verbose.py6
64 files changed, 1064 insertions, 1016 deletions
diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py
index 2c0c0d3..20f1f14 100644
--- a/QMTest/TestCmd.py
+++ b/QMTest/TestCmd.py
@@ -453,13 +453,17 @@ def pass_test(self = None, condition = 1, function = None):
sys.exit(0)
-def match_exact(lines = None, matches = None):
+def match_exact(lines = None, matches = None, newline = '\n'):
"""
"""
+
+ if isinstance(lines, bytes) or bytes is str:
+ newline = to_bytes('\n')
+
if not is_List(lines):
- lines = lines.split("\n")
+ lines = lines.split(newline)
if not is_List(matches):
- matches = matches.split("\n")
+ matches = matches.split(newline)
if len(lines) != len(matches):
return
for i in range(len(lines)):
@@ -737,16 +741,6 @@ class Popen(subprocess.Popen):
setattr(self, which, None)
- def to_bytes (s):
- if isinstance (s, bytes) or bytes is str:
- return s
- return bytes (s, 'utf-8')
-
- def to_str (s):
- if bytes is str or is_String(s):
- return s
- return str (s, 'utf-8')
-
if sys.platform == 'win32':# and subprocess.mswindows:
def send(self, input):
input = to_bytes(input)
@@ -993,7 +987,7 @@ class TestCmd(object):
condition = self.condition
if self._preserve[condition]:
for dir in self._dirlist:
- print("Preserved directory " + dir + "\n")
+ print(u"Preserved directory " + dir + "\n")
else:
list = self._dirlist[:]
list.reverse()
diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py
index b6366a6..9c89249 100644
--- a/QMTest/TestSCons.py
+++ b/QMTest/TestSCons.py
@@ -598,23 +598,33 @@ class TestSCons(TestCommon):
return s
+ @staticmethod
+ def to_bytes_re_sub(pattern, repl, str, count=0, flags=0):
+ """
+ Wrapper around re.sub to change pattern and repl to bytes to work with
+ both python 2 & 3
+ """
+ pattern = to_bytes(pattern)
+ repl = to_bytes(repl)
+ return re.sub(pattern, repl, str, count, flags)
+
def normalize_pdf(self, s):
- s = re.sub(r'/(Creation|Mod)Date \(D:[^)]*\)',
- r'/\1Date (D:XXXX)', s)
- s = re.sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]',
- r'/ID [<XXXX> <XXXX>]', s)
- s = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}',
- r'/\1 /XXXXXX', s)
- s = re.sub(r'/Length \d+ *\n/Filter /FlateDecode\n',
- r'/Length XXXX\n/Filter /FlateDecode\n', s)
+ s = self.to_bytes_re_sub(r'/(Creation|Mod)Date \(D:[^)]*\)',
+ r'/\1Date (D:XXXX)', s)
+ s = self.to_bytes_re_sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]',
+ r'/ID [<XXXX> <XXXX>]', s)
+ s = self.to_bytes_re_sub(r'/(BaseFont|FontName) /[A-Z]{6}',
+ r'/\1 /XXXXXX', s)
+ s = self.to_bytes_re_sub(r'/Length \d+ *\n/Filter /FlateDecode\n',
+ r'/Length XXXX\n/Filter /FlateDecode\n', s)
try:
import zlib
except ImportError:
pass
else:
- begin_marker = '/FlateDecode\n>>\nstream\n'
- end_marker = 'endstream\nendobj'
+ begin_marker = to_bytes('/FlateDecode\n>>\nstream\n')
+ end_marker = to_bytes('endstream\nendobj')
encoded = []
b = s.find(begin_marker, 0)
@@ -629,16 +639,16 @@ class TestSCons(TestCommon):
for b, e in encoded:
r.append(s[x:b])
d = zlib.decompress(s[b:e])
- d = re.sub(r'%%CreationDate: [^\n]*\n',
- r'%%CreationDate: 1970 Jan 01 00:00:00\n', d)
- d = re.sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d',
- r'%DVIPSSource: TeX output 1970.01.01:0000', d)
- d = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}',
- r'/\1 /XXXXXX', d)
+ d = self.to_bytes_re_sub(r'%%CreationDate: [^\n]*\n',
+ r'%%CreationDate: 1970 Jan 01 00:00:00\n', d)
+ d = self.to_bytes_re_sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d',
+ r'%DVIPSSource: TeX output 1970.01.01:0000', d)
+ d = self.to_bytes_re_sub(r'/(BaseFont|FontName) /[A-Z]{6}',
+ r'/\1 /XXXXXX', d)
r.append(d)
x = e
r.append(s[x:])
- s = ''.join(r)
+ s = to_bytes('').join(r)
return s
@@ -1236,7 +1246,10 @@ try:
import distutils.sysconfig
exec_prefix = distutils.sysconfig.EXEC_PREFIX
print(distutils.sysconfig.get_python_inc())
- print(os.path.join(exec_prefix, 'libs'))
+ lib_path = os.path.join(exec_prefix, 'libs')
+ if not os.path.exists(lib_path):
+ lib_path = os.path.join(exec_prefix, 'lib')
+ print(lib_path)
except:
print(os.path.join(sys.prefix, 'include', py_ver))
print(os.path.join(sys.prefix, 'lib', py_ver, 'config'))
diff --git a/SConstruct b/SConstruct
index 08f7da5..bd43f19 100644
--- a/SConstruct
+++ b/SConstruct
@@ -162,6 +162,15 @@ import distutils.command
no_winpack_templates = not os.path.exists(os.path.join(os.path.split(distutils.command.__file__)[0],'wininst-9.0.exe'))
skip_win_packages = ARGUMENTS.get('SKIP_WIN_PACKAGES',False) or no_winpack_templates
+
+if sys.version_info[0] > 2:
+ # TODO: Resolve this issue. Currently fails when run on windows with
+ # File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/distutils/command/bdist_wininst.py", line 262, in create_exe
+ # cfgdata = cfgdata.encode("mbcs")
+ # LookupError: unknown encoding: mbcs
+ print("Temporary PY3: Skipping windows package builds")
+ skip_win_packages = True
+
if skip_win_packages:
print("Skipping the build of Windows packages...")
@@ -327,17 +336,20 @@ try:
def zipit(env, target, source):
print("Zipping %s:" % str(target[0]))
- def visit(arg, dirname, names):
- for name in names:
- path = os.path.join(dirname, name)
+ def visit(arg, dirname, filenames):
+ for filename in filenames:
+ path = os.path.join(dirname, filename)
if os.path.isfile(path):
arg.write(path)
# default ZipFile compression is ZIP_STORED
zf = zipfile.ZipFile(str(target[0]), 'w', compression=zipfile.ZIP_DEFLATED)
olddir = os.getcwd()
os.chdir(env['CD'])
- try: os.path.walk(env['PSV'], visit, zf)
- finally: os.chdir(olddir)
+ try:
+ for dirname, dirnames, filenames in os.walk(env['PSV']):
+ visit(zf, dirname, filenames)
+ finally:
+ os.chdir(olddir)
zf.close()
def unzipit(env, target, source):
@@ -364,6 +376,7 @@ except ImportError:
zipit = "cd $CD && $ZIP $ZIPFLAGS $( ${TARGET.abspath} $) $PSV"
unzipit = "$UNZIP $UNZIPFLAGS $SOURCES"
+
def SCons_revision(target, source, env):
"""Interpolate specific values from the environment into a file.
@@ -372,7 +385,7 @@ def SCons_revision(target, source, env):
"""
t = str(target[0])
s = source[0].rstr()
- with open(s, 'rb') as fp:
+ with open(s, 'r') as fp:
contents = fp.read()
# Note: We construct the __*__ substitution strings here
# so that they don't get replaced when this file gets
@@ -387,9 +400,10 @@ def SCons_revision(target, source, env):
contents = contents.replace('__REVISION' + '__', env['REVISION'])
contents = contents.replace('__VERSION' + '__', env['VERSION'])
contents = contents.replace('__NULL' + '__', '')
- open(t, 'wb').write(contents)
+ open(t, 'w').write(contents)
os.chmod(t, os.stat(s)[0])
+
revaction = SCons_revision
revbuilder = Builder(action = Action(SCons_revision,
varlist=['COPYRIGHT', 'VERSION']))
@@ -819,6 +833,7 @@ for p in [ scons ]:
s = p['filemap'].get(b, b)
if not s[0] == '$' and not os.path.isabs(s):
s = os.path.join(src, s)
+
builder = p['buildermap'].get(b, env.SCons_revision)
x = builder(os.path.join(build, b), s)
Local(x)
@@ -835,7 +850,7 @@ for p in [ scons ]:
def write_src_files(target, source, **kw):
global src_files
src_files.sort()
- f = open(str(target[0]), 'wb')
+ f = open(str(target[0]), 'w')
for file in src_files:
f.write(file + "\n")
f.close()
@@ -1017,10 +1032,10 @@ for p in [ scons ]:
list generated from our MANIFEST(s), so we don't have to
maintain multiple lists.
"""
- c = open(str(source[0]), 'rb').read()
+ c = open(str(source[0]), 'r').read()
c = c.replace('__VERSION' + '__', env['VERSION'])
c = c.replace('__RPM_FILES' + '__', env['RPM_FILES'])
- open(str(target[0]), 'wb').write(c)
+ open(str(target[0]), 'w').write(c)
rpm_files.sort()
rpm_files_str = "\n".join(rpm_files) + "\n"
@@ -1391,3 +1406,4 @@ for pf, help_text in packaging_flavors:
os.path.join(build_dir, 'runtest.py'),
])
+
diff --git a/runtest.py b/runtest.py
index 0d9bbaf..18d4121 100755
--- a/runtest.py
+++ b/runtest.py
@@ -686,6 +686,7 @@ if testlistfile:
tests = [x for x in tests if x[0] != '#']
tests = [x[:-1] for x in tests]
tests = [x.strip() for x in tests]
+ tests = [x for x in tests if len(x) > 0]
else:
testpaths = []
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index cb6ab21..9e6151a 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -13,6 +13,16 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
RELEASE VERSION/DATE TO BE FILLED IN LATER
+ From Daniel Moody:
+ - Updated the QMTest/TestCmd.py so when using the
+ preserve option, it will be able to print unicode directories.
+ - Also updated test/scons-time/run/option/verbose.py that was
+ not taking into account the output when PRESERVE was enabled
+
+ From Gaurav Juvekar:
+ - Fix issue #2910: Make --tree=all handle Unicode. (PR #427)
+ - Fix issue #2788: Fix typo in documentation example for sconf. (PR #388)
+
From Manish Vachharajani:
- Update debian rules, compat, and control to not use features
deprecated or obsolete in later versions of debhelpers
@@ -36,6 +46,11 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
From William Deegan:
- Removed deprecated tools CVS, Perforce, BitKeeper, RCS, SCCS, Subversion.
+ - Removed deprecated module SCons.Sig
+ - Added prioritized list of xsltproc tools to docbook. The order will now be as
+ follows: xsltproc, saxon, saxon-xslt, xalan (with first being highest priority, first
+ tool found is used)
+ - Fixed MSVSProject example code (http://scons.tigris.org/issues/show_bug.cgi?id=2979)
From Daniel Moody:
- Fixed msvs.py for Visual Studio generated projects which were
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index af91b7c..32f4965 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -47,7 +47,6 @@ SCons/Script/Interactive.py
SCons/Script/Main.py
SCons/Script/SConscript.py
SCons/Script/SConsOptions.py
-SCons/Sig.py
SCons/Subst.py
SCons/Taskmaster.py
SCons/Tool/__init__.py
@@ -170,7 +169,7 @@ SCons/Variables/PackageVariable.py
SCons/Variables/PathVariable.py
SCons/Warnings.py
SCons/Tool/GettextCommon.py
-SCons/Tool/gettext.py
+SCons/Tool/gettext_tool.py
SCons/Tool/msgfmt.py
SCons/Tool/msginit.py
SCons/Tool/msgmerge.py
diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py
index f1d5bca..69d5c94 100644
--- a/src/engine/SCons/Defaults.py
+++ b/src/engine/SCons/Defaults.py
@@ -264,7 +264,10 @@ def copy_func(dest, src, symlinks=True):
shutil.copy2(src, dest)
return 0
else:
- return shutil.copytree(src, dest, symlinks)
+ shutil.copytree(src, dest, symlinks)
+ # copytree returns None in python2 and destination string in python3
+ # A error is raised in both cases, so we can just return 0 for success
+ return 0
Copy = ActionFactory(
copy_func,
@@ -485,6 +488,7 @@ def processDefines(defs):
l = [str(defs)]
return l
+
def _defines(prefix, defs, suffix, env, c=_concat_ixes):
"""A wrapper around _concat_ixes that turns a list or string
into a list of C preprocessor command-line definitions.
@@ -492,6 +496,7 @@ def _defines(prefix, defs, suffix, env, c=_concat_ixes):
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
+
class NullCmdGenerator(object):
"""This is a callable class that can be used in place of other
command generators if you don't want them to do anything.
@@ -510,6 +515,7 @@ class NullCmdGenerator(object):
def __call__(self, target, source, env, for_signature=None):
return self.cmd
+
class Variable_Method_Caller(object):
"""A class for finding a construction variable on the stack and
calling one of its methods.
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 33e4a2d..64b2e3f 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -351,33 +351,6 @@ class _Null(object):
_null = _Null()
-DefaultSCCSBuilder = None
-DefaultRCSBuilder = None
-
-def get_DefaultSCCSBuilder():
- global DefaultSCCSBuilder
- if DefaultSCCSBuilder is None:
- import SCons.Builder
- # "env" will get filled in by Executor.get_build_env()
- # calling SCons.Defaults.DefaultEnvironment() when necessary.
- act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR')
- DefaultSCCSBuilder = SCons.Builder.Builder(action = act,
- env = None,
- name = "DefaultSCCSBuilder")
- return DefaultSCCSBuilder
-
-def get_DefaultRCSBuilder():
- global DefaultRCSBuilder
- if DefaultRCSBuilder is None:
- import SCons.Builder
- # "env" will get filled in by Executor.get_build_env()
- # calling SCons.Defaults.DefaultEnvironment() when necessary.
- act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR')
- DefaultRCSBuilder = SCons.Builder.Builder(action = act,
- env = None,
- name = "DefaultRCSBuilder")
- return DefaultRCSBuilder
-
# Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem.
_is_cygwin = sys.platform == "cygwin"
if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin:
@@ -422,46 +395,12 @@ def do_diskcheck_match(node, predicate, errorfmt):
def ignore_diskcheck_match(node, predicate, errorfmt):
pass
-def do_diskcheck_rcs(node, name):
- try:
- rcs_dir = node.rcs_dir
- except AttributeError:
- if node.entry_exists_on_disk('RCS'):
- rcs_dir = node.Dir('RCS')
- else:
- rcs_dir = None
- node.rcs_dir = rcs_dir
- if rcs_dir:
- return rcs_dir.entry_exists_on_disk(name+',v')
- return None
-
-def ignore_diskcheck_rcs(node, name):
- return None
-
-def do_diskcheck_sccs(node, name):
- try:
- sccs_dir = node.sccs_dir
- except AttributeError:
- if node.entry_exists_on_disk('SCCS'):
- sccs_dir = node.Dir('SCCS')
- else:
- sccs_dir = None
- node.sccs_dir = sccs_dir
- if sccs_dir:
- return sccs_dir.entry_exists_on_disk('s.'+name)
- return None
-def ignore_diskcheck_sccs(node, name):
- return None
diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match)
-diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs)
-diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs)
diskcheckers = [
diskcheck_match,
- diskcheck_rcs,
- diskcheck_sccs,
]
def set_diskcheck(list):
@@ -477,6 +416,11 @@ class EntryProxy(SCons.Util.Proxy):
__str__ = SCons.Util.Delegate('__str__')
+ # In PY3 if a class defines __eq__, then it must explicitly provide
+ # __hash__. Since SCons.Util.Proxy provides __eq__ we need the following
+ # see: https://docs.python.org/3.1/reference/datamodel.html#object.__hash__
+ __hash__ = SCons.Util.Delegate('__hash__')
+
def __get_abspath(self):
entry = self.get()
return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(),
@@ -574,6 +518,7 @@ class EntryProxy(SCons.Util.Proxy):
else:
return attr_function(self)
+
class Base(SCons.Node.Node):
"""A generic class for file system entries. This class is for
when we don't know yet whether the entry being looked up is a file
@@ -976,8 +921,6 @@ class Entry(Base):
'root',
'dirname',
'on_disk_entries',
- 'sccs_dir',
- 'rcs_dir',
'released_target_info',
'contentsig']
@@ -1523,8 +1466,6 @@ class Dir(Base):
'root',
'dirname',
'on_disk_entries',
- 'sccs_dir',
- 'rcs_dir',
'released_target_info',
'contentsig']
@@ -2090,9 +2031,7 @@ class Dir(Base):
return node
def file_on_disk(self, name):
- if self.entry_exists_on_disk(name) or \
- diskcheck_rcs(self, name) or \
- diskcheck_sccs(self, name):
+ if self.entry_exists_on_disk(name):
try: return self.File(name)
except TypeError: pass
node = self.srcdir_duplicate(name)
@@ -2589,8 +2528,6 @@ class File(Base):
'root',
'dirname',
'on_disk_entries',
- 'sccs_dir',
- 'rcs_dir',
'released_target_info',
'contentsig']
@@ -3031,12 +2968,7 @@ class File(Base):
return None
scb = self.dir.src_builder()
if scb is _null:
- if diskcheck_sccs(self.dir, self.name):
- scb = get_DefaultSCCSBuilder()
- elif diskcheck_rcs(self.dir, self.name):
- scb = get_DefaultRCSBuilder()
- else:
- scb = None
+ scb = None
if scb is not None:
try:
b = self.builder
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 7366b7b..306f1a2 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -3269,18 +3269,11 @@ class has_src_builderTestCase(unittest.TestCase):
fs = SCons.Node.FS.FS(test.workpath(''))
os.chdir(test.workpath(''))
test.subdir('sub1')
- test.subdir('sub2', ['sub2', 'SCCS'], ['sub2', 'RCS'])
sub1 = fs.Dir('sub1', '.')
f1 = fs.File('f1', sub1)
f2 = fs.File('f2', sub1)
f3 = fs.File('f3', sub1)
- sub2 = fs.Dir('sub2', '.')
- f4 = fs.File('f4', sub2)
- f5 = fs.File('f5', sub2)
- f6 = fs.File('f6', sub2)
- f7 = fs.File('f7', sub2)
- f8 = fs.File('f8', sub2)
h = f1.has_src_builder()
assert not h, h
@@ -3305,32 +3298,6 @@ class has_src_builderTestCase(unittest.TestCase):
assert h, h
assert f3.builder is b1, f3.builder
- f7.set_src_builder(b1)
- f8.builder_set(b1)
-
- test.write(['sub2', 'SCCS', 's.f5'], "sub2/SCCS/s.f5\n")
- test.write(['sub2', 'RCS', 'f6,v'], "sub2/RCS/f6,v\n")
- h = f4.has_src_builder()
- assert not h, h
- h = f4.has_builder()
- assert not h, h
- h = f5.has_src_builder()
- assert h, h
- h = f5.has_builder()
- assert h, h
- h = f6.has_src_builder()
- assert h, h
- h = f6.has_builder()
- assert h, h
- h = f7.has_src_builder()
- assert h, h
- h = f7.has_builder()
- assert h, h
- h = f8.has_src_builder()
- assert not h, h
- h = f8.has_builder()
- assert h, h
-
class prepareTestCase(unittest.TestCase):
def runTest(self):
"""Test the prepare() method"""
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
index f151fc5..8c47c97 100644
--- a/src/engine/SCons/Node/Python.py
+++ b/src/engine/SCons/Node/Python.py
@@ -58,7 +58,7 @@ class ValueNodeInfo(SCons.Node.NodeInfoBase):
del state['__weakref__']
except KeyError:
pass
-
+
return state
def __setstate__(self, state):
@@ -77,7 +77,7 @@ class ValueBuildInfo(SCons.Node.BuildInfoBase):
current_version_id = 2
class Value(SCons.Node.Node):
- """A class for Python variables, typically passed on the command line
+ """A class for Python variables, typically passed on the command line
or generated by a script, but not from a file or some other source.
"""
@@ -108,7 +108,7 @@ class Value(SCons.Node.Node):
is_up_to_date = SCons.Node.Node.children_are_up_to_date
def is_under(self, dir):
- # Make Value nodes get built regardless of
+ # Make Value nodes get built regardless of
# what directory scons was run from. Value nodes
# are outside the filesystem:
return 1
@@ -133,10 +133,17 @@ class Value(SCons.Node.Node):
###TODO: something reasonable about universal newlines
contents = str(self.value)
for kid in self.children(None):
- contents = contents + kid.get_contents()
+ contents = contents + kid.get_contents().decode()
return contents
- get_contents = get_text_contents ###TODO should return 'bytes' value
+ def get_contents(self):
+ text_contents = self.get_text_contents()
+ try:
+ return text_contents.encode()
+ except UnicodeDecodeError:
+ # Already encoded as python2 str are bytes
+ return text_contents
+
def changed_since_last_build(self, target, prev_ni):
cur_csig = self.get_csig()
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
index e2e36bf..346542b 100644
--- a/src/engine/SCons/Node/PythonTests.py
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -90,15 +90,15 @@ class ValueTestCase(unittest.TestCase):
"""
v1 = SCons.Node.Python.Value('aaa')
csig = v1.get_csig(None)
- assert csig == 'aaa', csig
+ assert csig.decode() == 'aaa', csig
v2 = SCons.Node.Python.Value(7)
csig = v2.get_csig(None)
- assert csig == '7', csig
+ assert csig.decode() == '7', csig
v3 = SCons.Node.Python.Value(None)
csig = v3.get_csig(None)
- assert csig == 'None', csig
+ assert csig.decode() == 'None', csig
class ValueNodeInfoTestCase(unittest.TestCase):
def test___init__(self):
diff --git a/src/engine/SCons/Platform/darwin.py b/src/engine/SCons/Platform/darwin.py
index 1cf4aeb..c85b75b 100644
--- a/src/engine/SCons/Platform/darwin.py
+++ b/src/engine/SCons/Platform/darwin.py
@@ -63,6 +63,10 @@ def generate(env):
env.AppendENVPath('PATHOSX', line.strip('\n'))
f.close()
+ # Not sure why this wasn't the case all along?
+ if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False):
+ env.AppendENVPath('PATH',env['ENV']['PATHOSX'])
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index 31d9402..889af4a 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -110,7 +110,7 @@ def _createConfigH(target, source, env):
#define %(DEFNAME)s_SEEN
""" % {'DEFNAME' : defname})
- t.write(source[0].get_contents())
+ t.write(source[0].get_contents().decode())
t.write("""
#endif /* %(DEFNAME)s_SEEN */
""" % {'DEFNAME' : defname})
@@ -164,11 +164,11 @@ class ConfigureCacheError(SConfError):
# define actions for building text files
def _createSource( target, source, env ):
fd = open(str(target[0]), "w")
- fd.write(source[0].get_contents())
+ fd.write(source[0].get_contents().decode())
fd.close()
def _stringSource( target, source, env ):
return (str(target[0]) + ' <-\n |' +
- source[0].get_contents().replace( '\n', "\n |" ) )
+ source[0].get_contents().decode().replace( '\n', "\n |" ) )
class SConfBuildInfo(SCons.Node.FS.FileBuildInfo):
"""
@@ -609,7 +609,7 @@ class SConfBase(object):
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
del self.env['BUILDERS']['SConfActionBuilder']
if ok:
- outputStr = self.lastTarget.get_contents()
+ outputStr = self.lastTarget.get_contents().decode()
return (1, outputStr)
return (0, "")
diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py
index b2aa3b4..f4c6f89 100644
--- a/src/engine/SCons/SConfTests.py
+++ b/src/engine/SCons/SConfTests.py
@@ -48,7 +48,7 @@ class SConfTestCase(unittest.TestCase):
def setUp(self):
# we always want to start with a clean directory
self.save_cwd = os.getcwd()
- self.test = TestCmd.TestCmd(workdir = '')
+ self.test = TestCmd.TestCmd(workdir = '')
os.chdir(self.test.workpath(''))
def tearDown(self):
@@ -102,14 +102,17 @@ class SConfTestCase(unittest.TestCase):
import SCons.Platform.win32
- file = SCons.Platform.win32._builtin_file
- open = SCons.Platform.win32._builtin_open
+ try:
+ file = SCons.Platform.win32._builtin_file
+ open = SCons.Platform.win32._builtin_open
+ except AttributeError:
+ pass
def _baseTryXXX(self, TryFunc):
# TryCompile and TryLink are much the same, so we can test them
# in one method, we pass the function as a string ('TryCompile',
# 'TryLink'), so we are aware of reloading modules.
-
+
def checks(self, sconf, TryFuncString):
TryFunc = self.SConf.SConfBase.__dict__[TryFuncString]
res1 = TryFunc( sconf, "int main() { return 0; }\n", ".c" )
@@ -128,7 +131,7 @@ class SConfTestCase(unittest.TestCase):
assert res[0] and not res[1], res
finally:
sconf.Finish()
-
+
# 2.1 test the error caching mechanism (no dependencies have changed)
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
@@ -139,9 +142,9 @@ class SConfTestCase(unittest.TestCase):
assert res[0] and not res[1], res
finally:
sconf.Finish()
- # we should have exactly one one error cached
+ # we should have exactly one one error cached
log = str(self.test.read( self.test.workpath('config.log') ))
- expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
+ expr = re.compile( ".*failed in a previous run and all", re.DOTALL )
firstOcc = expr.match( log )
assert firstOcc is not None, log
secondOcc = expr.match( log, firstOcc.end(0) )
@@ -239,11 +242,11 @@ class SConfTestCase(unittest.TestCase):
"""Test SConf.TryCompile
"""
self._baseTryXXX( "TryCompile" ) #self.SConf.SConf.TryCompile )
-
+
def test_TryLink(self):
"""Test SConf.TryLink
"""
- self._baseTryXXX( "TryLink" ) #self.SConf.SConf.TryLink )
+ self._baseTryXXX( "TryLink" ) #self.SConf.SConf.TryLink )
def test_TryRun(self):
"""Test SConf.TryRun
@@ -256,10 +259,10 @@ int main() {
return 0;
}
"""
- res1 = sconf.TryRun( prog, ".c" )
+ res1 = sconf.TryRun( prog, ".c" )
res2 = sconf.TryRun( "not a c program\n", ".c" )
return (res1, res2)
-
+
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
conf_dir=self.test.workpath('config.tests'),
@@ -307,7 +310,7 @@ int main() {
log_file=self.test.workpath('config.log'))
try:
(ret, output) = sconf.TryAction(action=actionOK)
- assert ret and output == bytearray("RUN OK"+os.linesep,'utf-8'), (ret, output)
+ assert ret and output.encode('utf-8') == bytearray("RUN OK"+os.linesep,'utf-8'), (ret, output)
(ret, output) = sconf.TryAction(action=actionFAIL)
assert not ret and output == "", (ret, output)
finally:
@@ -354,7 +357,7 @@ int main() {
try:
self._test_check_compilers('CC', sconf.CheckCC, 'CheckCC')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -370,7 +373,7 @@ int main() {
try:
self._test_check_compilers('SHCC', sconf.CheckSHCC, 'CheckSHCC')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -386,7 +389,7 @@ int main() {
try:
self._test_check_compilers('CXX', sconf.CheckCXX, 'CheckCXX')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -402,7 +405,7 @@ int main() {
try:
self._test_check_compilers('SHCXX', sconf.CheckSHCXX, 'CheckSHCXX')
except AssertionError:
- sys.stderr.write(self.test.read('config.log'))
+ sys.stderr.write(self.test.read('config.log', mode='r'))
raise
finally:
sconf.Finish()
@@ -627,8 +630,8 @@ int main() {
else:
r = sconf.CheckProg('cmd.exe')
self.assertIn('cmd.exe',r)
-
-
+
+
r = sconf.CheckProg('hopefully-not-a-program')
assert r is None
@@ -717,7 +720,7 @@ int main() {
# In ANSI C, malloc should be available in stdlib
r = sconf.CheckDeclaration('malloc', includes = "#include <stdlib.h>")
assert r, "malloc not declared ??"
- # For C++, __cplusplus should be declared
+ # For C++, __cplusplus should be declared
r = sconf.CheckDeclaration('__cplusplus', language = 'C++')
assert r, "__cplusplus not declared in C++ ??"
r = sconf.CheckDeclaration('__cplusplus', language = 'C')
@@ -761,7 +764,7 @@ int main() {
test.Result( ret )
assert ret and output == "Hello", (ret, output)
return ret
-
+
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
@@ -773,7 +776,7 @@ int main() {
assert ret, ret
finally:
sconf.Finish()
-
+
if __name__ == "__main__":
suite = unittest.makeSuite(SConfTestCase, 'test_')
diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py
index 0c54bf3..e5abb0c 100644
--- a/src/engine/SCons/Scanner/LaTeX.py
+++ b/src/engine/SCons/Scanner/LaTeX.py
@@ -37,7 +37,9 @@ import SCons.Util
# list of graphics file extensions for TeX and LaTeX
TexGraphics = ['.eps', '.ps']
-LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif']
+#LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif']
+LatexGraphics = [ '.png', '.jpg', '.gif', '.tif']
+
# Used as a return value of modify_env_var if the variable is not set.
class _Null(object):
@@ -397,6 +399,7 @@ class LaTeX(SCons.Scanner.Base):
include = queue.pop()
inc_type, inc_subdir, inc_filename = include
+
try:
if seen[inc_filename] == 1:
continue
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index f9df813..c810634 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -47,6 +47,7 @@ import os
import sys
import time
import traceback
+import sysconfig
import SCons.CacheDir
import SCons.Debug
@@ -1251,16 +1252,19 @@ def _build_targets(fs, options, targets, target_top):
# various print_* settings, tree_printer list, etc.
BuildTask.options = options
+
+ python_has_threads = sysconfig.get_config_var('WITH_THREAD')
+ # to check if python configured with threads.
global num_jobs
num_jobs = options.num_jobs
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
if num_jobs > 1:
msg = None
- if jobs.num_jobs == 1:
+ if sys.platform == 'win32':
+ msg = fetch_win32_parallel_msg()
+ elif jobs.num_jobs == 1 or not python_has_threads:
msg = "parallel builds are unsupported by this version of Python;\n" + \
"\tignoring -j or num_jobs option.\n"
- elif sys.platform == 'win32':
- msg = fetch_win32_parallel_msg()
if msg:
SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg)
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 8609892..558e28f 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -179,10 +179,10 @@ def _SConscript(fs, *files, **kw):
fs.chdir(top, change_os_dir=1)
if f.rexists():
actual = f.rfile()
- _file_ = open(actual.get_abspath(), "r")
+ _file_ = open(actual.get_abspath(), "rb")
elif f.srcnode().rexists():
actual = f.srcnode().rfile()
- _file_ = open(actual.get_abspath(), "r")
+ _file_ = open(actual.get_abspath(), "rb")
elif f.has_src_builder():
# The SConscript file apparently exists in a source
# code management system. Build it, but then clear
@@ -192,7 +192,7 @@ def _SConscript(fs, *files, **kw):
f.built()
f.builder_set(None)
if f.exists():
- _file_ = open(f.get_abspath(), "r")
+ _file_ = open(f.get_abspath(), "rb")
if _file_:
# Chdir to the SConscript directory. Use a path
# name relative to the SConstruct file so that if
@@ -248,6 +248,7 @@ def _SConscript(fs, *files, **kw):
pass
try:
try:
+# _file_ = SCons.Util.to_str(_file_)
exec(compile(_file_.read(), _file_.name, 'exec'),
call_stack[-1].globals)
except SConscriptReturn:
diff --git a/src/engine/SCons/Sig.py b/src/engine/SCons/Sig.py
deleted file mode 100644
index 35fffc1..0000000
--- a/src/engine/SCons/Sig.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# __COPYRIGHT__
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-
-__doc__ = """Place-holder for the old SCons.Sig module hierarchy
-
-This is no longer used, but code out there (such as the NSIS module on
-the SCons wiki) may try to import SCons.Sig. If so, we generate a warning
-that points them to the line that caused the import, and don't die.
-
-If someone actually tried to use the sub-modules or functions within
-the package (for example, SCons.Sig.MD5.signature()), then they'll still
-get an AttributeError, but at least they'll know where to start looking.
-"""
-
-import SCons.Util
-import SCons.Warnings
-
-msg = 'The SCons.Sig module no longer exists.\n' \
- ' Remove the following "import SCons.Sig" line to eliminate this warning:'
-
-SCons.Warnings.warn(SCons.Warnings.DeprecatedSigModuleWarning, msg)
-
-default_calc = None
-default_module = None
-
-class MD5Null(SCons.Util.Null):
- def __repr__(self):
- return "MD5Null()"
-
-class TimeStampNull(SCons.Util.Null):
- def __repr__(self):
- return "TimeStampNull()"
-
-MD5 = MD5Null()
-TimeStamp = TimeStampNull()
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index ec7b9f2..9bd9597 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -546,9 +546,17 @@ class Task(object):
if sys.version_info[0] == 2:
exec("raise exc_type, exc_value, exc_traceback")
else: # sys.version_info[0] == 3:
- exec("raise exc_type(exc_value).with_traceback(exc_traceback)")
+ if isinstance(exc_value, Exception): #hasattr(exc_value, 'with_traceback'):
+ # If exc_value is an exception, then just reraise
+ exec("raise exc_value.with_traceback(exc_traceback)")
+ else:
+ # else we'll create an exception using the value and raise that
+ exec("raise exc_type(exc_value).with_traceback(exc_traceback)")
+
# raise e.__class__, e.__class__(e), sys.exc_info()[2]
+ # exec("raise exc_type(exc_value).with_traceback(exc_traceback)")
+
class AlwaysTask(Task):
diff --git a/src/engine/SCons/Tool/GettextCommon.py b/src/engine/SCons/Tool/GettextCommon.py
index e23a2d7..3b840a6 100644
--- a/src/engine/SCons/Tool/GettextCommon.py
+++ b/src/engine/SCons/Tool/GettextCommon.py
@@ -29,15 +29,32 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import SCons.Warnings
import re
+
#############################################################################
class XgettextToolWarning(SCons.Warnings.Warning): pass
+
+
class XgettextNotFound(XgettextToolWarning): pass
+
+
class MsginitToolWarning(SCons.Warnings.Warning): pass
+
+
class MsginitNotFound(MsginitToolWarning): pass
+
+
class MsgmergeToolWarning(SCons.Warnings.Warning): pass
+
+
class MsgmergeNotFound(MsgmergeToolWarning): pass
+
+
class MsgfmtToolWarning(SCons.Warnings.Warning): pass
+
+
class MsgfmtNotFound(MsgfmtToolWarning): pass
+
+
#############################################################################
SCons.Warnings.enableWarningClass(XgettextToolWarning)
SCons.Warnings.enableWarningClass(XgettextNotFound)
@@ -47,367 +64,406 @@ SCons.Warnings.enableWarningClass(MsgmergeToolWarning)
SCons.Warnings.enableWarningClass(MsgmergeNotFound)
SCons.Warnings.enableWarningClass(MsgfmtToolWarning)
SCons.Warnings.enableWarningClass(MsgfmtNotFound)
+
+
#############################################################################
#############################################################################
class _POTargetFactory(object):
- """ A factory of `PO` target files.
-
- Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
- (this is required by builders and actions gettext) and `noclean` flags by
- default for all produced nodes.
- """
- def __init__( self, env, nodefault = True, alias = None, precious = True
- , noclean = True ):
- """ Object constructor.
-
- **Arguments**
-
- - *env* (`SCons.Environment.Environment`)
- - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
- from default target `'.'`
- - *alias* (`string`) - if provided, produced nodes will be automatically
- added to this alias, and alias will be set as `AlwaysBuild`
- - *precious* (`boolean`) - if `True`, the produced nodes will be set as
- `Precious`.
- - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
- from `Clean`.
+ """ A factory of `PO` target files.
+
+ Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
+ (this is required by builders and actions gettext) and `noclean` flags by
+ default for all produced nodes.
"""
- self.env = env
- self.alias = alias
- self.precious = precious
- self.noclean = noclean
- self.nodefault = nodefault
-
- def _create_node(self, name, factory, directory = None, create = 1):
- """ Create node, and set it up to factory settings. """
- import SCons.Util
- node = factory(name, directory, create)
- node.set_noclean(self.noclean)
- node.set_precious(self.precious)
- if self.nodefault:
- self.env.Ignore('.', node)
- if self.alias:
- self.env.AlwaysBuild(self.env.Alias(self.alias, node))
- return node
-
- def Entry(self, name, directory = None, create = 1):
- """ Create `SCons.Node.FS.Entry` """
- return self._create_node(name, self.env.fs.Entry, directory, create)
-
- def File(self, name, directory = None, create = 1):
- """ Create `SCons.Node.FS.File` """
- return self._create_node(name, self.env.fs.File, directory, create)
+
+ def __init__(self, env, nodefault=True, alias=None, precious=True
+ , noclean=True):
+ """ Object constructor.
+
+ **Arguments**
+
+ - *env* (`SCons.Environment.Environment`)
+ - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
+ from default target `'.'`
+ - *alias* (`string`) - if provided, produced nodes will be automatically
+ added to this alias, and alias will be set as `AlwaysBuild`
+ - *precious* (`boolean`) - if `True`, the produced nodes will be set as
+ `Precious`.
+ - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
+ from `Clean`.
+ """
+ self.env = env
+ self.alias = alias
+ self.precious = precious
+ self.noclean = noclean
+ self.nodefault = nodefault
+
+ def _create_node(self, name, factory, directory=None, create=1):
+ """ Create node, and set it up to factory settings. """
+ import SCons.Util
+ node = factory(name, directory, create)
+ node.set_noclean(self.noclean)
+ node.set_precious(self.precious)
+ if self.nodefault:
+ self.env.Ignore('.', node)
+ if self.alias:
+ self.env.AlwaysBuild(self.env.Alias(self.alias, node))
+ return node
+
+ def Entry(self, name, directory=None, create=1):
+ """ Create `SCons.Node.FS.Entry` """
+ return self._create_node(name, self.env.fs.Entry, directory, create)
+
+ def File(self, name, directory=None, create=1):
+ """ Create `SCons.Node.FS.File` """
+ return self._create_node(name, self.env.fs.File, directory, create)
+
+
#############################################################################
#############################################################################
_re_comment = re.compile(r'(#[^\n\r]+)$', re.M)
_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M)
+
+
#############################################################################
-def _read_linguas_from_files(env, linguas_files = None):
- """ Parse `LINGUAS` file and return list of extracted languages """
- import SCons.Util
- import SCons.Environment
- global _re_comment
- global _re_lang
- if not SCons.Util.is_List(linguas_files) \
- and not SCons.Util.is_String(linguas_files) \
- and not isinstance(linguas_files, SCons.Node.FS.Base) \
- and linguas_files:
- # If, linguas_files==True or such, then read 'LINGUAS' file.
- linguas_files = [ 'LINGUAS' ]
- if linguas_files is None:
- return []
- fnodes = env.arg2nodes(linguas_files)
- linguas = []
- for fnode in fnodes:
- contents = _re_comment.sub("", fnode.get_text_contents())
- ls = [ l for l in _re_lang.findall(contents) if l ]
- linguas.extend(ls)
- return linguas
+def _read_linguas_from_files(env, linguas_files=None):
+ """ Parse `LINGUAS` file and return list of extracted languages """
+ import SCons.Util
+ import SCons.Environment
+ global _re_comment
+ global _re_lang
+ if not SCons.Util.is_List(linguas_files) \
+ and not SCons.Util.is_String(linguas_files) \
+ and not isinstance(linguas_files, SCons.Node.FS.Base) \
+ and linguas_files:
+ # If, linguas_files==True or such, then read 'LINGUAS' file.
+ linguas_files = ['LINGUAS']
+ if linguas_files is None:
+ return []
+ fnodes = env.arg2nodes(linguas_files)
+ linguas = []
+ for fnode in fnodes:
+ contents = _re_comment.sub("", fnode.get_text_contents())
+ ls = [l for l in _re_lang.findall(contents) if l]
+ linguas.extend(ls)
+ return linguas
+
+
#############################################################################
#############################################################################
from SCons.Builder import BuilderBase
+
+
#############################################################################
class _POFileBuilder(BuilderBase):
- """ `PO` file builder.
-
- This is multi-target single-source builder. In typical situation the source
- is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
- targets to be updated from this `POT`. We must run
- `SCons.Builder.BuilderBase._execute()` separatelly for each target to track
- dependencies separatelly for each target file.
+ """ `PO` file builder.
- **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
- with target being list of all targets, all targets would be rebuilt each time
- one of the targets from this list is missing. This would happen, for example,
- when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
- `ll.po` file yet). To avoid this, we override
- `SCons.Builder.BuilerBase._execute()` and call it separatelly for each
- target. Here we also append to the target list the languages read from
- `LINGUAS_FILE`.
- """
- #
- #* The argument for overriding _execute(): We must use environment with
- # builder overrides applied (see BuilderBase.__init__(). Here it comes for
- # free.
- #* The argument against using 'emitter': The emitter is called too late
- # by BuilderBase._execute(). If user calls, for example:
- #
- # env.POUpdate(LINGUAS_FILE = 'LINGUAS')
- #
- # the builder throws error, because it is called with target=None,
- # source=None and is trying to "generate" sources or target list first.
- # If user calls
- #
- # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
- #
- # the env.BuilderWrapper() calls our builder with target=None,
- # source=['foo', 'baz']. The BuilderBase._execute() then splits execution
- # and execute iterativelly (recursion) self._execute(None, source[i]).
- # After that it calls emitter (which is quite too late). The emitter is
- # also called in each iteration, what makes things yet worse.
- def __init__(self, env, **kw):
- if not 'suffix' in kw:
- kw['suffix'] = '$POSUFFIX'
- if not 'src_suffix' in kw:
- kw['src_suffix'] = '$POTSUFFIX'
- if not 'src_builder' in kw:
- kw['src_builder'] = '_POTUpdateBuilder'
- if not 'single_source' in kw:
- kw['single_source'] = True
- alias = None
- if 'target_alias' in kw:
- alias = kw['target_alias']
- del kw['target_alias']
- if not 'target_factory' in kw:
- kw['target_factory'] = _POTargetFactory(env, alias=alias).File
- BuilderBase.__init__(self, **kw)
-
- def _execute(self, env, target, source, *args, **kw):
- """ Execute builder's actions.
+ This is multi-target single-source builder. In typical situation the source
+ is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
+ targets to be updated from this `POT`. We must run
+ `SCons.Builder.BuilderBase._execute()` separatelly for each target to track
+ dependencies separatelly for each target file.
- Here we append to `target` the languages read from `$LINGUAS_FILE` and
- apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
- The arguments and return value are same as for
- `SCons.Builder.BuilderBase._execute()`.
+ **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
+ with target being list of all targets, all targets would be rebuilt each time
+ one of the targets from this list is missing. This would happen, for example,
+ when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
+ `ll.po` file yet). To avoid this, we override
+ `SCons.Builder.BuilerBase._execute()` and call it separatelly for each
+ target. Here we also append to the target list the languages read from
+ `LINGUAS_FILE`.
"""
- import SCons.Util
- import SCons.Node
- linguas_files = None
- if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']:
- linguas_files = env['LINGUAS_FILE']
- # This prevents endless recursion loop (we'll be invoked once for
- # each target appended here, we must not extend the list again).
- env['LINGUAS_FILE'] = None
- linguas = _read_linguas_from_files(env,linguas_files)
- if SCons.Util.is_List(target):
- target.extend(linguas)
- elif target is not None:
- target = [target] + linguas
- else:
- target = linguas
- if not target:
- # Let the SCons.BuilderBase to handle this patologic situation
- return BuilderBase._execute( self, env, target, source, *args, **kw)
- # The rest is ours
- if not SCons.Util.is_List(target):
- target = [ target ]
- result = []
- for tgt in target:
- r = BuilderBase._execute( self, env, [tgt], source, *args, **kw)
- result.extend(r)
- if linguas_files is not None:
- env['LINGUAS_FILE'] = linguas_files
- return SCons.Node.NodeList(result)
+
+ #
+ # * The argument for overriding _execute(): We must use environment with
+ # builder overrides applied (see BuilderBase.__init__(). Here it comes for
+ # free.
+ # * The argument against using 'emitter': The emitter is called too late
+ # by BuilderBase._execute(). If user calls, for example:
+ #
+ # env.POUpdate(LINGUAS_FILE = 'LINGUAS')
+ #
+ # the builder throws error, because it is called with target=None,
+ # source=None and is trying to "generate" sources or target list first.
+ # If user calls
+ #
+ # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
+ #
+ # the env.BuilderWrapper() calls our builder with target=None,
+ # source=['foo', 'baz']. The BuilderBase._execute() then splits execution
+ # and execute iterativelly (recursion) self._execute(None, source[i]).
+ # After that it calls emitter (which is quite too late). The emitter is
+ # also called in each iteration, what makes things yet worse.
+ def __init__(self, env, **kw):
+ if not 'suffix' in kw:
+ kw['suffix'] = '$POSUFFIX'
+ if not 'src_suffix' in kw:
+ kw['src_suffix'] = '$POTSUFFIX'
+ if not 'src_builder' in kw:
+ kw['src_builder'] = '_POTUpdateBuilder'
+ if not 'single_source' in kw:
+ kw['single_source'] = True
+ alias = None
+ if 'target_alias' in kw:
+ alias = kw['target_alias']
+ del kw['target_alias']
+ if not 'target_factory' in kw:
+ kw['target_factory'] = _POTargetFactory(env, alias=alias).File
+ BuilderBase.__init__(self, **kw)
+
+ def _execute(self, env, target, source, *args, **kw):
+ """ Execute builder's actions.
+
+ Here we append to `target` the languages read from `$LINGUAS_FILE` and
+ apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
+ The arguments and return value are same as for
+ `SCons.Builder.BuilderBase._execute()`.
+ """
+ import SCons.Util
+ import SCons.Node
+ linguas_files = None
+ if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']:
+ linguas_files = env['LINGUAS_FILE']
+ # This prevents endless recursion loop (we'll be invoked once for
+ # each target appended here, we must not extend the list again).
+ env['LINGUAS_FILE'] = None
+ linguas = _read_linguas_from_files(env, linguas_files)
+ if SCons.Util.is_List(target):
+ target.extend(linguas)
+ elif target is not None:
+ target = [target] + linguas
+ else:
+ target = linguas
+ if not target:
+ # Let the SCons.BuilderBase to handle this patologic situation
+ return BuilderBase._execute(self, env, target, source, *args, **kw)
+ # The rest is ours
+ if not SCons.Util.is_List(target):
+ target = [target]
+ result = []
+ for tgt in target:
+ r = BuilderBase._execute(self, env, [tgt], source, *args, **kw)
+ result.extend(r)
+ if linguas_files is not None:
+ env['LINGUAS_FILE'] = linguas_files
+ return SCons.Node.NodeList(result)
+
+
#############################################################################
import SCons.Environment
+
+
#############################################################################
def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
- """ Function for `Translate()` pseudo-builder """
- if target is None: target = []
- pot = env.POTUpdate(None, source, *args, **kw)
- po = env.POUpdate(target, pot, *args, **kw)
- return po
+ """ Function for `Translate()` pseudo-builder """
+ if target is None: target = []
+ pot = env.POTUpdate(None, source, *args, **kw)
+ po = env.POUpdate(target, pot, *args, **kw)
+ return po
+
+
#############################################################################
#############################################################################
class RPaths(object):
- """ Callable object, which returns pathnames relative to SCons current
- working directory.
-
- It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
- for nodes that are outside of current working directory (`env.fs.getcwd()`).
- Here, we often have `SConscript`, `POT` and `PO` files within `po/`
- directory and source files (e.g. `*.c`) outside of it. When generating `POT`
- template file, references to source files are written to `POT` template, so
- a translator may later quickly jump to appropriate source file and line from
- its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually
- interpreted by `PO` editor as paths relative to the place, where `PO` file
- lives. The absolute paths would make resultant `POT` file nonportable, as
- the references would be correct only on the machine, where `POT` file was
- recently re-created. For such reason, we need a function, which always
- returns relative paths. This is the purpose of `RPaths` callable object.
-
- The `__call__` method returns paths relative to current working directory, but
- we assume, that *xgettext(1)* is run from the directory, where target file is
- going to be created.
-
- Note, that this may not work for files distributed over several hosts or
- across different drives on windows. We assume here, that single local
- filesystem holds both source files and target `POT` templates.
-
- Intended use of `RPaths` - in `xgettext.py`::
-
- def generate(env):
- from GettextCommon import RPaths
- ...
- sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
- env.Append(
- ...
- XGETTEXTCOM = 'XGETTEXT ... ' + sources,
- ...
- XgettextRPaths = RPaths(env)
- )
- """
- # NOTE: This callable object returns pathnames of dirs/files relative to
- # current working directory. The pathname remains relative also for entries
- # that are outside of current working directory (node, that
- # SCons.Node.FS.File and siblings return absolute path in such case). For
- # simplicity we compute path relative to current working directory, this
- # seems be enough for our purposes (don't need TARGET variable and
- # SCons.Defaults.Variable_Caller stuff).
+ """ Callable object, which returns pathnames relative to SCons current
+ working directory.
- def __init__(self, env):
- """ Initialize `RPaths` callable object.
-
- **Arguments**:
-
- - *env* - a `SCons.Environment.Environment` object, defines *current
- working dir*.
+ It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
+ for nodes that are outside of current working directory (`env.fs.getcwd()`).
+ Here, we often have `SConscript`, `POT` and `PO` files within `po/`
+ directory and source files (e.g. `*.c`) outside of it. When generating `POT`
+ template file, references to source files are written to `POT` template, so
+ a translator may later quickly jump to appropriate source file and line from
+ its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually
+ interpreted by `PO` editor as paths relative to the place, where `PO` file
+ lives. The absolute paths would make resultant `POT` file nonportable, as
+ the references would be correct only on the machine, where `POT` file was
+ recently re-created. For such reason, we need a function, which always
+ returns relative paths. This is the purpose of `RPaths` callable object.
+
+ The `__call__` method returns paths relative to current working directory, but
+ we assume, that *xgettext(1)* is run from the directory, where target file is
+ going to be created.
+
+ Note, that this may not work for files distributed over several hosts or
+ across different drives on windows. We assume here, that single local
+ filesystem holds both source files and target `POT` templates.
+
+ Intended use of `RPaths` - in `xgettext.py`::
+
+ def generate(env):
+ from GettextCommon import RPaths
+ ...
+ sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
+ env.Append(
+ ...
+ XGETTEXTCOM = 'XGETTEXT ... ' + sources,
+ ...
+ XgettextRPaths = RPaths(env)
+ )
"""
- self.env = env
- # FIXME: I'm not sure, how it should be implemented (what the *args are in
- # general, what is **kw).
- def __call__(self, nodes, *args, **kw):
- """ Return nodes' paths (strings) relative to current working directory.
-
- **Arguments**:
+ # NOTE: This callable object returns pathnames of dirs/files relative to
+ # current working directory. The pathname remains relative also for entries
+ # that are outside of current working directory (node, that
+ # SCons.Node.FS.File and siblings return absolute path in such case). For
+ # simplicity we compute path relative to current working directory, this
+ # seems be enough for our purposes (don't need TARGET variable and
+ # SCons.Defaults.Variable_Caller stuff).
- - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
- - *args* - currently unused.
- - *kw* - currently unused.
+ def __init__(self, env):
+ """ Initialize `RPaths` callable object.
+
+ **Arguments**:
+
+ - *env* - a `SCons.Environment.Environment` object, defines *current
+ working dir*.
+ """
+ self.env = env
+
+ # FIXME: I'm not sure, how it should be implemented (what the *args are in
+ # general, what is **kw).
+ def __call__(self, nodes, *args, **kw):
+ """ Return nodes' paths (strings) relative to current working directory.
+
+ **Arguments**:
+
+ - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
+ - *args* - currently unused.
+ - *kw* - currently unused.
+
+ **Returns**:
+
+ - Tuple of strings, which represent paths relative to current working
+ directory (for given environment).
+ """
+ import os
+ import SCons.Node.FS
+ rpaths = ()
+ cwd = self.env.fs.getcwd().get_abspath()
+ for node in nodes:
+ rpath = None
+ if isinstance(node, SCons.Node.FS.Base):
+ rpath = os.path.relpath(node.get_abspath(), cwd)
+ # FIXME: Other types possible here?
+ if rpath is not None:
+ rpaths += (rpath,)
+ return rpaths
- **Returns**:
- - Tuple of strings, which represent paths relative to current working
- directory (for given environment).
- """
- import os
- import SCons.Node.FS
- rpaths = ()
- cwd = self.env.fs.getcwd().get_abspath()
- for node in nodes:
- rpath = None
- if isinstance(node, SCons.Node.FS.Base):
- rpath = os.path.relpath(node.get_abspath(), cwd)
- # FIXME: Other types possible here?
- if rpath is not None:
- rpaths += (rpath,)
- return rpaths
#############################################################################
-
+
#############################################################################
def _init_po_files(target, source, env):
- """ Action function for `POInit` builder. """
- nop = lambda target, source, env : 0
- if 'POAUTOINIT' in env:
- autoinit = env['POAUTOINIT']
- else:
- autoinit = False
- # Well, if everything outside works well, this loop should do single
- # iteration. Otherwise we are rebuilding all the targets even, if just
- # one has changed (but is this our fault?).
- for tgt in target:
- if not tgt.exists():
- if autoinit:
- action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
- else:
- msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
- + 'If you are a translator, you can create it through: \n' \
- + '$MSGINITCOM'
- action = SCons.Action.Action(nop, msg)
- status = action([tgt], source, env)
- if status: return status
- return 0
+ """ Action function for `POInit` builder. """
+ nop = lambda target, source, env: 0
+ if 'POAUTOINIT' in env:
+ autoinit = env['POAUTOINIT']
+ else:
+ autoinit = False
+ # Well, if everything outside works well, this loop should do single
+ # iteration. Otherwise we are rebuilding all the targets even, if just
+ # one has changed (but is this our fault?).
+ for tgt in target:
+ if not tgt.exists():
+ if autoinit:
+ action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
+ else:
+ msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
+ + 'If you are a translator, you can create it through: \n' \
+ + '$MSGINITCOM'
+ action = SCons.Action.Action(nop, msg)
+ status = action([tgt], source, env)
+ if status: return status
+ return 0
+
+
#############################################################################
#############################################################################
def _detect_xgettext(env):
- """ Detects *xgettext(1)* binary """
- if 'XGETTEXT' in env:
- return env['XGETTEXT']
- xgettext = env.Detect('xgettext');
- if xgettext:
- return xgettext
- raise SCons.Errors.StopError(XgettextNotFound,"Could not detect xgettext")
- return None
+ """ Detects *xgettext(1)* binary """
+ if 'XGETTEXT' in env:
+ return env['XGETTEXT']
+ xgettext = env.Detect('xgettext');
+ if xgettext:
+ return xgettext
+ raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
+ return None
+
+
#############################################################################
def _xgettext_exists(env):
- return _detect_xgettext(env)
+ return _detect_xgettext(env)
+
+
#############################################################################
#############################################################################
def _detect_msginit(env):
- """ Detects *msginit(1)* program. """
- if 'MSGINIT' in env:
- return env['MSGINIT']
- msginit = env.Detect('msginit');
- if msginit:
- return msginit
- raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
- return None
+ """ Detects *msginit(1)* program. """
+ if 'MSGINIT' in env:
+ return env['MSGINIT']
+ msginit = env.Detect('msginit');
+ if msginit:
+ return msginit
+ raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
+ return None
+
+
#############################################################################
def _msginit_exists(env):
- return _detect_msginit(env)
+ return _detect_msginit(env)
+
+
#############################################################################
#############################################################################
def _detect_msgmerge(env):
- """ Detects *msgmerge(1)* program. """
- if 'MSGMERGE' in env:
- return env['MSGMERGE']
- msgmerge = env.Detect('msgmerge');
- if msgmerge:
- return msgmerge
- raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
- return None
+ """ Detects *msgmerge(1)* program. """
+ if 'MSGMERGE' in env:
+ return env['MSGMERGE']
+ msgmerge = env.Detect('msgmerge');
+ if msgmerge:
+ return msgmerge
+ raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
+ return None
+
+
#############################################################################
def _msgmerge_exists(env):
- return _detect_msgmerge(env)
+ return _detect_msgmerge(env)
+
+
#############################################################################
#############################################################################
def _detect_msgfmt(env):
- """ Detects *msgmfmt(1)* program. """
- if 'MSGFMT' in env:
- return env['MSGFMT']
- msgfmt = env.Detect('msgfmt');
- if msgfmt:
- return msgfmt
- raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
- return None
+ """ Detects *msgmfmt(1)* program. """
+ if 'MSGFMT' in env:
+ return env['MSGFMT']
+ msgfmt = env.Detect('msgfmt');
+ if msgfmt:
+ return msgfmt
+ raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
+ return None
+
+
#############################################################################
def _msgfmt_exists(env):
- return _detect_msgfmt(env)
+ return _detect_msgfmt(env)
+
+
#############################################################################
#############################################################################
def tool_list(platform, env):
- """ List tools that shall be generated by top-level `gettext` tool """
- return [ 'xgettext', 'msginit', 'msgmerge', 'msgfmt' ]
-#############################################################################
+ """ List tools that shall be generated by top-level `gettext` tool """
+ return ['xgettext', 'msginit', 'msgmerge', 'msgfmt']
+#############################################################################
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 99e0770..61b7788 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -761,6 +761,7 @@ def LibSymlinksStrFun(target, source, env, *args):
LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun)
+
def createSharedLibBuilder(env):
"""This is a utility function that creates the SharedLibrary
Builder in an Environment if it is not there already.
diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py
index ba955a4..c5f4376 100644
--- a/src/engine/SCons/Tool/applelink.py
+++ b/src/engine/SCons/Tool/applelink.py
@@ -51,6 +51,14 @@ def generate(env):
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
+
+ # TODO: Work needed to generate versioned shared libraries
+ # Leaving this commented out, and also going to disable versioned library checking for now
+ # see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming
+ #link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname)
+ #env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
+
+
# override the default for loadable modules, which are different
# on OS X than dynamic shared libs. echoing what XCode does for
# pre/suffixes:
diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py
index 8a7b2e7..d3ea8ae 100644
--- a/src/engine/SCons/Tool/docbook/__init__.py
+++ b/src/engine/SCons/Tool/docbook/__init__.py
@@ -157,6 +157,11 @@ def __create_output_dir(base_dir):
#
# Supported command line tools and their call "signature"
#
+xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan']
+
+# TODO: Set minimum version of saxon-xslt to be 8.x (lower than this only supports xslt 1.0.
+# see: http://saxon.sourceforge.net/saxon6.5.5/
+# see: http://saxon.sourceforge.net/
xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE',
'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
@@ -166,19 +171,23 @@ fop_com = {'fop' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -fo $SOURCE -pdf $TARGET',
'xep' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -valid -fo $SOURCE -pdf $TARGET',
'jw' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -f docbook -b pdf $SOURCE -o $TARGET'}
-def __detect_cl_tool(env, chainkey, cdict):
+def __detect_cl_tool(env, chainkey, cdict, cpriority=None):
"""
Helper function, picks a command line tool from the list
and initializes its environment variables.
"""
if env.get(chainkey,'') == '':
clpath = ''
- for cltool in cdict:
+
+ if cpriority is None:
+ cpriority = cdict.keys()
+ for cltool in cpriority:
clpath = env.WhereIs(cltool)
if clpath:
env[chainkey] = clpath
if not env[chainkey + 'COM']:
env[chainkey + 'COM'] = cdict[cltool]
+ break
def _detect(env):
"""
@@ -192,7 +201,7 @@ def _detect(env):
if ((not has_libxml2 and not has_lxml) or (prefer_xsltproc)):
# Try to find the XSLT processors
- __detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com)
+ __detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority)
__detect_cl_tool(env, 'DOCBOOK_XMLLINT', xmllint_com)
__detect_cl_tool(env, 'DOCBOOK_FOP', fop_com)
diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py
index b7db947..07e9250 100644
--- a/src/engine/SCons/Tool/link.py
+++ b/src/engine/SCons/Tool/link.py
@@ -243,8 +243,10 @@ def _versioned_lib_callbacks():
'VersionedLdModSoname' : _versioned_ldmod_soname,
}.copy()
-# Setup all variables required by the versioning machinery
def _setup_versioned_lib_variables(env, **kw):
+ """
+ Setup all variables required by the versioning machinery
+ """
tool = None
try: tool = kw['tool']
diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml
index e85b27c..c4701e1 100644
--- a/src/engine/SCons/Tool/msvs.xml
+++ b/src/engine/SCons/Tool/msvs.xml
@@ -127,22 +127,24 @@ compilation error messages displayed in the Visual Studio console output
window. This can be remedied by adding the Visual C/C++ <literal>/FC</literal>
compiler option to the &cv-link-CCFLAGS; variable so that the compiler will
print the full path name of any files that cause compilation errors. </para>
-<para> Example usage: </para> <example_commands>barsrcs = ['bar.cpp'],
-barincs = ['bar.h'],
+<para> Example usage: </para>
+ <example_commands>
+barsrcs = ['bar.cpp']
+barincs = ['bar.h']
barlocalincs = ['StdAfx.h']
barresources = ['bar.rc','resource.h']
barmisc = ['bar_readme.txt']
dll = env.SharedLibrary(target = 'bar.dll',
source = barsrcs)
-
+buildtarget = [s for s in dll if str(s).endswith('dll')]
env.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'],
srcs = barsrcs,
incs = barincs,
localincs = barlocalincs,
resources = barresources,
misc = barmisc,
- buildtarget = dll,
+ buildtarget = buildtarget,
variant = 'Release')
</example_commands>
<para>Starting with version 2.4 of
diff --git a/src/engine/SCons/Tool/textfile.py b/src/engine/SCons/Tool/textfile.py
index 0e4d943..42a79cd 100644
--- a/src/engine/SCons/Tool/textfile.py
+++ b/src/engine/SCons/Tool/textfile.py
@@ -71,7 +71,11 @@ def _do_subst(node, subs):
contents = re.sub(k, v, contents)
if 'b' in TEXTFILE_FILE_WRITE_MODE:
- contents = bytearray(contents, 'utf-8')
+ try:
+ contents = bytearray(contents, 'utf-8')
+ except UnicodeDecodeError:
+ # contents is already utf-8 encoded python 2 str i.e. a byte array
+ contents = bytearray(contents)
return contents
diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py
index e9b49b7..2c0ce40 100644
--- a/src/engine/SCons/Tool/xgettext.py
+++ b/src/engine/SCons/Tool/xgettext.py
@@ -26,311 +26,333 @@ Tool specific initialization of `xgettext` tool.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
#############################################################################
class _CmdRunner(object):
- """ Callabe object, which runs shell command storing its stdout and stderr to
- variables. It also provides `strfunction()` method, which shall be used by
- scons Action objects to print command string. """
-
- def __init__(self, command, commandstr = None):
- self.out = None
- self.err = None
- self.status = None
- self.command = command
- self.commandstr = commandstr
-
- def __call__(self, target, source, env):
- import SCons.Action
- import subprocess
- import os
- import sys
- kw = {
- 'stdin' : 'devnull',
- 'stdout' : subprocess.PIPE,
- 'stderr' : subprocess.PIPE,
- 'universal_newlines' : True,
- 'shell' : True
- }
- command = env.subst(self.command, target = target, source = source)
- proc = SCons.Action._subproc(env, command, **kw)
- self.out, self.err = proc.communicate()
- self.status = proc.wait()
- if self.err:
- sys.stderr.write(unicode(self.err))
- return self.status
-
- def strfunction(self, target, source, env):
- import os
- comstr = self.commandstr
- if env.subst(comstr, target = target, source = source) == "":
- comstr = self.command
- s = env.subst(comstr, target = target, source = source)
- return s
+ """ Callable object, which runs shell command storing its stdout and stderr to
+ variables. It also provides `strfunction()` method, which shall be used by
+ scons Action objects to print command string. """
+
+ def __init__(self, command, commandstr=None):
+ self.out = None
+ self.err = None
+ self.status = None
+ self.command = command
+ self.commandstr = commandstr
+
+ def __call__(self, target, source, env):
+ import SCons.Action
+ import subprocess
+ import os
+ import sys
+ kw = {
+ 'stdin': 'devnull',
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.PIPE,
+ 'universal_newlines': True,
+ 'shell': True
+ }
+ command = env.subst(self.command, target=target, source=source)
+ proc = SCons.Action._subproc(env, command, **kw)
+ self.out, self.err = proc.communicate()
+ self.status = proc.wait()
+ if self.err:
+ sys.stderr.write(unicode(self.err))
+ return self.status
+
+ def strfunction(self, target, source, env):
+ import os
+ comstr = self.commandstr
+ if env.subst(comstr, target=target, source=source) == "":
+ comstr = self.command
+ s = env.subst(comstr, target=target, source=source)
+ return s
+
+
#############################################################################
#############################################################################
def _update_pot_file(target, source, env):
- """ Action function for `POTUpdate` builder """
- import re
- import os
- import SCons.Action
- nop = lambda target, source, env : 0
-
- # Save scons cwd and os cwd (NOTE: they may be different. After the job, we
- # revert each one to its original state).
- save_cwd = env.fs.getcwd()
- save_os_cwd = os.getcwd()
- chdir = target[0].dir
- chdir_str = repr(chdir.get_abspath())
- # Print chdir message (employ SCons.Action.Action for that. It knows better
- # than me how to to this correctly).
- env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str))
- # Go to target's directory and do our job
- env.fs.chdir(chdir, 1) # Go into target's directory
- try:
- cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR')
- action = SCons.Action.Action(cmd, strfunction=cmd.strfunction)
- status = action([ target[0] ], source, env)
- except:
- # Something went wrong.
+ """ Action function for `POTUpdate` builder """
+ import re
+ import os
+ import SCons.Action
+ nop = lambda target, source, env: 0
+
+ # Save scons cwd and os cwd (NOTE: they may be different. After the job, we
+ # revert each one to its original state).
+ save_cwd = env.fs.getcwd()
+ save_os_cwd = os.getcwd()
+ chdir = target[0].dir
+ chdir_str = repr(chdir.get_abspath())
+ # Print chdir message (employ SCons.Action.Action for that. It knows better
+ # than me how to to this correctly).
+ env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str))
+ # Go to target's directory and do our job
+ env.fs.chdir(chdir, 1) # Go into target's directory
+ try:
+ cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR')
+ action = SCons.Action.Action(cmd, strfunction=cmd.strfunction)
+ status = action([target[0]], source, env)
+ except:
+ # Something went wrong.
+ env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
+ # Revert working dirs to previous state and re-throw exception.
+ env.fs.chdir(save_cwd, 0)
+ os.chdir(save_os_cwd)
+ raise
+ # Print chdir message.
env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
- # Revert working dirs to previous state and re-throw exception.
+ # Revert working dirs to previous state.
env.fs.chdir(save_cwd, 0)
os.chdir(save_os_cwd)
- raise
- # Print chdir message.
- env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
- # Revert working dirs to previous state.
- env.fs.chdir(save_cwd, 0)
- os.chdir(save_os_cwd)
- # If the command was not successfull, return error code.
- if status: return status
-
- new_content = cmd.out
-
- if not new_content:
- # When xgettext finds no internationalized messages, no *.pot is created
- # (because we don't want to bother translators with empty POT files).
- needs_update = False
- explain = "no internationalized messages encountered"
- else:
- if target[0].exists():
- # If the file already exists, it's left unaltered unless its messages
- # are outdated (w.r.t. to these recovered by xgettext from sources).
- old_content = target[0].get_text_contents()
- re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M)
- old_content_nocdate = re.sub(re_cdate,"",old_content)
- new_content_nocdate = re.sub(re_cdate,"",new_content)
- if(old_content_nocdate == new_content_nocdate):
- # Messages are up-to-date
+ # If the command was not successfull, return error code.
+ if status: return status
+
+ new_content = cmd.out
+
+ if not new_content:
+ # When xgettext finds no internationalized messages, no *.pot is created
+ # (because we don't want to bother translators with empty POT files).
needs_update = False
- explain = "messages in file found to be up-to-date"
- else:
- # Messages are outdated
- needs_update = True
- explain = "messages in file were outdated"
+ explain = "no internationalized messages encountered"
else:
- # No POT file found, create new one
- needs_update = True
- explain = "new file"
- if needs_update:
- # Print message employing SCons.Action.Action for that.
- msg = "Writing " + repr(str(target[0])) + " (" + explain + ")"
- env.Execute(SCons.Action.Action(nop, msg))
- f = open(str(target[0]),"w")
- f.write(new_content)
- f.close()
- return 0
- else:
- # Print message employing SCons.Action.Action for that.
- msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")"
- env.Execute(SCons.Action.Action(nop, msg))
- return 0
+ if target[0].exists():
+ # If the file already exists, it's left unaltered unless its messages
+ # are outdated (w.r.t. to these recovered by xgettext from sources).
+ old_content = target[0].get_text_contents()
+ re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M)
+ old_content_nocdate = re.sub(re_cdate, "", old_content)
+ new_content_nocdate = re.sub(re_cdate, "", new_content)
+ if (old_content_nocdate == new_content_nocdate):
+ # Messages are up-to-date
+ needs_update = False
+ explain = "messages in file found to be up-to-date"
+ else:
+ # Messages are outdated
+ needs_update = True
+ explain = "messages in file were outdated"
+ else:
+ # No POT file found, create new one
+ needs_update = True
+ explain = "new file"
+ if needs_update:
+ # Print message employing SCons.Action.Action for that.
+ msg = "Writing " + repr(str(target[0])) + " (" + explain + ")"
+ env.Execute(SCons.Action.Action(nop, msg))
+ f = open(str(target[0]), "w")
+ f.write(new_content)
+ f.close()
+ return 0
+ else:
+ # Print message employing SCons.Action.Action for that.
+ msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")"
+ env.Execute(SCons.Action.Action(nop, msg))
+ return 0
+
+
#############################################################################
#############################################################################
from SCons.Builder import BuilderBase
+
+
#############################################################################
class _POTBuilder(BuilderBase):
- def _execute(self, env, target, source, *args):
- if not target:
- if 'POTDOMAIN' in env and env['POTDOMAIN']:
- domain = env['POTDOMAIN']
- else:
- domain = 'messages'
- target = [ domain ]
- return BuilderBase._execute(self, env, target, source, *args)
+ def _execute(self, env, target, source, *args):
+ if not target:
+ if 'POTDOMAIN' in env and env['POTDOMAIN']:
+ domain = env['POTDOMAIN']
+ else:
+ domain = 'messages'
+ target = [domain]
+ return BuilderBase._execute(self, env, target, source, *args)
+
+
#############################################################################
#############################################################################
-def _scan_xgettext_from_files(target, source, env, files = None, path = None):
- """ Parses `POTFILES.in`-like file and returns list of extracted file names.
- """
- import re
- import SCons.Util
- import SCons.Node.FS
-
- if files is None:
+def _scan_xgettext_from_files(target, source, env, files=None, path=None):
+ """ Parses `POTFILES.in`-like file and returns list of extracted file names.
+ """
+ import re
+ import SCons.Util
+ import SCons.Node.FS
+
+ if files is None:
+ return 0
+ if not SCons.Util.is_List(files):
+ files = [files]
+
+ if path is None:
+ if 'XGETTEXTPATH' in env:
+ path = env['XGETTEXTPATH']
+ else:
+ path = []
+ if not SCons.Util.is_List(path):
+ path = [path]
+
+ path = SCons.Util.flatten(path)
+
+ dirs = ()
+ for p in path:
+ if not isinstance(p, SCons.Node.FS.Base):
+ if SCons.Util.is_String(p):
+ p = env.subst(p, source=source, target=target)
+ p = env.arg2nodes(p, env.fs.Dir)
+ dirs += tuple(p)
+ # cwd is the default search path (when no path is defined by user)
+ if not dirs:
+ dirs = (env.fs.getcwd(),)
+
+ # Parse 'POTFILE.in' files.
+ re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M)
+ re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M)
+ re_trailws = re.compile(r'[ \t\r]+$')
+ for f in files:
+ # Find files in search path $XGETTEXTPATH
+ if isinstance(f, SCons.Node.FS.Base) and f.rexists():
+ contents = f.get_text_contents()
+ contents = re_comment.sub("", contents)
+ contents = re_emptyln.sub("", contents)
+ contents = re_trailws.sub("", contents)
+ depnames = contents.splitlines()
+ for depname in depnames:
+ depfile = SCons.Node.FS.find_file(depname, dirs)
+ if not depfile:
+ depfile = env.arg2nodes(depname, dirs[0].File)
+ env.Depends(target, depfile)
return 0
- if not SCons.Util.is_List(files):
- files = [ files ]
- if path is None:
- if 'XGETTEXTPATH' in env:
- path = env['XGETTEXTPATH']
- else:
- path = []
- if not SCons.Util.is_List(path):
- path = [ path ]
-
- path = SCons.Util.flatten(path)
-
- dirs = ()
- for p in path:
- if not isinstance(p, SCons.Node.FS.Base):
- if SCons.Util.is_String(p):
- p = env.subst(p, source = source, target = target)
- p = env.arg2nodes(p, env.fs.Dir)
- dirs += tuple(p)
- # cwd is the default search path (when no path is defined by user)
- if not dirs:
- dirs = (env.fs.getcwd(),)
-
- # Parse 'POTFILE.in' files.
- re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M)
- re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M)
- re_trailws = re.compile(r'[ \t\r]+$')
- for f in files:
- # Find files in search path $XGETTEXTPATH
- if isinstance(f, SCons.Node.FS.Base) and f.rexists():
- contents = f.get_text_contents()
- contents = re_comment.sub("", contents)
- contents = re_emptyln.sub("", contents)
- contents = re_trailws.sub("", contents)
- depnames = contents.splitlines()
- for depname in depnames:
- depfile = SCons.Node.FS.find_file(depname, dirs)
- if not depfile:
- depfile = env.arg2nodes(depname, dirs[0].File)
- env.Depends(target, depfile)
- return 0
+
#############################################################################
#############################################################################
def _pot_update_emitter(target, source, env):
- """ Emitter function for `POTUpdate` builder """
- from SCons.Tool.GettextCommon import _POTargetFactory
- import SCons.Util
- import SCons.Node.FS
-
- if 'XGETTEXTFROM' in env:
- xfrom = env['XGETTEXTFROM']
- else:
+ """ Emitter function for `POTUpdate` builder """
+ from SCons.Tool.GettextCommon import _POTargetFactory
+ import SCons.Util
+ import SCons.Node.FS
+
+ if 'XGETTEXTFROM' in env:
+ xfrom = env['XGETTEXTFROM']
+ else:
+ return target, source
+ if not SCons.Util.is_List(xfrom):
+ xfrom = [xfrom]
+
+ xfrom = SCons.Util.flatten(xfrom)
+
+ # Prepare list of 'POTFILE.in' files.
+ files = []
+ for xf in xfrom:
+ if not isinstance(xf, SCons.Node.FS.Base):
+ if SCons.Util.is_String(xf):
+ # Interpolate variables in strings
+ xf = env.subst(xf, source=source, target=target)
+ xf = env.arg2nodes(xf)
+ files.extend(xf)
+ if files:
+ env.Depends(target, files)
+ _scan_xgettext_from_files(target, source, env, files)
return target, source
- if not SCons.Util.is_List(xfrom):
- xfrom = [ xfrom ]
-
- xfrom = SCons.Util.flatten(xfrom)
-
- # Prepare list of 'POTFILE.in' files.
- files = []
- for xf in xfrom:
- if not isinstance(xf, SCons.Node.FS.Base):
- if SCons.Util.is_String(xf):
- # Interpolate variables in strings
- xf = env.subst(xf, source = source, target = target)
- xf = env.arg2nodes(xf)
- files.extend(xf)
- if files:
- env.Depends(target, files)
- _scan_xgettext_from_files(target, source, env, files)
- return target, source
+
+
#############################################################################
#############################################################################
from SCons.Environment import _null
+
+
#############################################################################
def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw):
- return env._POTUpdateBuilder(target, source, **kw)
+ return env._POTUpdateBuilder(target, source, **kw)
+
+
#############################################################################
#############################################################################
def _POTUpdateBuilder(env, **kw):
- """ Creates `POTUpdate` builder object """
- import SCons.Action
- from SCons.Tool.GettextCommon import _POTargetFactory
- kw['action'] = SCons.Action.Action(_update_pot_file, None)
- kw['suffix'] = '$POTSUFFIX'
- kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
- kw['emitter'] = _pot_update_emitter
- return _POTBuilder(**kw)
+ """ Creates `POTUpdate` builder object """
+ import SCons.Action
+ from SCons.Tool.GettextCommon import _POTargetFactory
+ kw['action'] = SCons.Action.Action(_update_pot_file, None)
+ kw['suffix'] = '$POTSUFFIX'
+ kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
+ kw['emitter'] = _pot_update_emitter
+ return _POTBuilder(**kw)
+
+
#############################################################################
#############################################################################
-def generate(env,**kw):
- """ Generate `xgettext` tool """
- import SCons.Util
- from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
-
- try:
- env['XGETTEXT'] = _detect_xgettext(env)
- except:
- env['XGETTEXT'] = 'xgettext'
- # NOTE: sources="$SOURCES" would work as well. However, we use following
- # construction to convert absolute paths provided by scons onto paths
- # relative to current working dir. Note, that scons expands $SOURCE(S) to
- # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in
- # "../"). With source=$SOURCE these absolute paths would be written to the
- # resultant *.pot file (and its derived *.po files) as references to lines in
- # source code (e.g. referring lines in *.c files). Such references would be
- # correct (e.g. in poedit) only on machine on which *.pot was generated and
- # would be of no use on other hosts (having a copy of source code located
- # in different place in filesystem).
- sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \
- + ', SOURCES)} $)'
-
- # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file.
- # This is required by the POTUpdate builder's action.
- xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \
- + ' $_XGETTEXTFROMFLAGS -o - ' + sources
-
- xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \
- + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)'
- xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \
- + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)'
-
- env.SetDefault(
- _XGETTEXTDOMAIN = '${TARGET.filebase}',
- XGETTEXTFLAGS = [ ],
- XGETTEXTCOM = xgettextcom,
- XGETTEXTCOMSTR = '',
- XGETTEXTPATH = [ ],
- XGETTEXTPATHPREFIX = '-D',
- XGETTEXTPATHSUFFIX = '',
- XGETTEXTFROM = None,
- XGETTEXTFROMPREFIX = '-f',
- XGETTEXTFROMSUFFIX = '',
- _XGETTEXTPATHFLAGS = xgettextpathflags,
- _XGETTEXTFROMFLAGS = xgettextfromflags,
- POTSUFFIX = ['.pot'],
- POTUPDATE_ALIAS = 'pot-update',
- XgettextRPaths = RPaths(env)
- )
- env.Append( BUILDERS = {
- '_POTUpdateBuilder' : _POTUpdateBuilder(env)
- } )
- env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate')
- env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS'))
+def generate(env, **kw):
+ """ Generate `xgettext` tool """
+ import SCons.Util
+ from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
+
+ try:
+ env['XGETTEXT'] = _detect_xgettext(env)
+ except:
+ env['XGETTEXT'] = 'xgettext'
+ # NOTE: sources="$SOURCES" would work as well. However, we use following
+ # construction to convert absolute paths provided by scons onto paths
+ # relative to current working dir. Note, that scons expands $SOURCE(S) to
+ # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in
+ # "../"). With source=$SOURCE these absolute paths would be written to the
+ # resultant *.pot file (and its derived *.po files) as references to lines in
+ # source code (e.g. referring lines in *.c files). Such references would be
+ # correct (e.g. in poedit) only on machine on which *.pot was generated and
+ # would be of no use on other hosts (having a copy of source code located
+ # in different place in filesystem).
+ sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \
+ + ', SOURCES)} $)'
+
+ # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file.
+ # This is required by the POTUpdate builder's action.
+ xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \
+ + ' $_XGETTEXTFROMFLAGS -o - ' + sources
+
+ xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \
+ + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)'
+ xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \
+ + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)'
+
+ env.SetDefault(
+ _XGETTEXTDOMAIN='${TARGET.filebase}',
+ XGETTEXTFLAGS=[],
+ XGETTEXTCOM=xgettextcom,
+ XGETTEXTCOMSTR='',
+ XGETTEXTPATH=[],
+ XGETTEXTPATHPREFIX='-D',
+ XGETTEXTPATHSUFFIX='',
+ XGETTEXTFROM=None,
+ XGETTEXTFROMPREFIX='-f',
+ XGETTEXTFROMSUFFIX='',
+ _XGETTEXTPATHFLAGS=xgettextpathflags,
+ _XGETTEXTFROMFLAGS=xgettextfromflags,
+ POTSUFFIX=['.pot'],
+ POTUPDATE_ALIAS='pot-update',
+ XgettextRPaths=RPaths(env)
+ )
+ env.Append(BUILDERS={
+ '_POTUpdateBuilder': _POTUpdateBuilder(env)
+ })
+ env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate')
+ env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS'))
+
+
#############################################################################
#############################################################################
def exists(env):
- """ Check, whether the tool exists """
- from SCons.Tool.GettextCommon import _xgettext_exists
- try:
- return _xgettext_exists(env)
- except:
- return False
+ """ Check, whether the tool exists """
+ from SCons.Tool.GettextCommon import _xgettext_exists
+ try:
+ return _xgettext_exists(env)
+ except:
+ return False
+
#############################################################################
# Local Variables:
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index a8a6990..2d8e75a 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -31,6 +31,7 @@ import sys
import copy
import re
import types
+import codecs
try:
from UserDict import UserDict
@@ -148,7 +149,7 @@ class NodeList(UserList):
# else:
# self.data = [ initlist,]
-
+
def __nonzero__(self):
return len(self.data) != 0
@@ -170,10 +171,10 @@ class NodeList(UserList):
return self.__class__(result)
def __getitem__(self, index):
- """
+ """
This comes for free on py2,
but py3 slices of NodeList are returning a list
- breaking slicing nodelist and refering to
+ breaking slicing nodelist and refering to
properties and methods on contained object
"""
# return self.__class__(self.data[index])
@@ -289,6 +290,17 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
"""
rname = str(root)
+ if sys.version_info.major < 3:
+ # Python 2 UTF-8 encoded str are str. escape_encode is a str to str
+ # encoding
+ rname = codecs.escape_encode(rname)[0]
+ else:
+ # Python 3 UTF-8 encoded str are bytes. escape_encode is a byte to byte
+ # encoding here.
+ rname = rname.encode('utf-8')
+ rname = codecs.escape_encode(rname)[0]
+ # Finally, we need a string again.
+ rname = rname.decode('ascii')
# Initialize 'visited' dict, if required
if visited is None:
diff --git a/src/script/sconsign.py b/src/script/sconsign.py
index 8f1722a..2e7a550 100644
--- a/src/script/sconsign.py
+++ b/src/script/sconsign.py
@@ -241,6 +241,11 @@ def default_mapper(entry, name):
val = eval("entry."+name)
except:
val = None
+ if sys.version_info.major >= 3 and isinstance(val, bytes):
+ # This is a dirty hack for py 2/3 compatibility. csig is a bytes object
+ # in Python3 while Python2 bytes are str. Hence, we decode the csig to a
+ # Python3 string
+ val = val.decode()
return str(val)
def map_action(entry, name):
diff --git a/test/CPPDEFINES/append.py b/test/CPPDEFINES/append.py
index 14ea7b3..7973f22 100644
--- a/test/CPPDEFINES/append.py
+++ b/test/CPPDEFINES/append.py
@@ -54,10 +54,24 @@ print(env_2300_2.subst('$_CPPDEFFLAGS'))
# http://scons.tigris.org/issues/show_bug.cgi?id=1152
# http://scons.tigris.org/issues/show_bug.cgi?id=2900
+# Python3 dicts dont preserve order. Hence we supply subclass of OrderedDict
+# whose __str__ and __repr__ act like a normal dict.
+from collections import OrderedDict
+class OrderedPrintingDict(OrderedDict):
+ def __repr__(self):
+ return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}'
+
+ __str__ = __repr__
+
+ # Because dict-like objects (except dict and UserDict) are not deep copied
+ # directly when constructing Environment(CPPDEFINES = OrderedPrintingDict(...))
+ def __semi_deepcopy__(self):
+ return self.copy()
+
cases=[('string', 'FOO'),
('list', ['NAME1', 'NAME2']),
('list-of-2lists', [('NAME1','VAL1'), ['NAME2','VAL2']]),
- ('dict', {'NAME1' : 'VAL1', 'NAME2' : 'VAL2', 'NAME3' : None})
+ ('dict', OrderedPrintingDict([('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]))
]
for (t1, c1) in cases:
@@ -180,7 +194,7 @@ AppendUnique:
==== Testing CPPDEFINES, appending a string to a dict
orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = FOO
Append:
- result={'FOO': None, 'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ result={'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1', 'FOO': None}
final=-DFOO -DNAME1=VAL1 -DNAME2=VAL2 -DNAME3
AppendUnique:
result=[('NAME2', 'VAL2'), ('NAME3',), ('NAME1', 'VAL1'), 'FOO']
diff --git a/test/CPPDEFINES/pkg-config.py b/test/CPPDEFINES/pkg-config.py
index 4e81dec..42f38b6 100644
--- a/test/CPPDEFINES/pkg-config.py
+++ b/test/CPPDEFINES/pkg-config.py
@@ -56,6 +56,20 @@ int main(int argc, char *argv[])
""")
test.write('SConstruct', """\
+# Python3 dicts dont preserve order. Hence we supply subclass of OrderedDict
+# whose __str__ and __repr__ act like a normal dict.
+from collections import OrderedDict
+class OrderedPrintingDict(OrderedDict):
+ def __repr__(self):
+ return '{' + ', '.join(['%r: %r'%(k, v) for (k, v) in self.items()]) + '}'
+
+ __str__ = __repr__
+
+ # Because dict-like objects (except dict and UserDict) are not deep copied
+ # directly when constructing Environment(CPPDEFINES = OrderedPrintingDict(...))
+ def __semi_deepcopy__(self):
+ return self.copy()
+""" + """
# http://scons.tigris.org/issues/show_bug.cgi?id=2671
# Passing test cases
env_1 = Environment(CPPDEFINES=[('DEBUG','1'), 'TEST'])
@@ -67,11 +81,11 @@ env_2.MergeFlags('-DSOMETHING -DVARIABLE=2')
print(env_2.subst('$_CPPDEFFLAGS'))
# Failing test cases
-env_3 = Environment(CPPDEFINES={'DEBUG':1, 'TEST':None})
+env_3 = Environment(CPPDEFINES=OrderedPrintingDict([('DEBUG', 1), ('TEST', None)]))
env_3.ParseConfig('PKG_CONFIG_PATH=. %(pkg_config_path)s --cflags bug')
print(env_3.subst('$_CPPDEFFLAGS'))
-env_4 = Environment(CPPDEFINES={'DEBUG':1, 'TEST':None})
+env_4 = Environment(CPPDEFINES=OrderedPrintingDict([('DEBUG', 1), ('TEST', None)]))
env_4.MergeFlags('-DSOMETHING -DVARIABLE=2')
print(env_4.subst('$_CPPDEFFLAGS'))
diff --git a/test/D/MixedDAndC/sconstest-dmd.py b/test/D/MixedDAndC/sconstest-dmd.py
index df66255..d96c5c3 100644
--- a/test/D/MixedDAndC/sconstest-dmd.py
+++ b/test/D/MixedDAndC/sconstest-dmd.py
@@ -27,6 +27,16 @@ Test compiling and executing a project with a C module.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import sys
+if sys.platform == 'darwin':
+ import TestSCons
+ test = TestSCons.TestSCons()
+
+ msg = "Skipping Mixed dmd test until a good way to ensure proper gcc is called."
+ "Calling default(system /usr/bin/gcc) gcc yields a surplus of linking errors\n"
+ test.skip_test(msg)
+
+
from Common.common import testForTool
testForTool('dmd')
diff --git a/test/Deprecated/Sig.py b/test/Deprecated/Sig.py
deleted file mode 100644
index 1ae118b..0000000
--- a/test/Deprecated/Sig.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# __COPYRIGHT__
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-
-"""
-Verify that we generate the proper warning, but don't die, when someone
-tries to import the SCons.Sig module (which no longer exists) and
-use the things we used to define therein.
-"""
-
-import TestSCons
-
-test = TestSCons.TestSCons()
-
-SConstruct = test.workpath('SConstruct')
-
-test.write(SConstruct, """
-import SCons.Sig
-x = SCons.Sig.default_calc
-x = SCons.Sig.default_module
-x = SCons.Sig.MD5.current()
-x = SCons.Sig.MD5.collect()
-x = SCons.Sig.MD5.signature()
-x = SCons.Sig.MD5.to_string()
-x = SCons.Sig.MD5.from_string()
-x = SCons.Sig.TimeStamp.current()
-x = SCons.Sig.TimeStamp.collect()
-x = SCons.Sig.TimeStamp.signature()
-x = SCons.Sig.TimeStamp.to_string()
-x = SCons.Sig.TimeStamp.from_string()
-""")
-
-expect = """
-scons: warning: The SCons.Sig module no longer exists.
- Remove the following "import SCons.Sig" line to eliminate this warning:
-""" + test.python_file_line(SConstruct, 2)
-
-test.run(arguments = '.', stderr=expect)
-
-test.pass_test()
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/test/Errors/InternalError.py b/test/Errors/InternalError.py
index 8ed6da1..a709597 100644
--- a/test/Errors/InternalError.py
+++ b/test/Errors/InternalError.py
@@ -47,7 +47,7 @@ test.run(stdout = "scons: Reading SConscript files ...\ninternal error\n",
File ".+", line \d+, in .+
File ".+SConstruct", line \d+, in .+
raise InternalError\('error inside'\)
-InternalError: error inside
+(SCons\.Errors\.|)InternalError: error inside
""", status=2)
test.pass_test()
diff --git a/test/GetBuildFailures/option-k.py b/test/GetBuildFailures/option-k.py
index 0ff22e6..12ae07b 100644
--- a/test/GetBuildFailures/option-k.py
+++ b/test/GetBuildFailures/option-k.py
@@ -64,7 +64,7 @@ Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE')
def print_build_failures():
from SCons.Script import GetBuildFailures
- for bf in sorted(GetBuildFailures(), key=lambda a: a.filename):
+ for bf in sorted(GetBuildFailures(), key=lambda a: a.filename or 'None'):
print("%%s failed: %%s" %% (bf.node, bf.errstr))
import atexit
diff --git a/test/GetBuildFailures/parallel.py b/test/GetBuildFailures/parallel.py
index ee0e831..f9503e0 100644
--- a/test/GetBuildFailures/parallel.py
+++ b/test/GetBuildFailures/parallel.py
@@ -80,7 +80,7 @@ Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE')
def print_build_failures():
from SCons.Script import GetBuildFailures
- for bf in sorted(GetBuildFailures(), key=lambda t: t.filename):
+ for bf in sorted(GetBuildFailures(), key=lambda t: t.filename or 'None'):
print("%%s failed: %%s" %% (bf.node, bf.errstr))
import atexit
diff --git a/test/LINK/VersionedLib-VariantDir.py b/test/LINK/VersionedLib-VariantDir.py
index 0a631b0..0350c6e 100644
--- a/test/LINK/VersionedLib-VariantDir.py
+++ b/test/LINK/VersionedLib-VariantDir.py
@@ -35,11 +35,19 @@ import sys
import SCons.Platform
import SCons.Defaults
+test = TestSCons.TestSCons()
+
+import sys
+if sys.platform == 'darwin':
+ # Skipping until logic is fixed for macosx
+ test.skip_test("Not working on darwin yet\n")
+
+
env = SCons.Defaults.DefaultEnvironment()
platform = SCons.Platform.platform_default()
tool_list = SCons.Platform.DefaultToolList(platform, env)
-test = TestSCons.TestSCons()
+
test.subdir(['src'])
test.subdir(['src','lib'])
diff --git a/test/LINK/VersionedLib-j2.py b/test/LINK/VersionedLib-j2.py
index 249b54f..4646a37 100644
--- a/test/LINK/VersionedLib-j2.py
+++ b/test/LINK/VersionedLib-j2.py
@@ -39,6 +39,11 @@ import SCons.Defaults
test = TestSCons.TestSCons()
+if sys.platform == 'darwin':
+ # Skipping until logic is fixed for macosx
+ test.skip_test("Not working on darwin yet\n")
+
+
test.write('foo.c', """
#if _WIN32
__declspec(dllexport)
diff --git a/test/LINK/VersionedLib-subdir.py b/test/LINK/VersionedLib-subdir.py
index a2e141b..91f3011 100644
--- a/test/LINK/VersionedLib-subdir.py
+++ b/test/LINK/VersionedLib-subdir.py
@@ -41,6 +41,11 @@ import SCons.Defaults
test = TestSCons.TestSCons()
+if sys.platform == 'darwin':
+ # Skipping until logic is fixed for macosx
+ test.skip_test("Not working on darwin yet\n")
+
+
test.write('foo.c', """
#if _WIN32
__declspec(dllexport)
diff --git a/test/LINK/VersionedLib.py b/test/LINK/VersionedLib.py
index 468e3e5..c05c159 100644
--- a/test/LINK/VersionedLib.py
+++ b/test/LINK/VersionedLib.py
@@ -33,6 +33,12 @@ import TestSCons
import SCons.Platform
import SCons.Defaults
+import sys
+if sys.platform == 'darwin':
+ # Skipping until logic is fixed for macosx
+ test = TestSCons.TestSCons()
+ test.skip_test("Not working on darwin yet\n")
+
env = SCons.Defaults.DefaultEnvironment()
platform = SCons.Platform.platform_default()
tool_list = SCons.Platform.DefaultToolList(platform, env)
diff --git a/test/MSVS/vs-10.0-scc-files.py b/test/MSVS/vs-10.0-scc-files.py
index 32dd9ef..0b8bd76 100644
--- a/test/MSVS/vs-10.0-scc-files.py
+++ b/test/MSVS/vs-10.0-scc-files.py
@@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcxproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSccProjectUniqueName1 = Test.vcxproj
\t\tSccLocalPath1 = .
diff --git a/test/MSVS/vs-11.0-scc-files.py b/test/MSVS/vs-11.0-scc-files.py
index 6d12c79..a25b954 100644
--- a/test/MSVS/vs-11.0-scc-files.py
+++ b/test/MSVS/vs-11.0-scc-files.py
@@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcxproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSccProjectUniqueName1 = Test.vcxproj
\t\tSccLocalPath1 = .
diff --git a/test/MSVS/vs-14.0-scc-files.py b/test/MSVS/vs-14.0-scc-files.py
index c934ac9..b6db6d5 100644
--- a/test/MSVS/vs-14.0-scc-files.py
+++ b/test/MSVS/vs-14.0-scc-files.py
@@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcxproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSccProjectUniqueName1 = Test.vcxproj
\t\tSccLocalPath1 = .
diff --git a/test/MSVS/vs-7.0-scc-files.py b/test/MSVS/vs-7.0-scc-files.py
index 76b4380..8586060 100644
--- a/test/MSVS/vs-7.0-scc-files.py
+++ b/test/MSVS/vs-7.0-scc-files.py
@@ -71,9 +71,9 @@ env.MSVSProject(target = 'Test.vcproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSolutionUniqueID = {SLNGUID}
\t\tSccProjectUniqueName1 = Test.vcproj
diff --git a/test/MSVS/vs-7.1-scc-files.py b/test/MSVS/vs-7.1-scc-files.py
index 219bd0a..8404422 100644
--- a/test/MSVS/vs-7.1-scc-files.py
+++ b/test/MSVS/vs-7.1-scc-files.py
@@ -71,9 +71,9 @@ env.MSVSProject(target = 'Test.vcproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSolutionUniqueID = {SLNGUID}
\t\tSccProjectUniqueName1 = Test.vcproj
diff --git a/test/MSVS/vs-8.0-scc-files.py b/test/MSVS/vs-8.0-scc-files.py
index 1baa407..05a8a5f 100644
--- a/test/MSVS/vs-8.0-scc-files.py
+++ b/test/MSVS/vs-8.0-scc-files.py
@@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSccProjectUniqueName1 = Test.vcproj
\t\tSccLocalPath1 = .
diff --git a/test/MSVS/vs-9.0-scc-files.py b/test/MSVS/vs-9.0-scc-files.py
index e3d37c0..c270010 100644
--- a/test/MSVS/vs-9.0-scc-files.py
+++ b/test/MSVS/vs-9.0-scc-files.py
@@ -69,9 +69,9 @@ env.MSVSProject(target = 'Test.vcproj',
expected_sln_sccinfo = """\
\tGlobalSection(SourceCodeControl) = preSolution
\t\tSccNumberOfProjects = 2
-\t\tSccProjectName0 = Perforce\u0020Project
+\t\tSccProjectName0 = Perforce\\u0020Project
\t\tSccLocalPath0 = .
-\t\tSccProvider0 = MSSCCI:Perforce\u0020SCM
+\t\tSccProvider0 = MSSCCI:Perforce\\u0020SCM
\t\tCanCheckoutShared = true
\t\tSccProjectUniqueName1 = Test.vcproj
\t\tSccLocalPath1 = .
diff --git a/test/Progress/TARGET.py b/test/Progress/TARGET.py
index d7ff3c9..9af5565 100644
--- a/test/Progress/TARGET.py
+++ b/test/Progress/TARGET.py
@@ -50,12 +50,12 @@ test.write('S2.in', "S2.in\n")
test.write('S3.in', "S3.in\n")
test.write('S4.in', "S4.in\n")
-expect = """\
+expect = bytearray("""\
S1.in\r \rS1.out\rCopy("S1.out", "S1.in")
\rS2.in\r \rS2.out\rCopy("S2.out", "S2.in")
\rS3.in\r \rS3.out\rCopy("S3.out", "S3.in")
\rS4.in\r \rS4.out\rCopy("S4.out", "S4.in")
- \rSConstruct\r \r.\r"""
+ \rSConstruct\r \r.\r""",'utf-8')
if os.linesep != '\n':
expect = expect.replace('\n', os.linesep)
diff --git a/test/Progress/spinner.py b/test/Progress/spinner.py
index 85ca32f..59c0a89 100644
--- a/test/Progress/spinner.py
+++ b/test/Progress/spinner.py
@@ -33,6 +33,7 @@ import os
import TestSCons
+
test = TestSCons.TestSCons(universal_newlines=None)
test.write('SConstruct', r"""
@@ -50,12 +51,12 @@ test.write('S2.in', "S2.in\n")
test.write('S3.in', "S3.in\n")
test.write('S4.in', "S4.in\n")
-expect = """\
+expect = bytearray("""\
\\\r|\rCopy("S1.out", "S1.in")
/\r-\rCopy("S2.out", "S2.in")
\\\r|\rCopy("S3.out", "S3.in")
/\r-\rCopy("S4.out", "S4.in")
-\\\r|\r"""
+\\\r|\r""",'utf-8')
if os.linesep != '\n':
expect = expect.replace('\n', os.linesep)
diff --git a/test/SConsignFile/use-dbm.py b/test/SConsignFile/use-dbm.py
index 90983b3..129d5b6 100644
--- a/test/SConsignFile/use-dbm.py
+++ b/test/SConsignFile/use-dbm.py
@@ -34,10 +34,16 @@ _python_ = TestSCons._python_
test = TestSCons.TestSCons()
+
try:
import dbm.ndbm
+ use_db = 'dbm.ndbm'
except ImportError:
- test.skip_test('No dbm in this version of Python; skipping test.\n')
+ try:
+ import dbm
+ use_db = 'dbm'
+ except ImportError:
+ test.skip_test('No dbm.ndbm in this version of Python; skipping test.\n')
test.subdir('subdir')
@@ -53,8 +59,8 @@ sys.exit(0)
#
test.write('SConstruct', """
import sys
-import dbm
-SConsignFile('.sconsign', dbm)
+import %(use_db)s
+SConsignFile('.sconsign', %(use_db)s)
B = Builder(action = '%(_python_)s build.py $TARGETS $SOURCES')
env = Environment(BUILDERS = { 'B' : B })
env.B(target = 'f1.out', source = 'f1.in')
diff --git a/test/SWIG/recursive-includes-cpp.py b/test/SWIG/recursive-includes-cpp.py
index 364bd73..dbcac6d 100644
--- a/test/SWIG/recursive-includes-cpp.py
+++ b/test/SWIG/recursive-includes-cpp.py
@@ -64,6 +64,7 @@ test.write("mod.i", """\
test.write('SConstruct', """\
import distutils.sysconfig
+import sys
DefaultEnvironment( tools = [ 'swig' ] )
@@ -77,6 +78,9 @@ env = Environment(
SHLIBPREFIX = ""
)
+if sys.platform == 'darwin':
+ env['LIBS']=['python%d.%d'%(sys.version_info[0],sys.version_info[1])]
+
env.SharedLibrary(
'mod.so',
[
diff --git a/test/Subst/TypeError.py b/test/Subst/TypeError.py
index 371ceff..628db2f 100644
--- a/test/Subst/TypeError.py
+++ b/test/Subst/TypeError.py
@@ -58,9 +58,7 @@ expect = expect_build % (r' \[foo\.bar\]', r'\$\{NONE\[0\]\}')
test.run(status=2, stderr=expect)
-
-
-expect_build = r"""scons: \*\*\*%s TypeError `(not enough arguments; expected 3, got 1|func\(\) takes exactly 3 arguments \(1 given\))' trying to evaluate `%s'
+expect_build = r"""scons: \*\*\*%s TypeError `(not enough arguments; expected 3, got 1|func\(\) takes exactly 3 arguments \(1 given\)|func\(\) missing 2 required positional arguments: 'b' and 'c')' trying to evaluate `%s'
"""
expect_read = "\n" + expect_build + TestSCons.file_expr
diff --git a/test/TEX/auxiliaries.py b/test/TEX/auxiliaries.py
index 98cbf41..8d220c5 100644
--- a/test/TEX/auxiliaries.py
+++ b/test/TEX/auxiliaries.py
@@ -120,7 +120,7 @@ test.write(['docs', 'test.tex'], tex_input)
test.run(stderr=None)
pdf_output_1 = test.read(['build', 'docs', 'test.pdf'])
-ps_output_1 = test.read(['build', 'docs', 'test.ps'])
+ps_output_1 = test.read(['build', 'docs', 'test.ps'], mode='r')
# Adding blank lines will cause SCons to re-run the builds, but the
# actual contents of the output files should be the same modulo
@@ -130,7 +130,7 @@ test.write(['docs', 'test.tex'], tex_input + "\n\n\n")
test.run(stderr=None)
pdf_output_2 = test.read(['build', 'docs', 'test.pdf'])
-ps_output_2 = test.read(['build', 'docs', 'test.ps'])
+ps_output_2 = test.read(['build', 'docs', 'test.ps'], mode='r')
diff --git a/test/diskcheck.py b/test/diskcheck.py
index adbeea1..36cfa4e 100644
--- a/test/diskcheck.py
+++ b/test/diskcheck.py
@@ -52,30 +52,6 @@ test.must_contain_all_lines(test.stderr(), ["found where file expected"])
-test.write('SConstruct', """
-SetOption('diskcheck', ['rcs', 'sccs'])
-Dir('file')
-""")
-
-test.run()
-
-test.run(arguments='--diskcheck=match', status=2, stderr=None)
-test.must_contain_all_lines(test.stderr(), ["found where directory expected"])
-
-
-
-test.write('SConstruct', """
-SetOption('diskcheck', 'rcs,sccs')
-Dir('file/subdir')
-""")
-
-test.run()
-
-test.run(arguments='--diskcheck=match', status=2, stderr=None)
-test.must_contain_all_lines(test.stderr(), ["found where directory expected"])
-
-
-
test.pass_test()
# Local Variables:
diff --git a/test/gettext/POTUpdate/UserExamples.py b/test/gettext/POTUpdate/UserExamples.py
index 6269081..06203fa 100644
--- a/test/gettext/POTUpdate/UserExamples.py
+++ b/test/gettext/POTUpdate/UserExamples.py
@@ -62,19 +62,19 @@ test.must_not_exist( ['ex1', 'po', 'bar.pot'] )
test.run(arguments = 'foo.pot', chdir = path.join('ex1', 'po'))
test.must_exist( ['ex1', 'po', 'foo.pot'] )
test.must_not_exist( ['ex1', 'po', 'bar.pot'] )
-test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from a.cpp" )
-test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from b.cpp" )
-test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from c.cpp" )
-test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from d.cpp" )
+test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from a.cpp", mode='r')
+test.must_contain( ['ex1', 'po', 'foo.pot'], "Hello from b.cpp", mode='r')
+test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from c.cpp", mode='r')
+test.must_not_contain( ['ex1', 'po', 'foo.pot'], "Hello from d.cpp", mode='r')
# scons 'pot-update' creates foo.pot and bar.pot
test.run(arguments = 'pot-update', chdir = path.join('ex1', 'po'))
test.must_exist( ['ex1', 'po', 'foo.pot'] )
test.must_exist( ['ex1', 'po', 'bar.pot'] )
-test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from a.cpp" )
-test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from b.cpp" )
-test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from c.cpp" )
-test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from d.cpp" )
+test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from a.cpp", mode='r')
+test.must_not_contain( ['ex1', 'po', 'bar.pot'], "Hello from b.cpp", mode='r')
+test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from c.cpp", mode='r')
+test.must_contain( ['ex1', 'po', 'bar.pot'], "Hello from d.cpp", mode='r')
# scons -c does not clean anything
test.run(arguments = '-c', chdir = path.join('ex1', 'po'))
@@ -101,16 +101,16 @@ test.write(['ex2', 'd.cpp'], """ gettext("Hello from d.cpp") """)
test.run(arguments = 'pot-update', chdir = path.join('ex2'))
test.must_exist( ['ex2', 'foo.pot'])
-test.must_contain( ['ex2', 'foo.pot'], "Hello from a.cpp" )
-test.must_contain( ['ex2', 'foo.pot'], "Hello from b.cpp" )
-test.must_not_contain( ['ex2', 'foo.pot'], "Hello from c.cpp" )
-test.must_not_contain( ['ex2', 'foo.pot'], "Hello from d.cpp" )
+test.must_contain( ['ex2', 'foo.pot'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex2', 'foo.pot'], "Hello from b.cpp", mode='r' )
+test.must_not_contain( ['ex2', 'foo.pot'], "Hello from c.cpp", mode='r' )
+test.must_not_contain( ['ex2', 'foo.pot'], "Hello from d.cpp", mode='r' )
test.must_exist( ['ex2', 'bar.pot'])
-test.must_not_contain( ['ex2', 'bar.pot'], "Hello from a.cpp" )
-test.must_not_contain( ['ex2', 'bar.pot'], "Hello from b.cpp" )
-test.must_contain( ['ex2', 'bar.pot'], "Hello from c.cpp" )
-test.must_contain( ['ex2', 'bar.pot'], "Hello from d.cpp" )
+test.must_not_contain( ['ex2', 'bar.pot'], "Hello from a.cpp", mode='r' )
+test.must_not_contain( ['ex2', 'bar.pot'], "Hello from b.cpp", mode='r' )
+test.must_contain( ['ex2', 'bar.pot'], "Hello from c.cpp", mode='r' )
+test.must_contain( ['ex2', 'bar.pot'], "Hello from d.cpp", mode='r' )
#############################################################################
@@ -192,9 +192,9 @@ test.write(['ex5', '0', '1', 'a.cpp'], """ gettext("Hello from ../a.cpp") """)
test.run(arguments = 'pot-update', chdir = path.join('ex5', '0', '1', 'po'))
test.must_exist( ['ex5', '0', '1', 'po', 'messages.pot'])
test.must_contain( ['ex5', '0', '1', 'po', 'messages.pot'],
- 'Hello from ../a.cpp' )
+ 'Hello from ../a.cpp', mode='r' )
test.must_not_contain( ['ex5', '0', '1', 'po', 'messages.pot'],
- 'Hello from ../../a.cpp' )
+ 'Hello from ../../a.cpp', mode='r' )
test.write(['ex5', '0', '1', 'po', 'SConstruct'],
"""
@@ -204,9 +204,9 @@ env.POTUpdate(XGETTEXTFROM = 'POTFILES.in', XGETTEXTPATH=['../../', '../'])
""")
test.run(arguments = 'pot-update', chdir = path.join('ex5', '0', '1', 'po'))
test.must_contain( ['ex5', '0', '1', 'po', 'messages.pot'],
- 'Hello from ../../a.cpp' )
+ 'Hello from ../../a.cpp', mode='r' )
test.must_not_contain( ['ex5', '0', '1', 'po', 'messages.pot'],
- 'Hello from ../a.cpp')
+ 'Hello from ../a.cpp', mode='r')
test.pass_test()
diff --git a/test/gettext/POUpdate/UserExamples.py b/test/gettext/POUpdate/UserExamples.py
index 01d3706..5f3e6c7 100644
--- a/test/gettext/POUpdate/UserExamples.py
+++ b/test/gettext/POUpdate/UserExamples.py
@@ -182,8 +182,8 @@ test.write(['ex1', 'pl.po'], pl_po_contents)
test.run(arguments = 'po-update', chdir = 'ex1', stderr = None)
test.must_exist( ['ex1', 'en.po'] )
test.must_exist( ['ex1', 'pl.po'] )
-test.must_contain( ['ex1', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex1', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex1', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex1', 'pl.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 2
@@ -205,8 +205,8 @@ test.write(['ex2', 'pl.po'], pl_po_contents)
test.run(arguments = 'po-update', chdir = 'ex2', stderr = None)
test.must_exist( ['ex2', 'en.po'] )
test.must_exist( ['ex2', 'pl.po'] )
-test.must_contain( ['ex2', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex2', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex2', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex2', 'pl.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 3
@@ -228,8 +228,8 @@ test.write(['ex3', 'pl.po'], pl_po_contents)
test.run(arguments = 'po-update', chdir = 'ex3', stderr = None)
test.must_exist( ['ex3', 'en.po'] )
test.must_exist( ['ex3', 'pl.po'] )
-test.must_contain( ['ex3', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex3', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex3', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex3', 'pl.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 4
@@ -258,8 +258,8 @@ test.run(arguments = 'po-update', chdir = 'ex4', stderr = None)
test.must_exist( ['ex4', 'messages.pot'] )
test.must_exist( ['ex4', 'en.po'] )
test.must_exist( ['ex4', 'pl.po'] )
-test.must_contain( ['ex4', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex4', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex4', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex4', 'pl.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 5
@@ -286,8 +286,8 @@ test.write(['ex5', 'pl.po'], pl_po_contents)
test.run(arguments = 'po-update', chdir= 'ex5', stderr = None)
test.must_exist( ['ex5', 'en.po'] )
test.must_exist( ['ex5', 'pl.po'] )
-test.must_contain( ['ex5', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex5', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex5', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex5', 'pl.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 6
@@ -317,10 +317,10 @@ test.must_exist( ['ex6', 'en.po'] )
test.must_exist( ['ex6', 'pl.po'] )
test.must_exist( ['ex6', 'de.po'] )
test.must_exist( ['ex6', 'fr.po'] )
-test.must_contain( ['ex6', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex6', 'pl.po'], "Hello from a.cpp" )
-test.must_contain( ['ex6', 'de.po'], "Hello from a.cpp" )
-test.must_contain( ['ex6', 'fr.po'], "Hello from a.cpp" )
+test.must_contain( ['ex6', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex6', 'pl.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex6', 'de.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex6', 'fr.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 7
@@ -351,8 +351,8 @@ test.write(['ex7', 'messages.pot'], pot_contents)
test.run(arguments = 'po-update', chdir= 'ex7', stderr = None)
test.must_exist( ['ex7', 'en.po'] )
test.must_exist( ['ex7', 'pl.po'] )
-test.must_contain( ['ex7', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex7', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex7', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex7', 'pl.po'], "Hello from a.cpp", mode='r' )
#############################################################################
# POUpdate: Example 8
@@ -389,8 +389,8 @@ test.run(arguments = 'po-update', chdir = 'ex8', stderr = None)
test.must_exist( ['ex8', 'foo.pot'] )
test.must_exist( ['ex8', 'en.po'] )
test.must_exist( ['ex8', 'pl.po'] )
-test.must_contain( ['ex8', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex8', 'pl.po'], "Hello from a.cpp" )
+test.must_contain( ['ex8', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex8', 'pl.po'], "Hello from a.cpp", mode='r' )
test.pass_test()
diff --git a/test/gettext/Translate/UserExamples.py b/test/gettext/Translate/UserExamples.py
index 384b96d..d7220a3 100644
--- a/test/gettext/Translate/UserExamples.py
+++ b/test/gettext/Translate/UserExamples.py
@@ -65,10 +65,10 @@ test.write(['ex1', 'b.cpp'], """ gettext("Hello from b.cpp") """)
test.run(arguments = 'po-update', chdir = path.join('ex1','po'), stderr = None)
test.must_exist( ['ex1', 'po', 'en.po'] )
test.must_exist( ['ex1', 'po', 'pl.po'] )
-test.must_contain( ['ex1', 'po', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex1', 'po', 'en.po'], "Hello from b.cpp" )
-test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from a.cpp" )
-test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from b.cpp" )
+test.must_contain( ['ex1', 'po', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex1', 'po', 'en.po'], "Hello from b.cpp", mode='r' )
+test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex1', 'po', 'pl.po'], "Hello from b.cpp", mode='r' )
#############################################################################
# Translate: Example 2
@@ -100,10 +100,10 @@ test.write(['ex2', 'b.cpp'], """ gettext("Hello from b.cpp") """)
test.run(arguments = 'po-update', chdir = path.join('ex2','po'), stderr = None)
test.must_exist( ['ex2', 'po', 'en.po'] )
test.must_exist( ['ex2', 'po', 'pl.po'] )
-test.must_contain( ['ex2', 'po', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex2', 'po', 'en.po'], "Hello from b.cpp" )
-test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from a.cpp" )
-test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from b.cpp" )
+test.must_contain( ['ex2', 'po', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex2', 'po', 'en.po'], "Hello from b.cpp", mode='r' )
+test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex2', 'po', 'pl.po'], "Hello from b.cpp", mode='r' )
#############################################################################
# Translate: Example 3
@@ -157,12 +157,12 @@ test.must_not_exist( ['ex3', 'build', 'po', 'messages.pot'] )
test.must_not_exist( ['ex3', 'build', 'po', 'en.po'] )
test.must_not_exist( ['ex3', 'build', 'po', 'pl.po'] )
#
-test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from a.cpp" )
-test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from b.cpp" )
-test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from a.cpp" )
-test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from b.cpp" )
-test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from a.cpp" )
-test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from b.cpp" )
+test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex3', 'src', 'po', 'messages.pot'], "Hello from b.cpp", mode='r' )
+test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex3', 'src', 'po', 'en.po'], "Hello from b.cpp", mode='r' )
+test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from a.cpp", mode='r' )
+test.must_contain( ['ex3', 'src', 'po', 'pl.po'], "Hello from b.cpp", mode='r' )
test.run(arguments = '.', chdir = 'ex3', stderr = None)
test.must_exist( ['ex3', 'build', 'po', 'en.mo'] )
diff --git a/test/leaky-handles.py b/test/leaky-handles.py
index 9502d1b..3787ee2 100644
--- a/test/leaky-handles.py
+++ b/test/leaky-handles.py
@@ -29,12 +29,13 @@ Verify that file handles aren't leaked to child processes
"""
import os
+import sys
import TestSCons
test = TestSCons.TestSCons()
-if os.name != 'posix':
+if os.name != 'posix' or sys.platform == 'darwin':
msg = "Skipping fork leak test on non-posix platform '%s'\n" % os.name
test.skip_test(msg)
diff --git a/test/option--max-drift.py b/test/option--max-drift.py
index 08fafd1..4e063c9 100644
--- a/test/option--max-drift.py
+++ b/test/option--max-drift.py
@@ -109,14 +109,14 @@ atime = os.path.getatime(test.workpath('foo.in'))
mtime = os.path.getmtime(test.workpath('foo.in'))
test.run()
-test.fail_test(test.read('foo.out') != 'foo.in\n')
+test.must_match('foo.out', 'foo.in\n', mode='r')
test.write('foo.in', 'foo.in delta\n')
os.utime(test.workpath('foo.in'), (atime,mtime))
test.run()
-test.fail_test(test.read('foo.out') != 'foo.in\n')
+test.must_match('foo.out', 'foo.in\n', mode='r')
test.pass_test()
diff --git a/test/option--tree.py b/test/option--tree.py
index a50433c..a9618d8 100644
--- a/test/option--tree.py
+++ b/test/option--tree.py
@@ -51,6 +51,30 @@ scons: warning: The --debug=tree option is deprecated; please use --tree=all ins
""",
status = 0, match=TestSCons.match_re_dotall)
+
+# Test that unicode characters can be printed (escaped) with the --tree option
+test.write('SConstruct',
+"""
+env = Environment()
+env.Tool("textfile")
+try:
+ # Python 2
+ write = unichr(0xe7).encode('utf-8')
+except NameError:
+ # Python 3
+ # str is utf-8 by default
+ write = chr(0xe7)
+env.Textfile("Foo", write)
+""")
+
+test.run(arguments = '-Q --tree=all',
+ stdout = """Creating 'Foo.txt'
++-.
+ +-Foo.txt
+ | +-\\xc3\\xa7
+ +-SConstruct
+""",
+ status = 0)
test.pass_test()
# Local Variables:
diff --git a/test/option-j.py b/test/option-j.py
index 3dbedc0..278fd30 100644
--- a/test/option-j.py
+++ b/test/option-j.py
@@ -122,7 +122,7 @@ test.fail_test(start2 < finish1)
# succeeds.
test.run(arguments='-j 2 out')
-if sys.platform != 'win32':
+if sys.platform != 'win32' and sys.version_info[0] == 2:
# Test breaks on win32 when using real subprocess is not the only
# package to import threading
#
diff --git a/test/packaging/use-builddir.py b/test/packaging/use-builddir.py
index 76b9737..9ad7aa4 100644
--- a/test/packaging/use-builddir.py
+++ b/test/packaging/use-builddir.py
@@ -85,7 +85,7 @@ test.run(stderr = None)
test.must_exist( 'libfoo-1.2.3.tar.gz' )
-os.popen( 'tar -C temp -xzf %s'%test.workpath('libfoo-1.2.3.tar.gz') )
+os.system('tar -C temp -xzf %s'%test.workpath('libfoo-1.2.3.tar.gz') )
test.must_exist( 'temp/libfoo-1.2.3/src/main.c' )
test.must_exist( 'temp/libfoo-1.2.3/SConstruct' )
diff --git a/test/redirection.py b/test/redirection.py
index ffc76b5..ba35ed0 100644
--- a/test/redirection.py
+++ b/test/redirection.py
@@ -32,11 +32,22 @@ test = TestSCons.TestSCons()
test.write('cat.py', r"""
import sys
+PY3K = sys.version_info >= (3, 0)
+
try:
- input = open(sys.argv[1], 'r').read()
+ input = open(sys.argv[1], 'rb').read()
except IndexError:
- input = sys.stdin.read()
-sys.stdout.write(input)
+ if PY3K:
+ source = sys.stdin.buffer
+ else:
+ source = sys.stdin
+ input = source.read()
+
+if PY3K:
+ sys.stdout.buffer.write(input)
+else:
+ sys.stdout.write(input)
+
sys.exit(0)
""")
diff --git a/test/scons-time/run/option/verbose.py b/test/scons-time/run/option/verbose.py
index 5fc6d64..0ef2a6c 100644
--- a/test/scons-time/run/option/verbose.py
+++ b/test/scons-time/run/option/verbose.py
@@ -30,7 +30,7 @@ Verify that the run -v and --verbose options display command output.
import sys
import re
-
+import os
import TestSCons_time
_python_ = re.escape('"' + sys.executable + '"')
@@ -112,7 +112,9 @@ scons-time%(time_re)s: %(_python_)s %(scons_py)s %(scons_flags)s --profile=%(pro
SCONS_LIB_DIR = %(src_engine)s
SConstruct file directory: %(tmp_scons_time_foo)s
scons-time%(time_re)s: cd .*
-scons-time%(time_re)s: rm -rf %(tmp_scons_time)s
+"""
+if 'PRESERVE' not in os.environ or not os.environ['PRESERVE']:
+ expect += """scons-time%(time_re)s: rm -rf %(tmp_scons_time)s
"""
foo_tar_gz = re.escape(foo_tar_gz)