Bug 910660 - Make the SimplePackager emit a separate base for addons. r=gps, a=sledru
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 13 Mar 2015 15:29:35 +0900
changeset 258296 f4f4979e09b2
parent 258295 90925932c88c
child 258297 f9441895096d
push id4638
push userryanvm@gmail.com
push date2015-04-06 20:41 +0000
treeherdermozilla-beta@499e1c563939 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps, sledru
bugs910660
milestone38.0
Bug 910660 - Make the SimplePackager emit a separate base for addons. r=gps, a=sledru Addons are detected by the presence of an install.rdf file in their base.
python/mozbuild/mozpack/packager/__init__.py
python/mozbuild/mozpack/test/test_packager.py
toolkit/mozapps/installer/packager.py
--- a/python/mozbuild/mozpack/packager/__init__.py
+++ b/python/mozbuild/mozpack/packager/__init__.py
@@ -229,16 +229,18 @@ class SimplePackager(object):
     def __init__(self, formatter):
         self.formatter = formatter
         # Queue for formatter.add_interfaces()/add_manifest() calls.
         self._queue = CallDeque()
         # Queue for formatter.add_manifest() calls for ManifestChrome.
         self._chrome_queue = CallDeque()
         # Queue for formatter.add() calls.
         self._file_queue = CallDeque()
+        # All paths containing addons.
+        self._addons = set()
         # All manifest paths imported.
         self._manifests = set()
         # All manifest paths included from some other manifest.
         self._included_manifests = set()
         self._closed = False
 
     def add(self, path, file):
         '''
@@ -246,16 +248,18 @@ class SimplePackager(object):
         '''
         assert not self._closed
         if is_manifest(path):
             self._add_manifest_file(path, file)
         elif path.endswith('.xpt'):
             self._queue.append(self.formatter.add_interfaces, path, file)
         else:
             self._file_queue.append(self.formatter.add, path, file)
+            if mozpack.path.basename(path) == 'install.rdf':
+                self._addons.add(mozpack.path.dirname(path))
 
     def _add_manifest_file(self, path, file):
         '''
         Add the given BaseFile with manifest file contents with the given path.
         '''
         self._manifests.add(path)
         base = ''
         if hasattr(file, 'path'):
@@ -273,32 +277,43 @@ class SimplePackager(object):
             elif not isinstance(e, (Manifest, ManifestInterfaces)):
                 self._queue.append(self.formatter.add_manifest, e.move(e.base))
             if isinstance(e, Manifest):
                 if e.flags:
                     errors.fatal('Flags are not supported on ' +
                                  '"manifest" entries')
                 self._included_manifests.add(e.path)
 
-    def get_bases(self):
+    def get_bases(self, addons=True):
         '''
         Return all paths under which root manifests have been found. Root
         manifests are manifests that are included in no other manifest.
+        `addons` indicates whether to include addon bases as well.
         '''
-        return set(mozpack.path.dirname(m)
-                   for m in self._manifests - self._included_manifests)
+        all_bases = set(mozpack.path.dirname(m)
+                        for m in self._manifests - self._included_manifests)
+        if not addons:
+            all_bases -= self._addons
+        return all_bases
 
     def close(self):
         '''
         Push all instructions to the formatter.
         '''
         self._closed = True
+        broken_addons = sorted(m for m in self._included_manifests
+                               if mozpack.path.dirname(m) in self._addons)
+        if broken_addons:
+            errors.fatal(
+                'Addon base manifest (%s) is included in some other manifest' %
+                ', '.join(broken_addons)
+            )
         for base in self.get_bases():
             if base:
