Bug 1451733 - [mozprofile] Remove ability to install from a manifest r=jmaher
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 05 Apr 2018 09:54:31 -0400
changeset 778783 796b0795dc5a65c700efce740cfb3c6d2698bad6
parent 778782 13d1bdd6e8cea4a88c3aaa55a5e2b9a236fb8ddb
child 778784 538664e0c82226505628be47a04ff475cdd7f893
push id105582
push userkgupta@mozilla.com
push dateFri, 06 Apr 2018 21:31:13 +0000
reviewersjmaher
bugs1451733
milestone61.0a1
Bug 1451733 - [mozprofile] Remove ability to install from a manifest r=jmaher This feature isn't used anywhere in mozilla-central that I can tell. Because using a manifest is the only way to install an addon from AMO, that ability has also been removed with this commit. MozReview-Commit-ID: BNFGPWdo96t
testing/mozbase/mozprofile/mozprofile/addons.py
testing/mozbase/mozprofile/mozprofile/cli.py
testing/mozbase/mozprofile/mozprofile/profile.py
testing/mozbase/mozprofile/tests/addon_stubs.py
testing/mozbase/mozprofile/tests/test_addons.py
--- a/testing/mozbase/mozprofile/mozprofile/addons.py
+++ b/testing/mozbase/mozprofile/mozprofile/addons.py
@@ -14,23 +14,19 @@ import hashlib
 from xml.dom import minidom
 
 from six import reraise, string_types
 from six.moves.urllib import request
 
 import mozfile
 from mozlog.unstructured import getLogger
 
-# Needed for the AMO's rest API -
-# https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API
-AMO_API_VERSION = "1.5"
 _SALT = os.urandom(32).encode('hex')
 _TEMPORARY_ADDON_SUFFIX = "@temporary-addon"
 
-
 # Logger for 'mozprofile.addons' module
 module_logger = getLogger(__name__)
 
 
 class AddonFormatError(Exception):
     """Exception for not well-formed add-on manifest files"""
 
 
@@ -60,17 +56,16 @@ class AddonManager(object):
         # Backup folder for already existing addons
         self.backup_dir = None
 
         # Add-ons downloaded and which have to be removed from the file system
         self.downloaded_addons = []
 
         # Information needed for profile reset (see http://bit.ly/17JesUf)
         self.installed_addons = []
-        self.installed_manifests = []
 
     def __del__(self):
         # reset to pre-instance state
         if self.restore:
             self.clean()
 
     def clean(self):
         """Clean up addons in the profile."""
@@ -158,89 +153,30 @@ class AddonManager(object):
         :param addon_path: path to the add-on directory or XPI
         """
         try:
             self.addon_details(addon_path)
             return True
         except AddonFormatError:
             return False
 
-    def install_addons(self, addons=None, manifests=None):
+    def install_addons(self, addons):
         """
         Installs all types of addons
 
         :param addons: a list of addon paths to install
