Bug 1431229 - Populate WebIDLCollection from the emitter rather than the common backend. draft
authorChris Manchester <cmanchester@mozilla.com>
Wed, 24 Jan 2018 13:55:06 -0800
changeset 724323 8c8344d9310d3f61b9077ea028f1b46f316e36f0
parent 724322 d15802decad40d56b92648d5421e105c2c1ddc3d
child 724324 d328f7ff2ac293c6f01c0fd416efaa57ed24e0d0
push id96730
push userbmo:cmanchester@mozilla.com
push dateWed, 24 Jan 2018 21:55:37 +0000
bugs1431229
milestone60.0a1
Bug 1431229 - Populate WebIDLCollection from the emitter rather than the common backend. MozReview-Commit-ID: JVaoPF53rhY
python/mozbuild/mozbuild/backend/common.py
python/mozbuild/mozbuild/frontend/data.py
python/mozbuild/mozbuild/frontend/emitter.py
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -18,33 +18,27 @@ from mozbuild.frontend.context import (
     Path,
     RenamedSourcePath,
     VARIABLES,
 )
 from mozbuild.frontend.data import (
     BaseProgram,
     ChromeManifestEntry,
     ConfigFileSubstitution,
-    ExampleWebIDLInterface,
     Exports,
     IPDLFile,
     FinalTargetPreprocessedFiles,
     FinalTargetFiles,
-    GeneratedEventWebIDLFile,
     GeneratedSources,
-    GeneratedWebIDLFile,
     GnProjectData,
     PreprocessedIPDLFile,
-    PreprocessedTestWebIDLFile,
-    PreprocessedWebIDLFile,
     SharedLibrary,
-    TestWebIDLFile,
     UnifiedSources,
     XPIDLFile,
-    WebIDLFile,
+    WebIDLCollection,
 )
 from mozbuild.jar import (
     DeprecatedJarManifest,
     JarManifestParser,
 )
 from mozbuild.preprocessor import Preprocessor
 from mozpack.chrome.manifest import parse_manifest_line
 
@@ -88,90 +82,16 @@ class XPIDLManager(object):
         t = self.modules.setdefault(entry['module'], (idl.install_target, set()))
         t[1].add(entry['root'])
 
         if idl.add_to_manifest:
             self.interface_manifests.setdefault(manifest, set()).add(xpt)
             self.chrome_manifests.add(chrome_manifest)
 
 
-class WebIDLCollection(object):
-    """Collects WebIDL info referenced during the build."""
-
-    def __init__(self):
-        self.sources = set()
-        self.generated_sources = set()
-        self.generated_events_sources = set()
-        self.preprocessed_sources = set()
-        self.test_sources = set()
-        self.preprocessed_test_sources = set()
-        self.example_interfaces = set()
-
-    def all_regular_sources(self):
-        return self.sources | self.generated_sources | \
-            self.generated_events_sources | self.preprocessed_sources
-
-    def all_regular_basenames(self):
-        return [os.path.basename(source) for source in self.all_regular_sources()]
-
-    def all_regular_stems(self):
-        return [os.path.splitext(b)[0] for b in self.all_regular_basenames()]
-
-    def all_regular_bindinggen_stems(self):
-        for stem in self.all_regular_stems():
-            yield '%sBinding' % stem
-
-        for source in self.generated_events_sources:
-            yield os.path.splitext(os.path.basename(source))[0]
-
-    def all_regular_cpp_basenames(self):
-        for stem in self.all_regular_bindinggen_stems():
-            yield '%s.cpp' % stem
-
-    def all_test_sources(self):
-        return self.test_sources | self.preprocessed_test_sources
-
-    def all_test_basenames(self):
-        return [os.path.basename(source) for source in self.all_test_sources()]
-
-    def all_test_stems(self):
-        return [os.path.splitext(b)[0] for b in self.all_test_basenames()]
-
-    def all_test_cpp_basenames(self):
-        return ['%sBinding.cpp' % s for s in self.all_test_stems()]
-
-    def all_static_sources(self):
-        return self.sources | self.generated_events_sources | \
-            self.test_sources
-
-    def all_non_static_sources(self):
-        return self.generated_sources | self.all_preprocessed_sources()
-
-    def all_non_static_basenames(self):
-        return [os.path.basename(s) for s in self.all_non_static_sources()]
-
-    def all_preprocessed_sources(self):
-        return self.preprocessed_sources | self.preprocessed_test_sources
-
-    def all_sources(self):
-        return set(self.all_regular_sources()) | set(self.all_test_sources())
-
-    def all_basenames(self):
-        return [os.path.basename(source) for source in self.all_sources()]
-
-    def all_stems(self):
-        return [os.path.splitext(b)[0] for b in self.all_basenames()]
-
-    def generated_events_basenames(self):
-        return [os.path.basename(s) for s in self.generated_events_sources]
-
-    def generated_events_stems(self):
-        return [os.path.splitext(b)[0] for b in self.generated_events_basenames()]
-
-
 class BinariesCollection(object):
     """Tracks state of binaries produced by the build."""
 
     def __init__(self):
         self.shared_libraries = []
         self.programs = []
 
 class IPDLCollection(object):