-                self.formatter.add_base(base)
+                self.formatter.add_base(base, base in self._addons)
         self._chrome_queue.execute()
         self._queue.execute()
         self._file_queue.execute()
 
 
 class SimpleManifestSink(object):
     '''
     Parser sink for "simple" package manifests. Simple package manifests use
--- a/python/mozbuild/mozpack/test/test_packager.py
+++ b/python/mozbuild/mozpack/test/test_packager.py
@@ -166,40 +166,55 @@ class TestSimplePackager(unittest.TestCa
                                          'manifest foo/bar.manifest\n',
                                          'manifest bar/baz.manifest\n',
                                      ]))
         with errors.context('manifest', 6):
             packager.add('foo.manifest', file)
         with errors.context('manifest', 7):
             packager.add('foo/qux.xpt', qux_xpt)
 
+        file = GeneratedFileWithPath(os.path.join(curdir, 'addon',
+                                                  'chrome.manifest'),
+                                     'resource hoge hoge/')
+        with errors.context('manifest', 8):
+            packager.add('addon/chrome.manifest', file)
+
+        install_rdf = GeneratedFile('<RDF></RDF>')
+        with errors.context('manifest', 9):
+            packager.add('addon/install.rdf', install_rdf)
+
         self.assertEqual(formatter.log, [])
 
         with errors.context('dummy', 1):
             packager.close()
         self.maxDiff = None
         # The formatter is expected to reorder the manifest entries so that
         # chrome entries appear before the others.
         self.assertEqual(formatter.log, [
-            (('dummy', 1), 'add_base', 'qux'),
+            (('dummy', 1), 'add_base', 'qux', False),
+            (('dummy', 1), 'add_base', 'addon', True),
             ((os.path.join(curdir, 'foo', 'bar.manifest'), 2),
              'add_manifest', ManifestContent('foo', 'bar', 'bar/')),
             ((os.path.join(curdir, 'foo', 'bar.manifest'), 1),
              'add_manifest', ManifestResource('foo', 'bar', 'bar/')),
             (('bar/baz.manifest', 1),
              'add_manifest', ManifestResource('bar', 'baz', 'baz/')),
             (('qux/qux.manifest', 1),
              'add_manifest', ManifestResource('qux', 'qux', 'qux/')),
             (('manifest', 4), 'add_interfaces', 'foo/bar.xpt', bar_xpt),
             (('manifest', 7), 'add_interfaces', 'foo/qux.xpt', qux_xpt),
+            ((os.path.join(curdir, 'addon', 'chrome.manifest'), 1),
+             'add_manifest', ManifestResource('addon', 'hoge', 'hoge/')),
             (('manifest', 5), 'add', 'foo/bar/foo.html', foo_html),
             (('manifest', 5), 'add', 'foo/bar/bar.html', bar_html),
+            (('manifest', 9), 'add', 'addon/install.rdf', install_rdf),
         ])
 
-        self.assertEqual(packager.get_bases(), set(['', 'qux']))
+        self.assertEqual(packager.get_bases(), set(['', 'addon', 'qux']))
+        self.assertEqual(packager.get_bases(addons=False), set(['', 'qux']))
 
 
 class TestSimpleManifestSink(unittest.TestCase):
     def test_simple_manifest_parser(self):
         formatter = MockFormatter()
         foobar = GeneratedFile('foobar')
         foobaz = GeneratedFile('foobaz')
         fooqux = GeneratedFile('fooqux')
--- a/toolkit/mozapps/installer/packager.py
+++ b/toolkit/mozapps/installer/packager.py
@@ -209,18 +209,18 @@ class NoPkgFilesRemover(object):
         self._files = os.environ['NO_PKG_FILES'].split()
         if has_manifest:
             self._error = errors.error
             self._msg = 'NO_PKG_FILES contains file listed in manifest: %s'
         else:
             self._error = errors.warn
             self._msg = 'Skipping %s'
 
-    def add_base(self, base):
-        self._formatter.add_base(base)
+    def add_base(self, base, *args):
+        self._formatter.add_base(base, *args)
 
     def add(self, path, content):
         if not any(mozpack.path.match(path, spec) for spec in self._files):
             self._formatter.add(path, content)
         else:
             self._error(self._msg % path)
 
     def add_manifest(self, entry):
@@ -377,19 +377,23 @@ def main():
     # Fill startup cache
     if isinstance(formatter, OmniJarFormatter) and launcher.can_launch() \
       and buildconfig.substs['MOZ_DISABLE_STARTUPCACHE'] != '1':
         if buildconfig.substs.get('LIBXUL_SDK'):
             gre_path = mozpack.path.join(buildconfig.substs['LIBXUL_DIST'],
                                          'bin')
         else:
             gre_path = None
-        for base in sorted([[p for p in [mozpack.path.join('bin', b), b]
-                            if os.path.exists(os.path.join(args.source, p))][0]
-                           for b in sink.packager.get_bases()]):
+        def get_bases():
+            for b in sink.packager.get_bases(addons=False):
+                for p in (mozpack.path.join('bin', b), b):
+                    if os.path.exists(os.path.join(args.source, p)):
+                        yield p
+                        break
+        for base in sorted(get_bases()):
             if not gre_path:
                 gre_path = base
             base_path = sink.normalize_path(base)
             if base_path in formatter.omnijars:
                 precompile_cache(formatter.omnijars[base_path],
                                  args.source, gre_path, base)
 
     copier.copy(args.destination)