-        :param manifest: a list of addon manifests to install
         """
+        if not addons:
+            return
 
         # install addon paths
-        if addons:
-            if isinstance(addons, string_types):
-                addons = [addons]
-            for addon in set(addons):
-                self.install_from_path(addon)
-
-        # install addon manifests
-        if manifests:
-            if isinstance(manifests, string_types):
-                manifests = [manifests]
-            for manifest in manifests:
-                self.install_from_manifest(manifest)
-
-    def install_from_manifest(self, filepath):
-        """
-        Installs addons from a manifest
-        :param filepath: path to the manifest of addons to install
-        """
-        try:
-            from manifestparser import ManifestParser
-        except ImportError:
-            module_logger.critical(
-                "Installing addons from manifest requires the"
-                " manifestparser package to be installed.")
-            raise
-
-        manifest = ManifestParser()
-        manifest.read(filepath)
-        addons = manifest.get()
-
-        for addon in addons:
-            if '://' in addon['path'] or os.path.exists(addon['path']):
-                self.install_from_path(addon['path'])
-                continue
-
-            # No path specified, try to grab it off AMO
-            locale = addon.get('amo_locale', 'en_US')
-            query = 'https://services.addons.mozilla.org/' + locale + '/firefox/api/' \
-                    + AMO_API_VERSION + '/'
-            if 'amo_id' in addon:
-                # this query grabs information on the addon base on its id
-                query += 'addon/' + addon['amo_id']
-            else:
-                # this query grabs information on the first addon returned from a search
-                query += 'search/' + addon['name'] + '/default/1'
-            install_path = AddonManager.get_amo_install_path(query)
-            self.install_from_path(install_path)
-
-        self.installed_manifests.append(filepath)
-
-    @classmethod
-    def get_amo_install_path(self, query):
-        """
-        Get the addon xpi install path for the specified AMO query.
-
-        :param query: query-documentation_
-
-        .. _query-documentation: https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API # noqa
-        """
-        response = request.urlopen(query)
-        dom = minidom.parseString(response.read())
-        for node in dom.getElementsByTagName('install')[0].childNodes:
-            if node.nodeType == node.TEXT_NODE:
-                return node.data
+        if isinstance(addons, string_types):
+            addons = [addons]
+        for addon in set(addons):
+            self.install_from_path(addon)
 
     @classmethod
     def _gen_iid(cls, addon_path):
         hash = hashlib.sha1(_SALT)
         hash.update(addon_path)
         return hash.hexdigest() + _TEMPORARY_ADDON_SUFFIX
 
     @classmethod
--- a/testing/mozbase/mozprofile/mozprofile/cli.py
+++ b/testing/mozbase/mozprofile/mozprofile/cli.py
@@ -38,34 +38,30 @@ class MozProfileCLI(object):
 
         parser.add_option("-p", "--profile", dest="profile",
                           help="The path to the profile to operate on. "
                           "If none, creates a new profile in temp directory")
         parser.add_option("-a", "--addon", dest="addons",
                           action="append", default=[],
                           help="Addon paths to install. Can be a filepath, "
                           "a directory containing addons, or a url")
-        parser.add_option("--addon-manifests", dest="addon_manifests",
-                          action="append",
-                          help="An addon manifest to install")
         parser.add_option("--pref", dest="prefs",
                           action='append', default=[],
                           help="A preference to set. "
                           "Must be a key-value pair separated by a ':'")
         parser.add_option("--preferences", dest="prefs_files",
                           action='append', default=[],
                           metavar="FILE",
                           help="read preferences from a JSON or INI file. "
                           "For INI, use 'file.ini:section' to specify a particular section.")
 
     def profile_args(self):
         """arguments to instantiate the profile class"""
         return dict(profile=self.options.profile,
                     addons=self.options.addons,
-                    addon_manifests=self.options.addon_manifests,
                     preferences=self.preferences())
 
     def preferences(self):
         """profile preferences"""
 
         # object to hold preferences
         prefs = Preferences()
 
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -40,32 +40,29 @@ class Profile(object):
     the profile as a context manager: ::
 
       with Profile() as profile:
           # do things with the profile
           pass
       # profile.cleanup() has been called here
     """
 
-    def __init__(self, profile=None, addons=None, addon_manifests=None,
-                 preferences=None, locations=None, proxy=None, restore=True,
-                 whitelistpaths=None):
+    def __init__(self, profile=None, addons=None, preferences=None, locations=None,
+                 proxy=None, restore=True, whitelistpaths=None):
         """
         :param profile: Path to the profile
         :param addons: String of one or list of addons to install
-        :param addon_manifests: Manifest for addons (see http://bit.ly/17jQ7i6)
         :param preferences: Dictionary or class of preferences
         :param locations: ServerLocations object
         :param proxy: Setup a proxy
         :param restore: Flag for removing all custom settings during cleanup
         :param whitelistpaths: List of paths to pass to Firefox to allow read
             access to from the content process sandbox.
         """
         self._addons = addons
-        self._addon_manifests = addon_manifests
         self._locations = locations
         self._proxy = proxy
 
         # Prepare additional preferences
         if preferences:
             if isinstance(preferences, dict):
                 # unordered
                 preferences = preferences.items()
@@ -131,17 +128,17 @@ class Profile(object):
             else:
                 prefs_js.append(("security.sandbox.content.read_path_whitelist",
                                  ",".join(self._whitelistpaths)))
         self.set_preferences(prefs_js, 'prefs.js')
         self.set_preferences(user_js)
 
         # handle add-on installation
         self.addon_manager = AddonManager(self.profile, restore=self.restore)
-        self.addon_manager.install_addons(self._addons, self._addon_manifests)
+        self.addon_manager.install_addons(self._addons)
 
     def __enter__(self):
         return self
 
     def __exit__(self, type, value, traceback):
         self.cleanup()
 
     def __del__(self):
--- a/testing/mozbase/mozprofile/tests/addon_stubs.py
+++ b/testing/mozbase/mozprofile/tests/addon_stubs.py
@@ -61,20 +61,8 @@ def generate_addon(addon_id, path=None, 
     xpi_file = os.path.join(tmpdir, (name or addon_id) + '.xpi')
     with zipfile.ZipFile(xpi_file, 'w') as x:
         x.write(install_rdf, install_rdf[len(addon_dir):])
 
     # Ensure we remove the temporary folder to not install the addon twice
     mozfile.rmtree(addon_dir)
 
     return xpi_file
-
-
-def generate_manifest(addon_list, path=None):
-    tmpdir = path or tempfile.mkdtemp()
-    addons = [generate_addon(addon, path=tmpdir) for addon in addon_list]
-
-    manifest = os.path.join(tmpdir, 'manifest.ini')
-    with open(manifest, 'w') as f:
-        for addon in addons:
-            f.write('[' + addon + ']\n')
-
-    return manifest
--- a/testing/mozbase/mozprofile/tests/test_addons.py
+++ b/testing/mozbase/mozprofile/tests/test_addons.py
@@ -8,23 +8,22 @@ from __future__ import absolute_import
 
 import os
 import tempfile
 import unittest
 import zipfile
 
 import mozunit
 
-from manifestparser import ManifestParser
 import mozfile
 import mozhttpd
 import mozlog.unstructured as mozlog
 import mozprofile
 
-from addon_stubs import generate_addon, generate_manifest
+from addon_stubs import generate_addon
 from six.moves.urllib import error
 
 
 here = os.path.dirname(os.path.abspath(__file__))
 
 
 class TestAddonsManager(unittest.TestCase):
     """ Class to test mozprofile.addons.AddonManager """
@@ -313,35 +312,16 @@ class TestAddonsManager(unittest.TestCas
     @unittest.skip("Feature not implemented as part of AddonManger")
     def test_install_from_path_error(self):
         """ Check install_from_path raises an error with an invalid addon"""
 
         temp_addon = generate_addon('test-addon-invalid-version@mozilla.org')
         # This should raise an error here
         self.am.install_from_path(temp_addon)
 
-    def test_install_from_manifest(self):
-        temp_manifest = generate_manifest(['test-addon-1@mozilla.org',
-                                           'test-addon-2@mozilla.org'])
-        m = ManifestParser()
-        m.read(temp_manifest)
-        addons = m.get()
-
-        # Obtain details of addons to install from the manifest
-        addons_to_install = [self.am.addon_details(x['path']).get('id') for x in addons]
-
-        self.am.install_from_manifest(temp_manifest)
-        # Generate a list of addons installed in the profile
-        addons_installed = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
-                            self.profile.profile, 'extensions'))]
-        self.assertEqual(addons_installed.sort(), addons_to_install.sort())
-
-        # Cleanup the temporary addon and manifest directories
-        mozfile.rmtree(os.path.dirname(temp_manifest))
-
     def test_addon_details(self):
         # Generate installer stubs for a valid and invalid add-on manifest
         valid_addon = generate_addon('test-addon-1@mozilla.org',
                                      path=self.tmpdir)
         invalid_addon = generate_addon('test-addon-invalid-not-wellformed@mozilla.org',
                                        path=self.tmpdir)
 
         # Check valid add-on