@@ -190,17 +110,16 @@ class IPDLCollection(object):
     def all_preprocessed_sources(self):
         return self.preprocessed_sources
 
 class CommonBackend(BuildBackend):
     """Holds logic common to all build backends."""
 
     def _init(self):
         self._idl_manager = XPIDLManager(self.environment)
-        self._webidls = WebIDLCollection()
         self._binaries = BinariesCollection()
         self._configs = set()
         self._ipdls = IPDLCollection()
         self._generated_sources = set()
 
     def consume_object(self, obj):
         self._configs.add(obj.config)
 
@@ -213,78 +132,26 @@ class CommonBackend(BuildBackend):
             # Do not handle ConfigFileSubstitution for Makefiles. Leave that
             # to other
             if mozpath.basename(obj.output_path) == 'Makefile':
                 return False
             with self._get_preprocessor(obj) as pp:
                 pp.do_include(obj.input_path)
             self.backend_input_files.add(obj.input_path)
 
-        # We should consider aggregating WebIDL types in emitter.py.
-        elif isinstance(obj, WebIDLFile):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.sources.add(mozpath.join(obj.srcdir, obj.basename))
-
-        elif isinstance(obj, GeneratedEventWebIDLFile):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.generated_events_sources.add(mozpath.join(
-                obj.srcdir, obj.basename))
-
-        elif isinstance(obj, TestWebIDLFile):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.test_sources.add(mozpath.join(obj.srcdir,
-                obj.basename))
-
-        elif isinstance(obj, PreprocessedTestWebIDLFile):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.preprocessed_test_sources.add(mozpath.join(
-                obj.srcdir, obj.basename))
-
-        elif isinstance(obj, GeneratedWebIDLFile):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.generated_sources.add(mozpath.join(obj.srcdir,
-                obj.basename))
+        elif isinstance(obj, WebIDLCollection):
+            self._handle_webidl_collection(obj)
 
         elif isinstance(obj, PreprocessedIPDLFile):
             if self.environment.is_artifact_build:
                 return True
 
             self._ipdls.preprocessed_sources.add(mozpath.join(
                 obj.srcdir, obj.basename))
 
-        elif isinstance(obj, PreprocessedWebIDLFile):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.preprocessed_sources.add(mozpath.join(
-                obj.srcdir, obj.basename))
-
-        elif isinstance(obj, ExampleWebIDLInterface):
-            # WebIDL isn't relevant to artifact builds.
-            if self.environment.is_artifact_build:
-                return True
-
-            self._webidls.example_interfaces.add(obj.name)
-
         elif isinstance(obj, IPDLFile):
             # IPDL isn't relevant to artifact builds.
             if self.environment.is_artifact_build:
                 return True
 
             self._ipdls.sources.add(mozpath.join(obj.srcdir, obj.basename))
 
         elif isinstance(obj, UnifiedSources):
@@ -325,18 +192,16 @@ class CommonBackend(BuildBackend):
 
         return True
 
     def consume_finished(self):
         if len(self._idl_manager.idls):
             self._handle_idl_manager(self._idl_manager)
             self._handle_generated_sources(mozpath.join(self.environment.topobjdir, 'dist/include/%s.h' % idl['root']) for idl in self._idl_manager.idls.values())
 
-        self._handle_webidl_collection(self._webidls)
-
         sorted_ipdl_sources = list(sorted(self._ipdls.all_sources()))
         sorted_nonstatic_ipdl_sources = list(sorted(self._ipdls.all_preprocessed_sources()))
         sorted_static_ipdl_sources = list(sorted(self._ipdls.all_regular_sources()))
 
         def files_from(ipdl):
             base = mozpath.basename(ipdl)
             root, ext = mozpath.splitext(base)
 
