Bug 910660 - Make the SimplePackager emit a separate base for addons. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 13 Mar 2015 15:29:35 +0900
changeset 265492 9403517d849cb171bb324072230ffc9e97fd7cde
parent 265491 b73fca5142ce0680a835967bf64c630d541dc59a
child 265493 c091c6c2861f14826f1612ca6ecf44c9b1a3c965
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs910660
milestone39.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 910660 - Make the SimplePackager emit a separate base for addons. r=gps 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
@@ -211,18 +211,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):
@@ -378,19 +378,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)