Bug 925185 - Part 1: Add add_java_jar to moz.build. r=gps
☠☠ backed out by cb59117d41f5 ☠ ☠
authorNick Alexander <nalexander@mozilla.com>
Thu, 24 Oct 2013 15:38:14 -0700
changeset 166032 ceaf4e435c8680161c5f6c91728cf3a9cfa9f645
parent 165916 f9208ba78a223b3c874d7c1da3b3ec30be5ea883
child 166033 2a368c09333a56c45518bc2b4a623e322a3f4903
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs925185
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 925185 - Part 1: Add add_java_jar to moz.build. r=gps
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/frontend/data.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/frontend/reader.py
python/mozbuild/mozbuild/frontend/sandbox_symbols.py
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -25,21 +25,23 @@ from ..frontend.data import (
     ConfigFileSubstitution,
     Defines,
     DirectoryTraversal,
     Exports,
     GeneratedEventWebIDLFile,
     GeneratedWebIDLFile,
     InstallationTarget,
     IPDLFile,
+    JavaJarData,
     LocalInclude,
     PreprocessedTestWebIDLFile,
     PreprocessedWebIDLFile,
     Program,
     SandboxDerived,
+    SandboxWrapped,
     TestWebIDLFile,
     VariablePassthru,
     XPIDLFile,
     TestManifest,
     WebIDLFile,
 )
 from ..util import (
     ensureParentDir,
@@ -408,16 +410,25 @@ class RecursiveMakeBackend(CommonBackend
             self._process_test_manifest(obj, backend_file)
 
         elif isinstance(obj, LocalInclude):
             self._process_local_include(obj.path, backend_file)
 
         elif isinstance(obj, InstallationTarget):
             self._process_installation_target(obj, backend_file)
 
+        elif isinstance(obj, SandboxWrapped):
+            # Process a rich build system object from the front-end
+            # as-is.  Please follow precedent and handle CamelCaseData
+            # in a function named _process_camel_case_data.  At some
+            # point in the future, this unwrapping process may be
+            # automated.
+            if isinstance(obj.wrapped, JavaJarData):
+                self._process_java_jar_data(obj.wrapped, backend_file)
+
         self._backend_files[obj.srcdir] = backend_file
 
     def _fill_root_mk(self):
         """
         Create two files, root.mk and root-deps.mk, the first containing
         convenience variables, and the other dependency definitions for a
         hopefully proper directory traversal.
         """
@@ -988,16 +999,33 @@ class RecursiveMakeBackend(CommonBackend
 
     def _process_local_include(self, local_include, backend_file):
         if local_include.startswith('/'):
             path = '$(topsrcdir)'
         else:
             path = '$(srcdir)/'
         backend_file.write('LOCAL_INCLUDES += -I%s%s\n' % (path, local_include))
 
+    def _process_java_jar_data(self, jar, backend_file):
+        target = jar.name
+        backend_file.write('JAVA_JAR_TARGETS += %s\n' % target)
+        backend_file.write('%s_DEST := %s.jar\n' % (target, jar.name))
+        if jar.sources:
+            backend_file.write('%s_JAVAFILES := %s\n' %
+                (target, ' '.join(jar.sources)))
+        if jar.generated_sources:
+            backend_file.write('%s_PP_JAVAFILES := %s\n' %
+                (target, ' '.join(jar.generated_sources)))
+        if jar.extra_jars:
+            backend_file.write('%s_EXTRA_JARS := %s\n' %
+                (target, ' '.join(jar.extra_jars)))
+        if jar.javac_flags:
+            backend_file.write('%s_JAVAC_FLAGS := %s\n' %
+                (target, jar.javac_flags))
+
     def _write_manifests(self, dest, manifests):
         man_dir = os.path.join(self.environment.topobjdir, '_build_manifests',
             dest)
 
         # We have a purger for the manifests themselves to ensure legacy
         # manifests are deleted.
         purger = FilePurger()
 
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -354,16 +354,64 @@ class LocalInclude(SandboxDerived):
         'path',
     )
 
     def __init__(self, sandbox, path):
         SandboxDerived.__init__(self, sandbox)
 
         self.path = path
 
+
+class SandboxWrapped(SandboxDerived):
+    """Generic sandbox container object for a wrapped rich object.
+
+    Use this wrapper class to shuttle a rich build system object
+    completely defined in moz.build files through the tree metadata
+    emitter to the build backend for processing as-is.
+    """
+
+    __slots__ = (
+        'wrapped',
+    )
+
+    def __init__(self, sandbox, wrapped):
+        SandboxDerived.__init__(self, sandbox)
+
+        self.wrapped = wrapped
+
+
+class JavaJarData(object):
+    """Represents a Java JAR file.
+
+    A Java JAR has the following members:
+        * sources - list of input java sources
+        * generated_sources - list of generated input java sources
+        * extra_jars - list of JAR file dependencies to include on the
+          javac compiler classpath
+        * javac_flags - string containing extra flags passed to the
+          javac compiler
+    """
+
+    __slots__ = (
+        'name',
+        'sources',
+        'generated_sources',
+        'extra_jars',
+        'javac_flags',
+    )
+
+    def __init__(self, name, sources=[], generated_sources=[],
+            extra_jars=[], javac_flags=None):
+        self.name = name
+        self.sources = list(sources)
+        self.generated_sources = list(generated_sources)
+        self.extra_jars = list(extra_jars)
+        self.javac_flags = javac_flags
+
+
 class InstallationTarget(SandboxDerived):
     """Describes the rules that affect where files get installed to."""
 
     __slots__ = (
         'xpiname',
         'subdir',
         'target',
         'enabled'
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -26,16 +26,17 @@ from .data import (
     GeneratedWebIDLFile,
     InstallationTarget,
     IPDLFile,
     LocalInclude,
     PreprocessedTestWebIDLFile,
     PreprocessedWebIDLFile,
     Program,
     ReaderSummary,
+    SandboxWrapped,
     TestWebIDLFile,
     TestManifest,
     VariablePassthru,
     WebIDLFile,
     XPIDLFile,
 )
 
 from .reader import (
@@ -243,16 +244,19 @@ class TreeMetadataEmitter(LoggingMixin):
             XPCSHELL_TESTS=('xpcshell', 'xpcshell', False),
         )
 
         for prefix, info in test_manifests.items():
             for path in sandbox.get('%s_MANIFESTS' % prefix, []):
                 for obj in self._process_test_manifest(sandbox, info, path):
                     yield obj
 
+        for name, jar in sandbox.get('JAVA_JAR_TARGETS', {}).items():
+            yield SandboxWrapped(sandbox, jar)
+
     def _process_test_manifest(self, sandbox, info, manifest_path):
         flavor, install_prefix, filter_inactive = info
 
         manifest_path = os.path.normpath(manifest_path)
         path = mozpath.normpath(mozpath.join(sandbox['SRCDIR'], manifest_path))
         manifest_dir = mozpath.dirname(path)
         manifest_reldir = mozpath.dirname(mozpath.relpath(path,
             sandbox['TOPSRCDIR']))
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -35,16 +35,20 @@ from io import StringIO
 
 from mozbuild.util import (
     ReadOnlyDefaultDict,
     ReadOnlyDict,
 )
 
 from mozbuild.backend.configenvironment import ConfigEnvironment
 
+from .data import (
+    JavaJarData,
+)
+
 from .sandbox import (
     SandboxError,
     SandboxExecutionError,
     SandboxLoadError,
     Sandbox,
 )
 
 from .sandbox_symbols import (
@@ -217,16 +221,32 @@ class MozbuildSandbox(Sandbox):
         # protection, so it is omitted.
         normalized_path = os.path.normpath(path)
         if not is_read_allowed(normalized_path, self.config):
             raise SandboxLoadError(list(self._execution_stack),
                 sys.exc_info()[2], illegal_path=path)
 
         Sandbox.exec_file(self, path)
 
+    def _add_java_jar(self, name):
+        """Add a Java JAR build target."""
+        if not name:
+            raise Exception('Java JAR cannot be registered without a name')
+
+        if '/' in name or '\\' in name or '.jar' in name:
+            raise Exception('Java JAR names must not include slashes or'
+                ' .jar: %s' % name)
+
+        if self['JAVA_JAR_TARGETS'].has_key(name):
+            raise Exception('Java JAR has already been registered: %s' % name)
+
+        jar = JavaJarData(name)
+        self['JAVA_JAR_TARGETS'][name] = jar
+        return jar
+
     def _add_tier_directory(self, tier, reldir, static=False, external=False):
         """Register a tier directory with the build."""
         if isinstance(reldir, text_type):
             reldir = [reldir]
 
         if not tier in self['TIERS']:
             self['TIERS'][tier] = {
                 'regular': [],
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -230,16 +230,23 @@ VARIABLES = {
         converted to not use Makefile's for the build frontend, this will
         likely go away.
         """, None),
 
     'HOST_LIBRARY_NAME': (unicode, unicode, "",
         """Name of target library generated when cross compiling.
         """, 'binaries'),
 
+    'JAVA_JAR_TARGETS': (dict, dict, {},
+        """Defines Java JAR targets to be built.
+
+        This variable should not be populated directly. Instead, it should
+        populated by calling add_java_jar().
+        """, 'binaries'),
+
     'JS_MODULES_PATH': (unicode, unicode, "",
         """Sub-directory of ``$(FINAL_TARGET)`` to install
         ``EXTRA_JS_MODULES``.
 
         ``EXTRA_JS_MODULES`` files are copied to
         ``$(FINAL_TARGET)/$(JS_MODULES_PATH)``. This variable does not
         need to be defined if the desired destination directory is
         ``$(FINAL_TARGET)/modules``.
@@ -569,16 +576,29 @@ FUNCTIONS = {
 
            include('sibling.build')
 
         Include ``foo.build`` from a path within the top source directory::
 
            include('/elsewhere/foo.build')
         """),
 
+    'add_java_jar': ('_add_java_jar', (str,),
+        """Declare a Java JAR target to be built.
+
+        This is the supported way to populate the JAVA_JAR_TARGETS
+        variable.
+
+        The parameters are:
+        * dest - target name, without the trailing .jar. (required)
+
+        This returns a rich Java JAR type, described at
+        :py:class:`mozbuild.frontend.data.JavaJarData`.
+        """),
+
     'add_tier_dir': ('_add_tier_directory', (str, [str, list], bool, bool),
         """Register a directory for tier traversal.
 
         This is the preferred way to populate the TIERS variable.
 
         Tiers are how the build system is organized. The build process is
         divided into major phases called tiers. The most important tiers are
         "platform" and "apps." The platform tier builds the Gecko platform