@@ -379,18 +244,16 @@ class CommonBackend(BuildBackend):
                 'sources': sorted(self._generated_sources),
             }
             json.dump(d, fh, sort_keys=True, indent=4)
 
     def _handle_generated_sources(self, files):
         self._generated_sources.update(mozpath.relpath(f, self.environment.topobjdir) for f in files)
 
     def _handle_webidl_collection(self, webidls):
-        if not webidls.all_stems():
-            return
 
         bindings_dir = mozpath.join(self.environment.topobjdir, 'dom', 'bindings')
 
         all_inputs = set(webidls.all_static_sources())
         for s in webidls.all_non_static_basenames():
             all_inputs.add(mozpath.join(bindings_dir, s))
 
         generated_events_stems = webidls.generated_events_stems()
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -227,16 +227,90 @@ class BaseDefines(ContextDerived):
             self.defines.update(more_defines)
 
 class Defines(BaseDefines):
     pass
 
 class HostDefines(BaseDefines):
     pass
 
+class WebIDLCollection(ContextDerived):
+    """Collects WebIDL info referenced during the build."""
+
+    def __init__(self, context):
+        ContextDerived.__init__(self, context)
+        self.sources = set()
+        self.generated_sources = set()
+        self.generated_events_sources = set()
+        self.preprocessed_sources = set()
+        self.test_sources = set()
+        self.preprocessed_test_sources = set()
+        self.example_interfaces = set()
+
+    def all_regular_sources(self):
+        return self.sources | self.generated_sources | \
+            self.generated_events_sources | self.preprocessed_sources
+
+    def all_regular_basenames(self):
+        return [mozpath.basename(source) for source in self.all_regular_sources()]
+
+    def all_regular_stems(self):
+        return [mozpath.splitext(b)[0] for b in self.all_regular_basenames()]
+
+    def all_regular_bindinggen_stems(self):
+        for stem in self.all_regular_stems():
+            yield '%sBinding' % stem
+
+        for source in self.generated_events_sources:
+            yield mozpath.splitext(mozpath.basename(source))[0]
+
+    def all_regular_cpp_basenames(self):
+        for stem in self.all_regular_bindinggen_stems():
+            yield '%s.cpp' % stem
+
+    def all_test_sources(self):
+        return self.test_sources | self.preprocessed_test_sources
+
+    def all_test_basenames(self):
+        return [mozpath.basename(source) for source in self.all_test_sources()]
+
+    def all_test_stems(self):
+        return [mozpath.splitext(b)[0] for b in self.all_test_basenames()]
+
+    def all_test_cpp_basenames(self):
+        return ['%sBinding.cpp' % s for s in self.all_test_stems()]
+
+    def all_static_sources(self):
+        return self.sources | self.generated_events_sources | \
+            self.test_sources
+
+    def all_non_static_sources(self):
+        return self.generated_sources | self.all_preprocessed_sources()
+
+    def all_non_static_basenames(self):
+        return [mozpath.basename(s) for s in self.all_non_static_sources()]
+
+    def all_preprocessed_sources(self):
+        return self.preprocessed_sources | self.preprocessed_test_sources
+
+    def all_sources(self):
+        return set(self.all_regular_sources()) | set(self.all_test_sources())
+
+    def all_basenames(self):
+        return [mozpath.basename(source) for source in self.all_sources()]
+
+    def all_stems(self):
+        return [mozpath.splitext(b)[0] for b in self.all_basenames()]
+
+    def generated_events_basenames(self):
+        return [mozpath.basename(s) for s in self.generated_events_sources]
+
+    def generated_events_stems(self):
+        return [mozpath.splitext(b)[0] for b in self.generated_events_basenames()]
+
 class IPDLFile(ContextDerived):
     """Describes an individual .ipdl source file."""
 
     __slots__ = (
         'basename',
     )
 
     def __init__(self, context, path):
@@ -251,103 +325,16 @@ class PreprocessedIPDLFile(ContextDerive
         'basename',
     )
 
     def __init__(self, context, path):
         ContextDerived.__init__(self, context)
 
         self.basename = path
 
