summaryrefslogtreecommitdiff
path: root/QMTest/TestSCons.py
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2019-07-14 08:35:24 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2019-07-14 08:35:24 +0200
commit697e33ed224b539a42ff68121f7497f5bbf941b2 (patch)
tree44ae83ad6ad4a7f6762a6d1bfde3766a1993b5ec /QMTest/TestSCons.py
parentbaee03c569c91b745a1e025660b19a718db16e7d (diff)
New upstream version 3.0.5upstream/3.0.5
Diffstat (limited to 'QMTest/TestSCons.py')
-rw-r--r--QMTest/TestSCons.py1617
1 files changed, 0 insertions, 1617 deletions
diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py
deleted file mode 100644
index c0b4ebc..0000000
--- a/QMTest/TestSCons.py
+++ /dev/null
@@ -1,1617 +0,0 @@
-"""
-TestSCons.py: a testing framework for the SCons software construction
-tool.
-
-A TestSCons environment object is created via the usual invocation:
-
- test = TestSCons()
-
-TestScons is a subclass of TestCommon, which in turn is a subclass
-of TestCmd), and hence has available all of the methods and attributes
-from those classes, as well as any overridden or additional methods or
-attributes defined in this subclass.
-"""
-
-# Copyright (c) 2001 - 2017 The SCons Foundation
-from __future__ import division, print_function
-
-__revision__ = "QMTest/TestSCons.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-import os
-import re
-import shutil
-import sys
-import time
-import subprocess
-
-from TestCommon import *
-from TestCommon import __all__
-
-from TestCmd import Popen
-from TestCmd import PIPE
-
-# Some tests which verify that SCons has been packaged properly need to
-# look for specific version file names. Replicating the version number
-# here provides some independent verification that what we packaged
-# conforms to what we expect.
-
-default_version = '3.0.0'
-
-python_version_unsupported = (2, 6, 0)
-python_version_deprecated = (2, 7, 0)
-
-# In the checked-in source, the value of SConsVersion in the following
-# line must remain "__ VERSION __" (without the spaces) so the built
-# version in build/QMTest/TestSCons.py contains the actual version
-# string of the packages that have been built.
-SConsVersion = '3.0.0'
-if SConsVersion == '__' + 'VERSION' + '__':
- SConsVersion = default_version
-
-__all__.extend([
- 'TestSCons',
- 'machine',
- 'python',
- '_exe',
- '_obj',
- '_shobj',
- 'shobj_',
- 'lib_',
- '_lib',
- 'dll_',
- '_dll'
- ])
-
-machine_map = {
- 'i686' : 'i386',
- 'i586' : 'i386',
- 'i486' : 'i386',
-}
-
-try:
- uname = os.uname
-except AttributeError:
- # Windows doesn't have a uname() function. We could use something like
- # sys.platform as a fallback, but that's not really a "machine," so
- # just leave it as None.
- machine = None
-else:
- machine = uname()[4]
- machine = machine_map.get(machine, machine)
-
-_exe = exe_suffix
-_obj = obj_suffix
-_shobj = shobj_suffix
-shobj_ = shobj_prefix
-_lib = lib_suffix
-lib_ = lib_prefix
-_dll = dll_suffix
-dll_ = dll_prefix
-
-
-if sys.platform == 'cygwin':
- # On Cygwin, os.path.normcase() lies, so just report back the
- # fact that the underlying Win32 OS is case-insensitive.
- def case_sensitive_suffixes(s1, s2):
- return 0
-else:
- def case_sensitive_suffixes(s1, s2):
- return (os.path.normcase(s1) != os.path.normcase(s2))
-
-
-file_expr = r"""File "[^"]*", line \d+, in [^\n]+
-"""
-
-# re.escape escapes too much.
-def re_escape(str):
- for c in '\\.[]()*+?': # Not an exhaustive list.
- str = str.replace(c, '\\' + c)
- return str
-
-#
-# Helper functions that we use as a replacement to the default re.match
-# when searching for special strings in stdout/stderr.
-#
-def search_re(out, l):
- """ Search the regular expression 'l' in the output 'out'
- and return the start index when successful.
- """
- m = re.search(l, out)
- if m:
- return m.start()
-
- return None
-
-def search_re_in_list(out, l):
- """ Search the regular expression 'l' in each line of
- the given string list 'out' and return the line's index
- when successful.
- """
- for idx, o in enumerate(out):
- m = re.search(l, o)
- if m:
- return idx
-
- return None
-
-#
-# Helpers for handling Python version numbers
-#
-def python_version_string():
- return sys.version.split()[0]
-
-def python_minor_version_string():
- return sys.version[:3]
-
-def unsupported_python_version(version=sys.version_info):
- return version < python_version_unsupported
-
-def deprecated_python_version(version=sys.version_info):
- return version < python_version_deprecated
-
-if deprecated_python_version():
- msg = r"""
-scons: warning: Support for pre-2.7.0 Python version (%s) is deprecated.
- If this will cause hardship, contact scons-dev@scons.org
-"""
-
- deprecated_python_expr = re_escape(msg % python_version_string()) + file_expr
- del msg
-else:
- deprecated_python_expr = ""
-
-
-def initialize_sconsflags(ignore_python_version):
- """
- Add the --warn=no-python-version option to SCONSFLAGS for every
- command so test scripts don't have to filter out Python version
- deprecation warnings.
- Same for --warn=no-visual-c-missing.
- """
- save_sconsflags = os.environ.get('SCONSFLAGS')
- if save_sconsflags:
- sconsflags = [save_sconsflags]
- else:
- sconsflags = []
- if ignore_python_version and deprecated_python_version():
- sconsflags.append('--warn=no-python-version')
- # Provide a way to suppress or provide alternate flags for
- # TestSCons purposes by setting TESTSCONS_SCONSFLAGS.
- # (The intended use case is to set it to null when running
- # timing tests of earlier versions of SCons which don't
- # support the --warn=no-visual-c-missing warning.)
- visual_c = os.environ.get('TESTSCONS_SCONSFLAGS',
- '--warn=no-visual-c-missing')
- if visual_c:
- sconsflags.append(visual_c)
- os.environ['SCONSFLAGS'] = ' '.join(sconsflags)
- return save_sconsflags
-
-def restore_sconsflags(sconsflags):
- if sconsflags is None:
- del os.environ['SCONSFLAGS']
- else:
- os.environ['SCONSFLAGS'] = sconsflags
-
-
-class TestSCons(TestCommon):
- """Class for testing SCons.
-
- This provides a common place for initializing SCons tests,
- eliminating the need to begin every test with the same repeated
- initializations.
- """
-
- scons_version = SConsVersion
- javac_is_gcj = False
-
- def __init__(self, **kw):
- """Initialize an SCons testing object.
-
- If they're not overridden by keyword arguments, this
- initializes the object with the following default values:
-
- program = 'scons' if it exists,
- else 'scons.py'
- interpreter = 'python'
- match = match_exact
- workdir = ''
-
- The workdir value means that, by default, a temporary workspace
- directory is created for a TestSCons environment. In addition,
- this method changes directory (chdir) to the workspace directory,
- so an explicit "chdir = '.'" on all of the run() method calls
- is not necessary.
- """
- self.orig_cwd = os.getcwd()
- self.external = os.environ.get('SCONS_EXTERNAL_TEST', 0)
-
- if not self.external:
- try:
- script_dir = os.environ['SCONS_SCRIPT_DIR']
- except KeyError:
- pass
- else:
- os.chdir(script_dir)
- if 'program' not in kw:
- kw['program'] = os.environ.get('SCONS')
- if not kw['program']:
- if not self.external:
- if os.path.exists('scons'):
- kw['program'] = 'scons'
- else:
- kw['program'] = 'scons.py'
- else:
- kw['program'] = 'scons'
- kw['interpreter'] = ''
- elif not self.external and not os.path.isabs(kw['program']):
- kw['program'] = os.path.join(self.orig_cwd, kw['program'])
- if 'interpreter' not in kw and not os.environ.get('SCONS_EXEC'):
- kw['interpreter'] = [python, '-tt']
- if 'match' not in kw:
- kw['match'] = match_exact
- if 'workdir' not in kw:
- kw['workdir'] = ''
-
- # Term causing test failures due to bogus readline init
- # control character output on FC8
- # TERM can cause test failures due to control chars in prompts etc.
- os.environ['TERM'] = 'dumb'
-
- self.ignore_python_version = kw.get('ignore_python_version', 1)
- if kw.get('ignore_python_version', -1) != -1:
- del kw['ignore_python_version']
-
- TestCommon.__init__(self, **kw)
-
- if not self.external:
- import SCons.Node.FS
- if SCons.Node.FS.default_fs is None:
- SCons.Node.FS.default_fs = SCons.Node.FS.FS()
-
- try:
- self.fixture_dirs = (os.environ['FIXTURE_DIRS']).split(os.pathsep)
- except KeyError:
- pass
-
- def Environment(self, ENV=None, *args, **kw):
- """
- Return a construction Environment that optionally overrides
- the default external environment with the specified ENV.
- """
- if not self.external:
- import SCons.Environment
- import SCons.Errors
- if not ENV is None:
- kw['ENV'] = ENV
- try:
- return SCons.Environment.Environment(*args, **kw)
- except (SCons.Errors.UserError, SCons.Errors.InternalError):
- return None
-
- return None
-
- def detect(self, var, prog=None, ENV=None, norm=None):
- """
- Detect a program named 'prog' by first checking the construction
- variable named 'var' and finally searching the path used by
- SCons. If either method fails to detect the program, then false
- is returned, otherwise the full path to prog is returned. If
- prog is None, then the value of the environment variable will be
- used as prog.
- """
- env = self.Environment(ENV)
- if env:
- v = env.subst('$'+var)
- if not v:
- return None
- if prog is None:
- prog = v
- if v != prog:
- return None
- result = env.WhereIs(prog)
- if norm and os.sep != '/':
- result = result.replace(os.sep, '/')
- return result
-
- return self.where_is(prog)
-
- def detect_tool(self, tool, prog=None, ENV=None):
- """
- Given a tool (i.e., tool specification that would be passed
- to the "tools=" parameter of Environment()) and a program that
- corresponds to that tool, return true if and only if we can find
- that tool using Environment.Detect().
-
- By default, prog is set to the value passed into the tools parameter.
- """
-
- if not prog:
- prog = tool
- env = self.Environment(ENV, tools=[tool])
- if env is None:
- return None
- return env.Detect([prog])
-
- def where_is(self, prog, path=None):
- """
- Given a program, search for it in the specified external PATH,
- or in the actual external PATH if none is specified.
- """
- if path is None:
- path = os.environ['PATH']
- if self.external:
- if isinstance(prog, str):
- prog = [prog]
- import stat
- paths = path.split(os.pathsep)
- for p in prog:
- for d in paths:
- f = os.path.join(d, p)
- if os.path.isfile(f):
- try:
- st = os.stat(f)
- except OSError:
- # os.stat() raises OSError, not IOError if the file
- # doesn't exist, so in this case we let IOError get
- # raised so as to not mask possibly serious disk or
- # network issues.
- continue
- if stat.S_IMODE(st[stat.ST_MODE]) & 0o111:
- return os.path.normpath(f)
- else:
- import SCons.Environment
- env = SCons.Environment.Environment()
- return env.WhereIs(prog, path)
-
- return None
-
- def wrap_stdout(self, build_str = "", read_str = "", error = 0, cleaning = 0):
- """Wraps standard output string(s) in the normal
- "Reading ... done" and "Building ... done" strings
- """
- cap,lc = [ ('Build','build'),
- ('Clean','clean') ][cleaning]
- if error:
- term = "scons: %sing terminated because of errors.\n" % lc
- else:
- term = "scons: done %sing targets.\n" % lc
- return "scons: Reading SConscript files ...\n" + \
- read_str + \
- "scons: done reading SConscript files.\n" + \
- "scons: %sing targets ...\n" % cap + \
- build_str + \
- term
-
- def run(self, *args, **kw):
- """
- Set up SCONSFLAGS for every command so test scripts don't need
- to worry about unexpected warnings in their output.
- """
- sconsflags = initialize_sconsflags(self.ignore_python_version)
- try:
- TestCommon.run(self, *args, **kw)
- finally:
- restore_sconsflags(sconsflags)
-
-# Modifying the options should work and ought to be simpler, but this
-# class is used for more than just running 'scons' itself. If there's
-# an automated way of determining whether it's running 'scons' or
-# something else, this code should be resurected.
-# options = kw.get('options')
-# if options:
-# options = [options]
-# else:
-# options = []
-# if self.ignore_python_version and deprecated_python_version():
-# options.append('--warn=no-python-version')
-# # Provide a way to suppress or provide alternate flags for
-# # TestSCons purposes by setting TESTSCONS_SCONSFLAGS.
-# # (The intended use case is to set it to null when running
-# # timing tests of earlier versions of SCons which don't
-# # support the --warn=no-visual-c-missing warning.)
-# visual_c = os.environ.get('TESTSCONS_SCONSFLAGS',
-# '--warn=no-visual-c-missing')
-# if visual_c:
-# options.append(visual_c)
-# kw['options'] = ' '.join(options)
-# TestCommon.run(self, *args, **kw)
-
- def up_to_date(self, arguments = '.', read_str = "", **kw):
- s = ""
- for arg in arguments.split():
- s = s + "scons: `%s' is up to date.\n" % arg
- kw['arguments'] = arguments
- stdout = self.wrap_stdout(read_str = read_str, build_str = s)
- # Append '.*' so that timing output that comes after the
- # up-to-date output is okay.
- kw['stdout'] = re.escape(stdout) + '.*'
- kw['match'] = self.match_re_dotall
- self.run(**kw)
-
- def not_up_to_date(self, arguments = '.', **kw):
- """Asserts that none of the targets listed in arguments is
- up to date, but does not make any assumptions on other targets.
- This function is most useful in conjunction with the -n option.
- """
- s = ""
- for arg in arguments.split():
- s = s + "(?!scons: `%s' is up to date.)" % re.escape(arg)
- s = '('+s+'[^\n]*\n)*'
- kw['arguments'] = arguments
- stdout = re.escape(self.wrap_stdout(build_str='ARGUMENTSGOHERE'))
- kw['stdout'] = stdout.replace('ARGUMENTSGOHERE', s)
- kw['match'] = self.match_re_dotall
- self.run(**kw)
-
- def option_not_yet_implemented(self, option, arguments=None, **kw):
- """
- Verifies expected behavior for options that are not yet implemented:
- a warning message, and exit status 1.
- """
- msg = "Warning: the %s option is not yet implemented\n" % option
- kw['stderr'] = msg
- if arguments:
- # If it's a long option and the argument string begins with '=',
- # it's of the form --foo=bar and needs no separating space.
- if option[:2] == '--' and arguments[0] == '=':
- kw['arguments'] = option + arguments
- else:
- kw['arguments'] = option + ' ' + arguments
- return self.run(**kw)
-
- def deprecated_wrap(self, msg):
- """
- Calculate the pattern that matches a deprecation warning.
- """
- return '\nscons: warning: ' + re_escape(msg) + '\n' + file_expr
-
- def deprecated_fatal(self, warn, msg):
- """
- Determines if the warning has turned into a fatal error. If so,
- passes the test, as any remaining runs are now moot.
-
- This method expects a SConscript to be present that will causes
- the warning. The method writes a SConstruct that calls the
- SConsscript and looks to see what type of result occurs.
-
- The pattern that matches the warning is returned.
-
- TODO: Actually detect that it's now an error. We don't have any
- cases yet, so there's no way to test it.
- """
- self.write('SConstruct', """if True:
- WARN = ARGUMENTS.get('WARN')
- if WARN: SetOption('warn', WARN)
- SConscript('SConscript')
- """)
-
- def err_out():
- # TODO calculate stderr for fatal error
- return re_escape('put something here')
-
- # no option, should get one of nothing, warning, or error
- warning = self.deprecated_wrap(msg)
- self.run(arguments = '.', stderr = None)
- stderr = self.stderr()
- if stderr:
- # most common case done first
- if match_re_dotall(stderr, warning):
- # expected output
- pass
- elif match_re_dotall(stderr, err_out()):
- # now a fatal error; skip the rest of the tests
- self.pass_test()
- else:
- # test failed; have to do this by hand...
- print(self.banner('STDOUT '))
- print(self.stdout())
- print(self.diff(warning, stderr, 'STDERR '))
- self.fail_test()
-
- return warning
-
- def deprecated_warning(self, warn, msg):
- """
- Verifies the expected behavior occurs for deprecation warnings.
- This method expects a SConscript to be present that will causes
- the warning. The method writes a SConstruct and exercises various
- combinations of command-line options and SetOption parameters to
- validate that it performs correctly.
-
- The pattern that matches the warning is returned.
- """
- warning = self.deprecated_fatal(warn, msg)
-
- def RunPair(option, expected):
- # run the same test with the option on the command line and
- # then with the option passed via SetOption().
- self.run(options = '--warn=' + option,
- arguments = '.',
- stderr = expected,
- match = match_re_dotall)
- self.run(options = 'WARN=' + option,
- arguments = '.',
- stderr = expected,
- match = match_re_dotall)
-
- # all warnings off, should get no output
- RunPair('no-deprecated', '')
-
- # warning enabled, should get expected output
- RunPair(warn, warning)
-
- # warning disabled, should get either nothing or mandatory message
- expect = """()|(Can not disable mandataory warning: 'no-%s'\n\n%s)""" % (warn, warning)
- RunPair('no-' + warn, expect)
-
- return warning
-
- def diff_substr(self, expect, actual, prelen=20, postlen=40):
- i = 0
- for x, y in zip(expect, actual):
- if x != y:
- return "Actual did not match expect at char %d:\n" \
- " Expect: %s\n" \
- " Actual: %s\n" \
- % (i, repr(expect[i-prelen:i+postlen]),
- repr(actual[i-prelen:i+postlen]))
- i = i + 1
- return "Actual matched the expected output???"
-
- def python_file_line(self, file, line):
- """
- Returns a Python error line for output comparisons.
-
- The exec of the traceback line gives us the correct format for
- this version of Python.
-
- File "<string>", line 1, <module>
-
- We stick the requested file name and line number in the right
- places, abstracting out the version difference.
- """
- # This routine used to use traceback to get the proper format
- # that doesn't work well with py3. And the format of the
- # traceback seems to be stable, so let's just format
- # an appropriate string
- #
- #exec('import traceback; x = traceback.format_stack()[-1]')
- # import traceback
- # x = traceback.format_stack()
- # x = # XXX: .lstrip()
- # x = x.replace('<string>', file)
- # x = x.replace('line 1,', 'line %s,' % line)
- # x="\n".join(x)
- x='File "%s", line %s, in <module>\n'%(file,line)
- return x
-
- def normalize_ps(self, s):
- s = re.sub(r'(Creation|Mod)Date: .*',
- r'\1Date XXXX', s)
- s = re.sub(r'%DVIPSSource:\s+TeX output\s.*',
- r'%DVIPSSource: TeX output XXXX', s)
- s = re.sub(r'/(BaseFont|FontName) /[A-Z0-9]{6}',
- r'/\1 /XXXXXX', s)
- s = re.sub(r'BeginFont: [A-Z0-9]{6}',
- r'BeginFont: XXXXXX', s)
-
- 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 = 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 = to_bytes('/FlateDecode\n>>\nstream\n')
- end_marker = to_bytes('endstream\nendobj')
-
- encoded = []
- b = s.find(begin_marker, 0)
- while b != -1:
- b = b + len(begin_marker)
- e = s.find(end_marker, b)
- encoded.append((b, e))
- b = s.find(begin_marker, e + len(end_marker))
-
- x = 0
- r = []
- for b, e in encoded:
- r.append(s[x:b])
- d = zlib.decompress(s[b:e])
- 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 = to_bytes('').join(r)
-
- return s
-
- def paths(self,patterns):
- import glob
- result = []
- for p in patterns:
- result.extend(sorted(glob.glob(p)))
- return result
-
- def unlink_sconsignfile(self,name='.sconsign.dblite'):
- """
- Delete sconsign file.
- Note on python it seems to append .p3 to the file name so we take care of that
- Parameters
- ----------
- name - expected name of sconsign file
-
- Returns
- -------
- None
- """
- if sys.version_info[0] == 3:
- name += '.p3'
- self.unlink(name)
-
- def java_ENV(self, version=None):
- """
- Initialize with a default external environment that uses a local
- Java SDK in preference to whatever's found in the default PATH.
- """
- if not self.external:
- try:
- return self._java_env[version]['ENV']
- except AttributeError:
- self._java_env = {}
- except KeyError:
- pass
-
- import SCons.Environment
- env = SCons.Environment.Environment()
- self._java_env[version] = env
-
-
- if version:
- patterns = [
- '/usr/java/jdk%s*/bin' % version,
- '/usr/lib/jvm/*-%s*/bin' % version,
- '/usr/local/j2sdk%s*/bin' % version,
- ]
- java_path = self.paths(patterns) + [env['ENV']['PATH']]
- else:
- patterns = [
- '/usr/java/latest/bin',
- '/usr/lib/jvm/*/bin',
- '/usr/local/j2sdk*/bin',
- ]
- java_path = self.paths(patterns) + [env['ENV']['PATH']]
-
- env['ENV']['PATH'] = os.pathsep.join(java_path)
- return env['ENV']
-
- return None
-
- def java_where_includes(self,version=None):
- """
- Return java include paths compiling java jni code
- """
- import sys
-
- result = []
- if sys.platform[:6] == 'darwin':
- java_home = self.java_where_java_home(version)
- jni_path = os.path.join(java_home,'include','jni.h')
- if os.path.exists(jni_path):
- result.append(os.path.dirname(jni_path))
-
- if not version:
- version=''
- jni_dirs = ['/System/Library/Frameworks/JavaVM.framework/Headers/jni.h',
- '/usr/lib/jvm/default-java/include/jni.h',
- '/usr/lib/jvm/java-*-oracle/include/jni.h']
- else:
- jni_dirs = ['/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/jni.h'%version]
- jni_dirs.extend(['/usr/lib/jvm/java-*-sun-%s*/include/jni.h'%version,
- '/usr/lib/jvm/java-%s*-openjdk*/include/jni.h'%version,
- '/usr/java/jdk%s*/include/jni.h'%version])
- dirs = self.paths(jni_dirs)
- if not dirs:
- return None
- d=os.path.dirname(self.paths(jni_dirs)[0])
- result.append(d)
-
- if sys.platform == 'win32':
- result.append(os.path.join(d,'win32'))
- elif sys.platform.startswith('linux'):
- result.append(os.path.join(d,'linux'))
- return result
-
- def java_where_java_home(self, version=None):
- if sys.platform[:6] == 'darwin':
- # osx 10.11, 10.12
- home_tool = '/usr/libexec/java_home'
- java_home = False
- if os.path.exists(home_tool):
- java_home = subprocess.check_output(home_tool).strip()
- java_home = java_home.decode()
-
- if version is None:
- if java_home:
- return java_home
- else:
- homes = ['/System/Library/Frameworks/JavaVM.framework/Home',
- # osx 10.10
- '/System/Library/Frameworks/JavaVM.framework/Versions/Current/Home']
- for home in homes:
- if os.path.exists(home):
- return home
-
- else:
- if java_home.find('jdk%s'%version) != -1:
- return java_home
- else:
- home = '/System/Library/Frameworks/JavaVM.framework/Versions/%s/Home' % version
- if not os.path.exists(home):
- # This works on OSX 10.10
- home = '/System/Library/Frameworks/JavaVM.framework/Versions/Current/'
- else:
- jar = self.java_where_jar(version)
- home = os.path.normpath('%s/..'%jar)
- if os.path.isdir(home):
- return home
- print("Could not determine JAVA_HOME: %s is not a directory" % home)
- self.fail_test()
-
- def java_where_jar(self, version=None):
- ENV = self.java_ENV(version)
- if self.detect_tool('jar', ENV=ENV):
- where_jar = self.detect('JAR', 'jar', ENV=ENV)
- else:
- where_jar = self.where_is('jar', ENV['PATH'])
- if not where_jar:
- self.skip_test("Could not find Java jar, skipping test(s).\n")
- return where_jar
-
- def java_where_java(self, version=None):
- """
- Return a path to the java executable.
- """
- ENV = self.java_ENV(version)
- where_java = self.where_is('java', ENV['PATH'])
- if not where_java:
- self.skip_test("Could not find Java java, skipping test(s).\n")
- return where_java
-
- def java_where_javac(self, version=None):
- """
- Return a path to the javac compiler.
- """
- ENV = self.java_ENV(version)
- if self.detect_tool('javac'):
- where_javac = self.detect('JAVAC', 'javac', ENV=ENV)
- else:
- where_javac = self.where_is('javac', ENV['PATH'])
- if not where_javac:
- self.skip_test("Could not find Java javac, skipping test(s).\n")
- self.run(program = where_javac,
- arguments = '-version',
- stderr=None,
- status=None)
- if version:
- if self.stderr().find('javac %s' % version) == -1:
- fmt = "Could not find javac for Java version %s, skipping test(s).\n"
- self.skip_test(fmt % version)
- else:
- m = re.search(r'javac (\d\.\d)', self.stderr())
- if m:
- version = m.group(1)
- self.javac_is_gcj = False
- elif self.stderr().find('gcj'):
- version='1.2'
- self.javac_is_gcj = True
- else:
- version = None
- self.javac_is_gcj = False
- return where_javac, version
-
- def java_where_javah(self, version=None):
- ENV = self.java_ENV(version)
- if self.detect_tool('javah'):
- where_javah = self.detect('JAVAH', 'javah', ENV=ENV)
- else:
- where_javah = self.where_is('javah', ENV['PATH'])
- if not where_javah:
- self.skip_test("Could not find Java javah, skipping test(s).\n")
- return where_javah
-
- def java_where_rmic(self, version=None):
- ENV = self.java_ENV(version)
- if self.detect_tool('rmic'):
- where_rmic = self.detect('RMIC', 'rmic', ENV=ENV)
- else:
- where_rmic = self.where_is('rmic', ENV['PATH'])
- if not where_rmic:
- self.skip_test("Could not find Java rmic, skipping non-simulated test(s).\n")
- return where_rmic
-
-
- def java_get_class_files(self, dir):
- result = []
- for dirpath, dirnames, filenames in os.walk(dir):
- for fname in filenames:
- if fname.endswith('.class'):
- result.append(os.path.join(dirpath, fname))
- return sorted(result)
-
-
- def Qt_dummy_installation(self, dir='qt'):
- # create a dummy qt installation
-
- self.subdir( dir, [dir, 'bin'], [dir, 'include'], [dir, 'lib'] )
-
- self.write([dir, 'bin', 'mymoc.py'], """\
-import getopt
-import sys
-import re
-# -w and -z are fake options used in test/QT/QTFLAGS.py
-cmd_opts, args = getopt.getopt(sys.argv[1:], 'io:wz', [])
-output = None
-impl = 0
-opt_string = ''
-for opt, arg in cmd_opts:
- if opt == '-o': output = open(arg, 'w')
- elif opt == '-i': impl = 1
- else: opt_string = opt_string + ' ' + opt
-output.write("/* mymoc.py%s */\\n" % opt_string)
-for a in args:
- contents = open(a, 'r').read()
- a = a.replace('\\\\', '\\\\\\\\')
- subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }'
- if impl:
- contents = re.sub( r'#include.*', '', contents )
- output.write(contents.replace('Q_OBJECT', subst))
-output.close()
-sys.exit(0)
-""")
-
- self.write([dir, 'bin', 'myuic.py'], """\
-import os.path
-import re
-import sys
-output_arg = 0
-impl_arg = 0
-impl = None
-source = None
-opt_string = ''
-for arg in sys.argv[1:]:
- if output_arg:
- output = open(arg, 'w')
- output_arg = 0
- elif impl_arg:
- impl = arg
- impl_arg = 0
- elif arg == "-o":
- output_arg = 1
- elif arg == "-impl":
- impl_arg = 1
- elif arg[0:1] == "-":
- opt_string = opt_string + ' ' + arg
- else:
- if source:
- sys.exit(1)
- source = open(arg, 'r')
- sourceFile = arg
-output.write("/* myuic.py%s */\\n" % opt_string)
-if impl:
- output.write( '#include "' + impl + '"\\n' )
- includes = re.findall('<include.*?>(.*?)</include>', source.read())
- for incFile in includes:
- # this is valid for ui.h files, at least
- if os.path.exists(incFile):
- output.write('#include "' + incFile + '"\\n')
-else:
- output.write( '#include "my_qobject.h"\\n' + source.read() + " Q_OBJECT \\n" )
-output.close()
-sys.exit(0)
-""" )
-
- self.write([dir, 'include', 'my_qobject.h'], r"""
-#define Q_OBJECT ;
-void my_qt_symbol(const char *arg);
-""")
-
- self.write([dir, 'lib', 'my_qobject.cpp'], r"""
-#include "../include/my_qobject.h"
-#include <stdio.h>
-void my_qt_symbol(const char *arg) {
- fputs( arg, stdout );
-}
-""")
-
- self.write([dir, 'lib', 'SConstruct'], r"""
-env = Environment()
-import sys
-if sys.platform == 'win32':
- env.StaticLibrary( 'myqt', 'my_qobject.cpp' )
-else:
- env.SharedLibrary( 'myqt', 'my_qobject.cpp' )
-""")
-
- self.run(chdir = self.workpath(dir, 'lib'),
- arguments = '.',
- stderr = noisy_ar,
- match = self.match_re_dotall)
-
- self.QT = self.workpath(dir)
- self.QT_LIB = 'myqt'
- self.QT_MOC = '%s %s' % (_python_, self.workpath(dir, 'bin', 'mymoc.py'))
- self.QT_UIC = '%s %s' % (_python_, self.workpath(dir, 'bin', 'myuic.py'))
- self.QT_LIB_DIR = self.workpath(dir, 'lib')
-
- def Qt_create_SConstruct(self, place):
- if isinstance(place, list):
- place = test.workpath(*place)
- self.write(place, """\
-if ARGUMENTS.get('noqtdir', 0): QTDIR=None
-else: QTDIR=r'%s'
-env = Environment(QTDIR = QTDIR,
- QT_LIB = r'%s',
- QT_MOC = r'%s',
- QT_UIC = r'%s',
- tools=['default','qt'])
-dup = 1
-if ARGUMENTS.get('variant_dir', 0):
- if ARGUMENTS.get('chdir', 0):
- SConscriptChdir(1)
- else:
- SConscriptChdir(0)
- dup=int(ARGUMENTS.get('dup', 1))
- if dup == 0:
- builddir = 'build_dup0'
- env['QT_DEBUG'] = 1
- else:
- builddir = 'build'
- VariantDir(builddir, '.', duplicate=dup)
- print(builddir, dup)
- sconscript = Dir(builddir).File('SConscript')
-else:
- sconscript = File('SConscript')
-Export("env dup")
-SConscript( sconscript )
-""" % (self.QT, self.QT_LIB, self.QT_MOC, self.QT_UIC))
-
-
- NCR = 0 # non-cached rebuild
- CR = 1 # cached rebuild (up to date)
- NCF = 2 # non-cached build failure
- CF = 3 # cached build failure
-
- if sys.platform == 'win32':
- Configure_lib = 'msvcrt'
- else:
- Configure_lib = 'm'
-
- # to use cygwin compilers on cmd.exe -> uncomment following line
- #Configure_lib = 'm'
-
- def skip_if_not_msvc(self, check_platform=True):
- """ Check whether we are on a Windows platform and skip the
- test if not. This check can be omitted by setting
- check_platform to False.
- Then, for a win32 platform, additionally check
- whether we have a MSVC toolchain installed
- in the system, and skip the test if none can be
- found (=MinGW is the only compiler available).
- """
- if check_platform:
- if sys.platform != 'win32':
- msg = "Skipping Visual C/C++ test on non-Windows platform '%s'\n" % sys.platform
- self.skip_test(msg)
- return
-
- try:
- import SCons.Tool.MSCommon as msc
- if not msc.msvc_exists():
- msg = "No MSVC toolchain found...skipping test\n"
- self.skip_test(msg)
- except:
- pass
-
- def checkLogAndStdout(self, checks, results, cached,
- logfile, sconf_dir, sconstruct,
- doCheckLog=True, doCheckStdout=True):
- """
- Used to verify the expected output from using Configure()
- via the contents of one or both of stdout or config.log file.
- The checks, results, cached parameters all are zipped together
- for use in comparing results.
-
- TODO: Perhaps a better API makes sense?
-
- Parameters
- ----------
- checks : The Configure checks being run
-
- results : The expected results for each check
-
- cached : If the corresponding check is expected to be cached
-
- logfile : Name of the config log
-
- sconf_dir : Name of the sconf dir
-
- sconstruct : SConstruct file name
-
- doCheckLog : check specified log file, defaults to true
-
- doCheckStdout : Check stdout, defaults to true
-
- Returns
- -------
-
- """
-
- class NoMatch(Exception):
- def __init__(self, p):
- self.pos = p
-
- def matchPart(log, logfile, lastEnd, NoMatch=NoMatch):
- """
- Match part of the logfile
- """
- m = re.match(log, logfile[lastEnd:])
- if not m:
- raise NoMatch(lastEnd)
- return m.end() + lastEnd
-
- try:
-
- # Build regexp for a character which is not
- # a linesep, and in the case of CR/LF
- # build it with both CR and CR/LF
- # TODO: Not sure why this is a good idea. A static string
- # could do the same since we only have two variations
- # to do with?
- # ls = os.linesep
- # nols = "("
- # for i in range(len(ls)):
- # nols = nols + "("
- # for j in range(i):
- # nols = nols + ls[j]
- # nols = nols + "[^" + ls[i] + "])"
- # if i < len(ls)-1:
- # nols = nols + "|"
- # nols = nols + ")"
- #
- # Replaced above logic with \n as we're reading the file
- # using non-binary read. Python will translate \r\n -> \n
- # For us.
- ls = '\n'
- nols = '([^\n])'
- lastEnd = 0
-
- # Read the whole logfile
- logfile = self.read(self.workpath(logfile), mode='r')
-
- # Some debug code to keep around..
- # sys.stderr.write("LOGFILE[%s]:%s"%(type(logfile),logfile))
-
- if (doCheckLog and
- logfile.find("scons: warning: The stored build information has an unexpected class.") >= 0):
- self.fail_test()
-
- sconf_dir = sconf_dir
- sconstruct = sconstruct
-
- log = r'file\ \S*%s\,line \d+:' % re.escape(sconstruct) + ls
- if doCheckLog:
- lastEnd = matchPart(log, logfile, lastEnd)
-
- log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls
- if doCheckLog:
- lastEnd = matchPart(log, logfile, lastEnd)
-
- rdstr = ""
- cnt = 0
- for check,result,cache_desc in zip(checks, results, cached):
- log = re.escape("scons: Configure: " + check) + ls
-
- if doCheckLog:
- lastEnd = matchPart(log, logfile, lastEnd)
-
- log = ""
- result_cached = 1
- for bld_desc in cache_desc: # each TryXXX
- for ext, flag in bld_desc: # each file in TryBuild
- file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext))
- if flag == self.NCR:
- # NCR = Non Cached Rebuild
- # rebuild will pass
- if ext in ['.c', '.cpp']:
- log=log + re.escape(file + " <-") + ls
- log=log + r"( \|" + nols + "*" + ls + ")+?"
- else:
- log=log + "(" + nols + "*" + ls +")*?"
- result_cached = 0
- if flag == self.CR:
- # CR = cached rebuild (up to date)s
- # up to date
- log=log + \
- re.escape("scons: Configure: \"%s\" is up to date."
- % file) + ls
- log=log+re.escape("scons: Configure: The original builder "
- "output was:") + ls
- log=log+r"( \|.*"+ls+")+"
- if flag == self.NCF:
- # non-cached rebuild failure
- log=log + "(" + nols + "*" + ls + ")*?"
- result_cached = 0
- if flag == self.CF:
- # cached rebuild failure
- log=log + \
- re.escape("scons: Configure: Building \"%s\" failed "
- "in a previous run and all its sources are"
- " up to date." % file) + ls
- log=log+re.escape("scons: Configure: The original builder "
- "output was:") + ls
- log=log+r"( \|.*"+ls+")+"
- cnt = cnt + 1
- if result_cached:
- result = "(cached) " + result
- rdstr = rdstr + re.escape(check) + re.escape(result) + "\n"
- log=log + re.escape("scons: Configure: " + result) + ls + ls
-
- if doCheckLog:
- lastEnd = matchPart(log, logfile, lastEnd)
-
- log = ""
- if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd)
- if doCheckLog and lastEnd != len(logfile):
- raise NoMatch(lastEnd)
-
- except NoMatch as m:
- print("Cannot match log file against log regexp.")
- print("log file: ")
- print("------------------------------------------------------")
- print(logfile[m.pos:])
- print("------------------------------------------------------")
- print("log regexp: ")
- print("------------------------------------------------------")
- print(log)
- print("------------------------------------------------------")
- self.fail_test()
-
- if doCheckStdout:
- exp_stdout = self.wrap_stdout(".*", rdstr)
- if not self.match_re_dotall(self.stdout(), exp_stdout):
- print("Unexpected stdout: ")
- print("-----------------------------------------------------")
- print(repr(self.stdout()))
- print("-----------------------------------------------------")
- print(repr(exp_stdout))
- print("-----------------------------------------------------")
- self.fail_test()
-
- def get_python_version(self):
- """
- Returns the Python version (just so everyone doesn't have to
- hand-code slicing the right number of characters).
- """
- # see also sys.prefix documentation
- return python_minor_version_string()
-
- def get_platform_python_info(self):
- """
- Returns a path to a Python executable suitable for testing on
- this platform and its associated include path, library path,
- and library name.
- """
- python = self.where_is('python')
- if not python:
- self.skip_test('Can not find installed "python", skipping test.\n')
-
- self.run(program = python, stdin = """\
-import os, sys
-try:
- if sys.platform == 'win32':
- py_ver = 'python%d%d' % sys.version_info[:2]
- else:
- py_ver = 'python%d.%d' % sys.version_info[:2]
-except AttributeError:
- py_ver = 'python' + sys.version[:3]
-# print include and lib path
-try:
- import distutils.sysconfig
- exec_prefix = distutils.sysconfig.EXEC_PREFIX
- print(distutils.sysconfig.get_python_inc())
- 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'))
-print(py_ver)
-""")
-
- return [python] + self.stdout().strip().split('\n')
-
- def start(self, *args, **kw):
- """
- Starts SCons in the test environment.
-
- This method exists to tell Test{Cmd,Common} that we're going to
- use standard input without forcing every .start() call in the
- individual tests to do so explicitly.
- """
- if 'stdin' not in kw:
- kw['stdin'] = True
- sconsflags = initialize_sconsflags(self.ignore_python_version)
- try:
- p = TestCommon.start(self, *args, **kw)
- finally:
- restore_sconsflags(sconsflags)
- return p
-
- def wait_for(self, fname, timeout=20.0, popen=None):
- """
- Waits for the specified file name to exist.
- """
- waited = 0.0
- while not os.path.exists(fname):
- if timeout and waited >= timeout:
- sys.stderr.write('timed out waiting for %s to exist\n' % fname)
- if popen:
- popen.stdin.close()
- popen.stdin = None
- self.status = 1
- self.finish(popen)
- stdout = self.stdout()
- if stdout:
- sys.stdout.write(self.banner('STDOUT ') + '\n')
- sys.stdout.write(stdout)
- stderr = self.stderr()
- if stderr:
- sys.stderr.write(self.banner('STDERR ') + '\n')
- sys.stderr.write(stderr)
- self.fail_test()
- time.sleep(1.0)
- waited = waited + 1.0
-
- def get_alt_cpp_suffix(self):
- """
- Many CXX tests have this same logic.
- They all needed to determine if the current os supports
- files with .C and .c as different files or not
- in which case they are instructed to use .cpp instead of .C
- """
- if not case_sensitive_suffixes('.c','.C'):
- alt_cpp_suffix = '.cpp'
- else:
- alt_cpp_suffix = '.C'
- return alt_cpp_suffix
-
- def platform_has_symlink(self):
- if not hasattr(os, 'symlink') or sys.platform == 'win32':
- return False
- else:
- return True
-
-
-class Stat:
- def __init__(self, name, units, expression, convert=None):
- if convert is None:
- convert = lambda x: x
- self.name = name
- self.units = units
- self.expression = re.compile(expression)
- self.convert = convert
-
-StatList = [
- Stat('memory-initial', 'kbytes',
- r'Memory before reading SConscript files:\s+(\d+)',
- convert=lambda s: int(s) // 1024),
- Stat('memory-prebuild', 'kbytes',
- r'Memory before building targets:\s+(\d+)',
- convert=lambda s: int(s) // 1024),
- Stat('memory-final', 'kbytes',
- r'Memory after building targets:\s+(\d+)',
- convert=lambda s: int(s) // 1024),
-
- Stat('time-sconscript', 'seconds',
- r'Total SConscript file execution time:\s+([\d.]+) seconds'),
- Stat('time-scons', 'seconds',
- r'Total SCons execution time:\s+([\d.]+) seconds'),
- Stat('time-commands', 'seconds',
- r'Total command execution time:\s+([\d.]+) seconds'),
- Stat('time-total', 'seconds',
- r'Total build time:\s+([\d.]+) seconds'),
-]
-
-
-class TimeSCons(TestSCons):
- """Class for timing SCons."""
- def __init__(self, *args, **kw):
- """
- In addition to normal TestSCons.TestSCons intialization,
- this enables verbose mode (which causes the command lines to
- be displayed in the output) and copies the contents of the
- directory containing the executing script to the temporary
- working directory.
- """
- self.variables = kw.get('variables')
- default_calibrate_variables = []
- if self.variables is not None:
- for variable, value in self.variables.items():
- value = os.environ.get(variable, value)
- try:
- value = int(value)
- except ValueError:
- try:
- value = float(value)
- except ValueError:
- pass
- else:
- default_calibrate_variables.append(variable)
- else:
- default_calibrate_variables.append(variable)
- self.variables[variable] = value
- del kw['variables']
- calibrate_keyword_arg = kw.get('calibrate')
- if calibrate_keyword_arg is None:
- self.calibrate_variables = default_calibrate_variables
- else:
- self.calibrate_variables = calibrate_keyword_arg
- del kw['calibrate']
-
- self.calibrate = os.environ.get('TIMESCONS_CALIBRATE', '0') != '0'
-
- if 'verbose' not in kw and not self.calibrate:
- kw['verbose'] = True
-
- TestSCons.__init__(self, *args, **kw)
-
- # TODO(sgk): better way to get the script dir than sys.argv[0]
- self.test_dir = os.path.dirname(sys.argv[0])
- test_name = os.path.basename(self.test_dir)
-
- if not os.path.isabs(self.test_dir):
- self.test_dir = os.path.join(self.orig_cwd, self.test_dir)
- self.copy_timing_configuration(self.test_dir, self.workpath())
-
- def main(self, *args, **kw):
- """
- The main entry point for standard execution of timings.
-
- This method run SCons three times:
-
- Once with the --help option, to have it exit after just reading
- the configuration.
-
- Once as a full build of all targets.
-
- Once again as a (presumably) null or up-to-date build of
- all targets.
-
- The elapsed time to execute each build is printed after
- it has finished.
- """
- if 'options' not in kw and self.variables:
- options = []
- for variable, value in self.variables.items():
- options.append('%s=%s' % (variable, value))
- kw['options'] = ' '.join(options)
- if self.calibrate:
- self.calibration(*args, **kw)
- else:
- self.uptime()
- self.startup(*args, **kw)
- self.full(*args, **kw)
- self.null(*args, **kw)
-
- def trace(self, graph, name, value, units, sort=None):
- fmt = "TRACE: graph=%s name=%s value=%s units=%s"
- line = fmt % (graph, name, value, units)
- if sort is not None:
- line = line + (' sort=%s' % sort)
- line = line + '\n'
- sys.stdout.write(line)
- sys.stdout.flush()
-
- def report_traces(self, trace, stats):
- self.trace('TimeSCons-elapsed',
- trace,
- self.elapsed_time(),
- "seconds",
- sort=0)
- for name, args in stats.items():
- self.trace(name, trace, **args)
-
- def uptime(self):
- try:
- fp = open('/proc/loadavg')
- except EnvironmentError:
- pass
- else:
- avg1, avg5, avg15 = fp.readline().split(" ")[:3]
- fp.close()
- self.trace('load-average', 'average1', avg1, 'processes')
- self.trace('load-average', 'average5', avg5, 'processes')
- self.trace('load-average', 'average15', avg15, 'processes')
-
- def collect_stats(self, input):
- result = {}
- for stat in StatList:
- m = stat.expression.search(input)
- if m:
- value = stat.convert(m.group(1))
- # The dict keys match the keyword= arguments
- # of the trace() method above so they can be
- # applied directly to that call.
- result[stat.name] = {'value':value, 'units':stat.units}
- return result
-
- def add_timing_options(self, kw, additional=None):
- """
- Add the necessary timings options to the kw['options'] value.
- """
- options = kw.get('options', '')
- if additional is not None:
- options += additional
- kw['options'] = options + ' --debug=memory,time'
-
- def startup(self, *args, **kw):
- """
- Runs scons with the --help option.
-
- This serves as a way to isolate just the amount of startup time
- spent reading up the configuration, since --help exits before any
- "real work" is done.
- """
- self.add_timing_options(kw, ' --help')
- # Ignore the exit status. If the --help run dies, we just
- # won't report any statistics for it, but we can still execute
- # the full and null builds.
- kw['status'] = None
- self.run(*args, **kw)
- sys.stdout.write(self.stdout())
- stats = self.collect_stats(self.stdout())
- # Delete the time-commands, since no commands are ever
- # executed on the help run and it is (or should be) always 0.0.
- del stats['time-commands']
- self.report_traces('startup', stats)
-
- def full(self, *args, **kw):
- """
- Runs a full build of SCons.
- """
- self.add_timing_options(kw)
- self.run(*args, **kw)
- sys.stdout.write(self.stdout())
- stats = self.collect_stats(self.stdout())
- self.report_traces('full', stats)
- self.trace('full-memory', 'initial', **stats['memory-initial'])
- self.trace('full-memory', 'prebuild', **stats['memory-prebuild'])
- self.trace('full-memory', 'final', **stats['memory-final'])
-
- def calibration(self, *args, **kw):
- """
- Runs a full build of SCons, but only reports calibration
- information (the variable(s) that were set for this configuration,
- and the elapsed time to run.
- """
- self.add_timing_options(kw)
- self.run(*args, **kw)
- for variable in self.calibrate_variables:
- value = self.variables[variable]
- sys.stdout.write('VARIABLE: %s=%s\n' % (variable, value))
- sys.stdout.write('ELAPSED: %s\n' % self.elapsed_time())
-
- def null(self, *args, **kw):
- """
- Runs an up-to-date null build of SCons.
- """
- # TODO(sgk): allow the caller to specify the target (argument)
- # that must be up-to-date.
- self.add_timing_options(kw)
- self.up_to_date(arguments='.', **kw)
- sys.stdout.write(self.stdout())
- stats = self.collect_stats(self.stdout())
- # time-commands should always be 0.0 on a null build, because
- # no commands should be executed. Remove it from the stats
- # so we don't trace it, but only if it *is* 0 so that we'll
- # get some indication if a supposedly-null build actually does
- # build something.
- if float(stats['time-commands']['value']) == 0.0:
- del stats['time-commands']
- self.report_traces('null', stats)
- self.trace('null-memory', 'initial', **stats['memory-initial'])
- self.trace('null-memory', 'prebuild', **stats['memory-prebuild'])
- self.trace('null-memory', 'final', **stats['memory-final'])
-
- def elapsed_time(self):
- """
- Returns the elapsed time of the most recent command execution.
- """
- return self.endTime - self.startTime
-
- def run(self, *args, **kw):
- """
- Runs a single build command, capturing output in the specified file.
-
- Because this class is about timing SCons, we record the start
- and end times of the elapsed execution, and also add the
- --debug=memory and --debug=time options to have SCons report
- its own memory and timing statistics.
- """
- self.startTime = time.time()
- try:
- result = TestSCons.run(self, *args, **kw)
- finally:
- self.endTime = time.time()
- return result
-
- def copy_timing_configuration(self, source_dir, dest_dir):
- """
- Copies the timing configuration from the specified source_dir (the
- directory in which the controlling script lives) to the specified
- dest_dir (a temporary working directory).
-
- This ignores all files and directories that begin with the string
- 'TimeSCons-', and all '.svn' subdirectories.
- """
- for root, dirs, files in os.walk(source_dir):
- if '.svn' in dirs:
- dirs.remove('.svn')
- dirs = [ d for d in dirs if not d.startswith('TimeSCons-') ]
- files = [ f for f in files if not f.startswith('TimeSCons-') ]
- for dirname in dirs:
- source = os.path.join(root, dirname)
- destination = source.replace(source_dir, dest_dir)
- os.mkdir(destination)
- if sys.platform != 'win32':
- shutil.copystat(source, destination)
- for filename in files:
- source = os.path.join(root, filename)
- destination = source.replace(source_dir, dest_dir)
- shutil.copy2(source, destination)
-
-
-# In some environments, $AR will generate a warning message to stderr
-# if the library doesn't previously exist and is being created. One
-# way to fix this is to tell AR to be quiet (sometimes the 'c' flag),
-# but this is difficult to do in a platform-/implementation-specific
-# method. Instead, we will use the following as a stderr match for
-# tests that use AR so that we will view zero or more "ar: creating
-# <file>" messages to be successful executions of the test (see
-# test/AR.py for sample usage).
-
-noisy_ar=r'(ar: creating( archive)? \S+\n?)*'
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4: