--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -60,17 +60,16 @@ from ..frontend.data import (
Library,
LocalInclude,
PerSourceFlag,
Program,
SharedLibrary,
SimpleProgram,
Sources,
StaticLibrary,
- TestHarnessFiles,
TestManifest,
VariablePassthru,
XPIDLFile,
)
from ..util import (
ensureParentDir,
FileAvoidWrite,
)
@@ -522,19 +521,16 @@ class RecursiveMakeBackend(CommonBackend
""".format(output=obj.output,
dep_file=dep_file,
inputs=' ' + ' '.join(obj.inputs) if obj.inputs else '',
flags=' ' + ' '.join(obj.flags) if obj.flags else '',
backend=' backend.mk' if obj.flags else '',
script=obj.script,
method=obj.method))
- elif isinstance(obj, TestHarnessFiles):
- self._process_test_harness_files(obj, backend_file)
-
elif isinstance(obj, JARManifest):
self._no_skip['libs'].add(backend_file.relobjdir)
backend_file.write('JAR_MANIFEST := %s\n' % obj.path.full_path)
elif isinstance(obj, Program):
self._process_program(obj.program, backend_file)
self._process_linked_libraries(obj, backend_file)
@@ -904,39 +900,16 @@ class RecursiveMakeBackend(CommonBackend
def _process_defines(self, obj, backend_file, which='DEFINES'):
"""Output the DEFINES rules to the given backend file."""
defines = list(obj.get_defines())
if defines:
defines = ' '.join(shell_quote(d) for d in defines)
backend_file.write_once('%s += %s\n' % (which, defines))
- def _process_test_harness_files(self, obj, backend_file):
- for path, files in obj.srcdir_files.iteritems():
- for source in files:
- dest = '%s/%s' % (path, mozpath.basename(source))
- self._install_manifests['_tests'].add_symlink(source, dest)
-
- for path, patterns in obj.srcdir_pattern_files.iteritems():
- for p in patterns:
- self._install_manifests['_tests'].add_pattern_symlink(p[0], p[1], path)
-
- for path, files in obj.objdir_files.iteritems():
- self._no_skip['misc'].add(backend_file.relobjdir)
- prefix = 'TEST_HARNESS_%s' % path.replace('/', '_')
- backend_file.write("""
-%(prefix)s_FILES := %(files)s
-%(prefix)s_DEST := %(dest)s
-%(prefix)s_TARGET := misc
-INSTALL_TARGETS += %(prefix)s
-""" % { 'prefix': prefix,
- 'dest': '$(DEPTH)/_tests/%s' % path,
- 'files': ' '.join(mozpath.relpath(f, backend_file.objdir)
- for f in files) })
-
def _process_installation_target(self, obj, backend_file):
# A few makefiles need to be able to override the following rules via
# make XPI_NAME=blah commands, so we default to the lazy evaluation as
# much as possible here to avoid breaking things.
if obj.xpiname:
backend_file.write('XPI_NAME = %s\n' % (obj.xpiname))
if obj.subdir:
backend_file.write('DIST_SUBDIR = %s\n' % (obj.subdir))
@@ -1263,17 +1236,25 @@ INSTALL_TARGETS += %(prefix)s
for path, files in files.walk():
target_var = (mozpath.join(target, path)
if path else target).replace('/', '_')
have_objdir_files = False
for f in files:
assert not isinstance(f, RenamedSourcePath)
dest = mozpath.join(reltarget, path, f.target_basename)
if not isinstance(f, ObjDirPath):
- install_manifest.add_symlink(f.full_path, dest)
+ if '*' in f:
+ if not isinstance(f, SourcePath):
+ raise Exception("Wildcards are only supported in "
+ "SourcePath objects in %s. Path is: %s" % (
+ type(obj), f
+ ))
+ install_manifest.add_pattern_symlink(f.srcdir, f, path)
+ else:
+ install_manifest.add_symlink(f.full_path, dest)
else:
install_manifest.add_optional_exists(dest)
backend_file.write('%s_FILES += %s\n' % (
target_var, self._pretty_path(f, backend_file)))
have_objdir_files = True
if have_objdir_files:
tier = 'export' if obj.install_target == 'dist/include' else 'misc'
self._no_skip[tier].add(backend_file.relobjdir)
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -1039,22 +1039,16 @@ VARIABLES = {
"""Disable the wrappers for STL which allow it to work with C++ exceptions
disabled.
"""),
'FINAL_TARGET_PP_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
"""Like ``FINAL_TARGET_FILES``, with preprocessing.
"""),
- 'TESTING_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
- """List of files to be installed in the _tests directory.
-
- This works similarly to FINAL_TARGET_FILES.
- """),
-
'FINAL_LIBRARY': (unicode, unicode,
"""Library in which the objects of the current directory will be linked.
This variable contains the name of a library, defined elsewhere with
``LIBRARY_NAME``, in which the objects of the current directory will be
linked.
"""),
@@ -1689,17 +1683,17 @@ VARIABLES = {
Note that the ordering of flags matter here, these flags will be
added to the linker's command line in the same order as they
appear in the moz.build file.
This variable only has an effect on Windows.
"""),
- 'TEST_HARNESS_FILES': (HierarchicalStringList, list,
+ 'TEST_HARNESS_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
"""List of files to be installed for test harnesses.
``TEST_HARNESS_FILES`` can be used to install files to any directory
under $objdir/_tests. Files can be appended to a field to indicate
which subdirectory they should be exported to. For example,
to export ``foo.py`` to ``_tests/foo``, append to
``TEST_HARNESS_FILES`` like so::
TEST_HARNESS_FILES.foo += ['foo.py']
@@ -2028,17 +2022,17 @@ SPECIAL_VARIABLES = {
'EXTRA_PP_JS_MODULES': (lambda context: context['FINAL_TARGET_PP_FILES'].modules, list,
"""Additional JavaScript files to distribute.
This variable contains a list of files to copy into
``$(FINAL_TARGET)/modules``, after preprocessing.
"""),
- 'TESTING_JS_MODULES': (lambda context: context['TESTING_FILES'].modules, list,
+ 'TESTING_JS_MODULES': (lambda context: context['TEST_HARNESS_FILES'].modules, list,
"""JavaScript modules to install in the test-only destination.
Some JavaScript modules (JSMs) are test-only and not distributed
with Firefox. This variable defines them.
To install modules in a subdirectory, use properties of this
variable to control the final destination. e.g.
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -198,32 +198,16 @@ class BaseDefines(ContextDerived):
self.defines.update(more_defines)
class Defines(BaseDefines):
pass
class HostDefines(BaseDefines):
pass
-class TestHarnessFiles(ContextDerived):
- """Sandbox container object for TEST_HARNESS_FILES,
- which is a HierarchicalStringList.
-
- We need an object derived from ContextDerived for use in the backend, so
- this object fills that role. It just has a reference to the underlying
- HierarchicalStringList, which is created when parsing TEST_HARNESS_FILES.
- """
- __slots__ = ('srcdir_files', 'srcdir_pattern_files', 'objdir_files')
-
- def __init__(self, context, srcdir_files, srcdir_pattern_files, objdir_files):
- ContextDerived.__init__(self, context)
- self.srcdir_files = srcdir_files
- self.srcdir_pattern_files = srcdir_pattern_files
- self.objdir_files = objdir_files
-
class IPDLFile(ContextDerived):
"""Describes an individual .ipdl source file."""
__slots__ = (
'basename',
)
def __init__(self, context, path):
@@ -809,17 +793,20 @@ class FinalTargetPreprocessedFiles(Conte
"""
__slots__ = ('files')
def __init__(self, sandbox, files):
ContextDerived.__init__(self, sandbox)
self.files = files
-class TestingFiles(FinalTargetFiles):
+class TestHarnessFiles(FinalTargetFiles):
+ """Sandbox container object for TEST_HARNESS_FILES,
+ which is a HierarchicalStringList.
+ """
@property
def install_target(self):
return '_tests'
class Exports(FinalTargetFiles):
"""Context derived container object for EXPORTS, which is a
HierarchicalStringList.
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -60,17 +60,16 @@ from .data import (
PreprocessedTestWebIDLFile,
PreprocessedWebIDLFile,
Program,
SharedLibrary,
SimpleProgram,
Sources,
StaticLibrary,
TestHarnessFiles,
- TestingFiles,
TestWebIDLFile,
TestManifest,
UnifiedSources,
VariablePassthru,
WebIDLFile,
XPIDLFile,
)
from mozpack.chrome.manifest import (
@@ -788,19 +787,16 @@ class TreeMetadataEmitter(LoggingMixin):
yield obj
for path in context['CONFIGURE_SUBST_FILES']:
sub = self._create_substitution(ConfigFileSubstitution, context,
path)
generated_files.add(str(sub.relpath))
yield sub
- for obj in self._process_test_harness_files(context):
- yield obj
-
defines = context.get('DEFINES')
if defines:
yield Defines(context, defines)
host_defines = context.get('HOST_DEFINES')
if host_defines:
yield HostDefines(context, host_defines)
@@ -827,49 +823,55 @@ class TreeMetadataEmitter(LoggingMixin):
yield LocalInclude(context, local_include)
components = []
for var, cls in (
('BRANDING_FILES', BrandingFiles),
('EXPORTS', Exports),
('FINAL_TARGET_FILES', FinalTargetFiles),
('FINAL_TARGET_PP_FILES', FinalTargetPreprocessedFiles),
- ('TESTING_FILES', TestingFiles),
+ ('TEST_HARNESS_FILES', TestHarnessFiles),
):
all_files = context.get(var)
if not all_files:
continue
- if dist_install is False and var != 'TESTING_FILES':
+ if dist_install is False and var != 'TEST_HARNESS_FILES':
raise SandboxValidationError(
'%s cannot be used with DIST_INSTALL = False' % var,
context)
has_prefs = False
has_resources = False
for base, files in all_files.walk():
+ if var == 'TEST_HARNESS_FILES' and not base:
+ raise SandboxValidationError(
+ 'Cannot install files to the root of TEST_HARNESS_FILES', context)
if base == 'components':
components.extend(files)
if base == 'defaults/pref':
has_prefs = True
if mozpath.split(base)[0] == 'res':
has_resources = True
for f in files:
if (var == 'FINAL_TARGET_PP_FILES' and
not isinstance(f, SourcePath)):
raise SandboxValidationError(
('Only source directory paths allowed in ' +
'FINAL_TARGET_PP_FILES: %s')
% (f,), context)
if not isinstance(f, ObjDirPath):
path = f.full_path
- if not os.path.exists(path):
+ if '*' not in path and not os.path.exists(path):
raise SandboxValidationError(
'File listed in %s does not exist: %s'
% (var, path), context)
else:
- if f.target_basename not in generated_files:
+ # The '/' check is to allow installing files generated
+ # from other directories, which is done occasionally for
+ # tests.
+ if f.target_basename not in generated_files and '/' not in f:
raise SandboxValidationError(
('Objdir file listed in %s not in ' +
'GENERATED_FILES: %s') % (var, f), context)
# Addons (when XPI_NAME is defined) and Applications (when
# DIST_SUBDIR is defined) use a different preferences directory
# (default/preferences) from the one the GRE uses (defaults/pref).
# Hence, we move the files from the latter to the former in that
@@ -1013,57 +1015,16 @@ class TreeMetadataEmitter(LoggingMixin):
'Input for generating %s does not exist: %s'
% (f, p.full_path), context)
inputs.append(p.full_path)
else:
script = None
method = None
yield GeneratedFile(context, script, method, output, inputs)
- def _process_test_harness_files(self, context):
- test_harness_files = context.get('TEST_HARNESS_FILES')
- if not test_harness_files:
- return
-
- srcdir_files = defaultdict(list)
- srcdir_pattern_files = defaultdict(list)
- objdir_files = defaultdict(list)
-
- for path, strings in test_harness_files.walk():
- if not path and strings:
- raise SandboxValidationError(
- 'Cannot install files to the root of TEST_HARNESS_FILES', context)
-
- for s in strings:
- # Ideally, TEST_HARNESS_FILES would expose Path instances, but
- # subclassing HierarchicalStringList to be ContextDerived is
- # painful, so until we actually kill HierarchicalStringList,
- # just do Path manipulation here.
- p = Path(context, s)
- if isinstance(p, ObjDirPath):
- objdir_files[path].append(p.full_path)
- elif '*' in s:
- resolved = p.full_path
- if s[0] == '/':
- pattern_start = resolved.index('*')
- base_path = mozpath.dirname(resolved[:pattern_start])
- pattern = resolved[len(base_path)+1:]
- else:
- base_path = context.srcdir
- pattern = s
- srcdir_pattern_files[path].append((base_path, pattern));
- elif not os.path.exists(p.full_path):
- raise SandboxValidationError(
- 'File listed in TEST_HARNESS_FILES does not exist: %s' % s, context)
- else:
- srcdir_files[path].append(p.full_path)
-
- yield TestHarnessFiles(context, srcdir_files,
- srcdir_pattern_files, objdir_files)
-
def _process_test_manifests(self, context):
for prefix, info in TEST_MANIFESTS.items():
for path in context.get('%s_MANIFESTS' % prefix, []):
for obj in self._process_test_manifest(context, info, path):
yield obj
for flavor in REFTEST_FLAVORS:
for path in context.get('%s_MANIFESTS' % flavor.upper(), []):
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -314,17 +314,17 @@ class TestEmitterBasic(unittest.TestCase
self.assertEqual(len(objs), 1)
self.assertIsInstance(objs[0], TestHarnessFiles)
expected = {
'mochitest': ['runtests.py', 'utils.py'],
'testing/mochitest': ['mochitest.py', 'mochitest.ini'],
}
- for path, strings in objs[0].srcdir_files.iteritems():
+ for path, strings in objs[0].files.walk():
self.assertTrue(path in expected)
basenames = sorted(mozpath.basename(s) for s in strings)
self.assertEqual(sorted(expected[path]), basenames)
def test_test_harness_files_root(self):
reader = self.reader('test-harness-files-root')
with self.assertRaisesRegexp(SandboxValidationError,
'Cannot install files to the root of TEST_HARNESS_FILES'):
--- a/testing/mochitest/moz.build
+++ b/testing/mochitest/moz.build
@@ -23,16 +23,20 @@ if CONFIG['MOZ_BUILD_APP'] != 'mobile/an
DEFINES['MOCHITEST_BOOTSTRAP'] = True
FINAL_TARGET_FILES += ['bootstrap.js']
MOCHITEST_MANIFESTS += [
'tests/MochiKit-1.4.2/tests/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
+GENERATED_FILES += [
+ 'automation.py',
+]
+
TEST_HARNESS_FILES.testing.mochitest += [
'!automation.py',
'/build/mobile/remoteautomation.py',
'/build/pgo/server-locations.txt',
'/build/sanitizers/lsan_suppressions.txt',
'/build/valgrind/cross-architecture.sup',
'/build/valgrind/i386-redhat-linux-gnu.sup',
'/build/valgrind/x86_64-redhat-linux-gnu.sup',