-class WebIDLFile(ContextDerived):
-    """Describes an individual .webidl source file."""
-
-    __slots__ = (
-        'basename',
-    )
-
-    def __init__(self, context, path):
-        ContextDerived.__init__(self, context)
-
-        self.basename = path
-
-class GeneratedEventWebIDLFile(ContextDerived):
-    """Describes an individual .webidl source file."""
-
-    __slots__ = (
-        'basename',
-    )
-
-    def __init__(self, context, path):
-        ContextDerived.__init__(self, context)
-
-        self.basename = path
-
-class TestWebIDLFile(ContextDerived):
-    """Describes an individual test-only .webidl source file."""
-
-    __slots__ = (
-        'basename',
-    )
-
-    def __init__(self, context, path):
-        ContextDerived.__init__(self, context)
-
-        self.basename = path
-
-class PreprocessedTestWebIDLFile(ContextDerived):
-    """Describes an individual test-only .webidl source file that requires
-    preprocessing."""
-
-    __slots__ = (
-        'basename',
-    )
-
-    def __init__(self, context, path):
-        ContextDerived.__init__(self, context)
-
-        self.basename = path
-
-class PreprocessedWebIDLFile(ContextDerived):
-    """Describes an individual .webidl source file that requires preprocessing."""
-
-    __slots__ = (
-        'basename',
-    )
-
-    def __init__(self, context, path):
-        ContextDerived.__init__(self, context)
-
-        self.basename = path
-
-class GeneratedWebIDLFile(ContextDerived):
-    """Describes an individual .webidl source file that is generated from
-    build rules."""
-
-    __slots__ = (
-        'basename',
-    )
-
-    def __init__(self, context, path):
-        ContextDerived.__init__(self, context)
-
-        self.basename = path
-
-
-class ExampleWebIDLInterface(ContextDerived):
-    """An individual WebIDL interface to generate."""
-
-    __slots__ = (
-        'name',
-    )
-
-    def __init__(self, context, name):
-        ContextDerived.__init__(self, context)
-
-        self.name = name
-
 
 class LinkageWrongKindError(Exception):
     """Error thrown when trying to link objects of the wrong kind"""
 
 
 class LinkageMultipleRustLibrariesError(Exception):
     """Error thrown when trying to link multiple Rust libraries to an object"""
 
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -33,22 +33,19 @@ from .data import (
     ComputedFlags,
     ConfigFileSubstitution,
     ContextWrapped,
     Defines,
     DirectoryTraversal,
     Exports,
     FinalTargetFiles,
     FinalTargetPreprocessedFiles,
-    GeneratedEventWebIDLFile,
     GeneratedFile,
     GeneratedSources,
-    GeneratedWebIDLFile,
     GnProjectData,
-    ExampleWebIDLInterface,
     ExternalStaticLibrary,
     ExternalSharedLibrary,
     HostDefines,
     HostLibrary,
     HostProgram,
     HostRustProgram,
     HostSimpleProgram,
     HostSources,
@@ -59,33 +56,30 @@ from .data import (
     Linkable,
     LocalInclude,
     LocalizedFiles,
     LocalizedPreprocessedFiles,
     ObjdirFiles,
     ObjdirPreprocessedFiles,
     PerSourceFlag,
     PreprocessedIPDLFile,
-    PreprocessedTestWebIDLFile,
-    PreprocessedWebIDLFile,
+    WebIDLCollection,
     Program,
     RustLibrary,
     HostRustLibrary,
     RustProgram,
     RustTest,
     SharedLibrary,
     SimpleProgram,
     Sources,
     StaticLibrary,
     TestHarnessFiles,
-    TestWebIDLFile,
     TestManifest,
     UnifiedSources,
     VariablePassthru,
-    WebIDLFile,
     XPIDLFile,
 )
 from mozpack.chrome.manifest import (
     Manifest,
 )
 
 from .reader import SandboxValidationError
 
@@ -139,16 +133,17 @@ class TreeMetadataEmitter(LoggingMixin):
         self._rust_compile_dirs = set()
         self._asm_compile_dirs = set()
         self._compile_flags = dict()
         self._compile_as_flags = dict()
         self._linkage = []
         self._static_linking_shared = set()
         self._crate_verified_local = set()
         self._crate_directories = dict()
+        self._webidls = defaultdict(set)
 
         # Keep track of external paths (third party build systems), starting
         # from what we run a subconfigure in. We'll eliminate some directories
         # as we traverse them with moz.build (e.g. js/src).
         subconfigures = os.path.join(self.config.topobjdir, 'subconfigures')
         paths = []
         if os.path.exists(subconfigures):
             paths = open(subconfigures).read().splitlines()
@@ -289,16 +284,34 @@ class TreeMetadataEmitter(LoggingMixin):
             yield flags_obj
 
         for flags_obj in self._compile_as_flags.values():
             yield flags_obj
 
         for obj in self._binaries.values():
             yield obj
 
+        webidl_root = self.config.substs.get('WEBIDL_ROOT')
+        if webidl_root:
+            idlcollection = WebIDLCollection(contexts[webidl_root])
+            webidl_attrs = [
+                ('GENERATED_EVENTS_WEBIDL_FILES', idlcollection.generated_events_sources),
+                ('GENERATED_WEBIDL_FILES', idlcollection.generated_sources),
+                ('PREPROCESSED_TEST_WEBIDL_FILES', idlcollection.preprocessed_test_sources),
+                ('PREPROCESSED_WEBIDL_FILES', idlcollection.preprocessed_sources),
+                ('TEST_WEBIDL_FILES', idlcollection.test_sources),
+                ('WEBIDL_FILES', idlcollection.sources),
+                ('WEBIDL_EXAMPLE_INTERFACES', idlcollection.example_interfaces),
+            ]
+            for var, src_set in webidl_attrs:
+                src_set |= self._webidls[var]
+
+            yield idlcollection
+
+
     LIBRARY_NAME_VAR = {
         'host': 'HOST_LIBRARY_NAME',
         'target': 'LIBRARY_NAME',
     }
 
     LIBSTDCXX_VAR = {
         'host': 'MOZ_LIBSTDCXX_HOST_VERSION',
         'target': 'MOZ_LIBSTDCXX_TARGET_VERSION',
@@ -1100,30 +1113,38 @@ class TreeMetadataEmitter(LoggingMixin):
                 defines_obj = cls(context, context[defines_var])
 
             defines_from_obj = list(defines_obj.get_defines())
             if defines_from_obj:
                 for flags in backend_flags:
                     flags.resolve_flags(defines_var, defines_from_obj)
 
         simple_lists = [
-            ('GENERATED_EVENTS_WEBIDL_FILES', GeneratedEventWebIDLFile),
-            ('GENERATED_WEBIDL_FILES', GeneratedWebIDLFile),
             ('IPDL_SOURCES', IPDLFile),
             ('PREPROCESSED_IPDL_SOURCES', PreprocessedIPDLFile),
-            ('PREPROCESSED_TEST_WEBIDL_FILES', PreprocessedTestWebIDLFile),
-            ('PREPROCESSED_WEBIDL_FILES', PreprocessedWebIDLFile),
-            ('TEST_WEBIDL_FILES', TestWebIDLFile),
-            ('WEBIDL_FILES', WebIDLFile),
-            ('WEBIDL_EXAMPLE_INTERFACES', ExampleWebIDLInterface),
         ]
         for context_var, klass in simple_lists:
             for name in context.get(context_var, []):
                 yield klass(context, name)
 
+        webidl_vars = (
+            'GENERATED_EVENTS_WEBIDL_FILES',
+            'GENERATED_WEBIDL_FILES',
+            'PREPROCESSED_TEST_WEBIDL_FILES',
+            'PREPROCESSED_WEBIDL_FILES',
+            'TEST_WEBIDL_FILES',
+            'WEBIDL_FILES',
+        )
+        for context_var in webidl_vars:
+            for name in context.get(context_var, []):
+                self._webidls[context_var].add(mozpath.join(context.srcdir, name))
+        # WEBIDL_EXAMPLE_INTERFACES do not correspond to files.
+        for name in context.get('WEBIDL_EXAMPLE_INTERFACES', []):
+            self._webidls['WEBIDL_EXAMPLE_INTERFACES'].add(name)
+
         local_includes = []
         for local_include in context.get('LOCAL_INCLUDES', []):
             full_path = local_include.full_path
             if (not isinstance(local_include, ObjDirPath) and
                     not os.path.exists(full_path)):
                 raise SandboxValidationError('Path specified in LOCAL_INCLUDES '
                     'does not exist: %s (resolved to %s)' % (local_include,
                     full_path), context)