Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Unified Diff: third_party/mozprofile/mozprofile/addons.py

Issue 108313011: Adding mozilla libraries required by Firefox interop test. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/mozprofile/mozprofile/__init__.py ('k') | third_party/mozprofile/mozprofile/cli.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/mozprofile/mozprofile/addons.py
===================================================================
--- third_party/mozprofile/mozprofile/addons.py (revision 0)
+++ third_party/mozprofile/mozprofile/addons.py (revision 0)
@@ -0,0 +1,229 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import shutil
+import tempfile
+import urllib2
+import zipfile
+from distutils import dir_util
+from manifestparser import ManifestParser
+from xml.dom import minidom
+
+# 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"
+
+class AddonManager(object):
+ """
+ Handles all operations regarding addons including: installing and cleaning addons
+ """
+
+ def __init__(self, profile):
+ """
+ profile - the path to the profile for which we install addons
+ """
+ self.profile = profile
+
+ # information needed for profile reset:
+ # https://github.com/mozilla/mozbase/blob/270a857328b130860d1b1b512e23899557a3c8f7/mozprofile/mozprofile/profile.py#L93
+ self.installed_addons = []
+ self.installed_manifests = []
+
+ # addons that we've installed; needed for cleanup
+ self._addon_dirs = []
+
+ def install_addons(self, addons=None, manifests=None):
+ """
+ Installs all types of addons
+ addons - a list of addon paths to install
+ manifest - a list of addon manifests to install
+ """
+ # install addon paths
+ if addons:
+ if isinstance(addons, basestring):
+ addons = [addons]
+ self.installed_addons.extend(addons)
+ for addon in addons:
+ self.install_from_path(addon)
+ # install addon manifests
+ if manifests:
+ if isinstance(manifests, basestring):
+ manifests = [manifests]
+ for manifest in manifests:
+ self.install_from_manifest(manifest)
+ self.installed_manifests.extended(manifests)
+
+ def install_from_manifest(self, filepath):
+ """
+ Installs addons from a manifest
+ filepath - path to the manifest of addons to install
+ """
+ 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:
+ query += 'addon/' + addon['amo_id'] # this query grabs information on the addon base on its id
+ else:
+ query += 'search/' + addon['name'] + '/default/1' # this query grabs information on the first addon returned from a search
+ install_path = AddonManager.get_amo_install_path(query)
+ self.install_from_path(install_path)
+
+ @classmethod
+ def get_amo_install_path(self, query):
+ """
+ Return the addon xpi install path for the specified AMO query.
+ See: https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API
+ for query documentation.
+ """
+ response = urllib2.urlopen(query)
+ dom = minidom.parseString(response.read())
+ for node in dom.getElementsByTagName('install')[0].childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ return node.data
+
+ @classmethod
+ def addon_details(cls, addon_path):
+ """
+ returns a dictionary of details about the addon
+ - addon_path : path to the addon directory
+ Returns:
+ {'id': u'rainbow@colors.org', # id of the addon
+ 'version': u'1.4', # version of the addon
+ 'name': u'Rainbow', # name of the addon
+ 'unpack': False } # whether to unpack the addon
+ """
+
+ # TODO: We don't use the unpack variable yet, but we should: bug 662683
+ details = {
+ 'id': None,
+ 'unpack': False,
+ 'name': None,
+ 'version': None
+ }
+
+ def get_namespace_id(doc, url):
+ attributes = doc.documentElement.attributes
+ namespace = ""
+ for i in range(attributes.length):
+ if attributes.item(i).value == url:
+ if ":" in attributes.item(i).name:
+ # If the namespace is not the default one remove 'xlmns:'
+ namespace = attributes.item(i).name.split(':')[1] + ":"
+ break
+ return namespace
+
+ def get_text(element):
+ """Retrieve the text value of a given node"""
+ rc = []
+ for node in element.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ rc.append(node.data)
+ return ''.join(rc).strip()
+
+ doc = minidom.parse(os.path.join(addon_path, 'install.rdf'))
+
+ # Get the namespaces abbreviations
+ em = get_namespace_id(doc, "http://www.mozilla.org/2004/em-rdf#")
+ rdf = get_namespace_id(doc, "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+
+ description = doc.getElementsByTagName(rdf + "Description").item(0)
+ for node in description.childNodes:
+ # Remove the namespace prefix from the tag for comparison
+ entry = node.nodeName.replace(em, "")
+ if entry in details.keys():
+ details.update({ entry: get_text(node) })
+
+ # turn unpack into a true/false value
+ if isinstance(details['unpack'], basestring):
+ details['unpack'] = details['unpack'].lower() == 'true'
+
+ return details
+
+ def install_from_path(self, path, unpack=False):
+ """
+ Installs addon from a filepath, url
+ or directory of addons in the profile.
+ - path: url, path to .xpi, or directory of addons
+ - unpack: whether to unpack unless specified otherwise in the install.rdf
+ """
+
+ # if the addon is a url, download it
+ # note that this won't work with protocols urllib2 doesn't support
+ if '://' in path:
+ response = urllib2.urlopen(path)
+ fd, path = tempfile.mkstemp(suffix='.xpi')
+ os.write(fd, response.read())
+ os.close(fd)
+ tmpfile = path
+ else:
+ tmpfile = None
+
+ # if the addon is a directory, install all addons in it
+ addons = [path]
+ if not path.endswith('.xpi') and not os.path.exists(os.path.join(path, 'install.rdf')):
+ # If the path doesn't exist, then we don't really care, just return
+ if not os.path.isdir(path):
+ return
+ addons = [os.path.join(path, x) for x in os.listdir(path) if
+ os.path.isdir(os.path.join(path, x))]
+
+ # install each addon
+ for addon in addons:
+ tmpdir = None
+ xpifile = None
+ if addon.endswith('.xpi'):
+ tmpdir = tempfile.mkdtemp(suffix = '.' + os.path.split(addon)[-1])
+ compressed_file = zipfile.ZipFile(addon, 'r')
+ for name in compressed_file.namelist():
+ if name.endswith('/'):
+ os.makedirs(os.path.join(tmpdir, name))
+ else:
+ if not os.path.isdir(os.path.dirname(os.path.join(tmpdir, name))):
+ os.makedirs(os.path.dirname(os.path.join(tmpdir, name)))
+ data = compressed_file.read(name)
+ f = open(os.path.join(tmpdir, name), 'wb')
+ f.write(data)
+ f.close()
+ xpifile = addon
+ addon = tmpdir
+
+ # determine the addon id
+ addon_details = AddonManager.addon_details(addon)
+ addon_id = addon_details.get('id')
+ assert addon_id, 'The addon id could not be found: %s' % addon
+
+ # copy the addon to the profile
+ extensions_path = os.path.join(self.profile, 'extensions', 'staged')
+ addon_path = os.path.join(extensions_path, addon_id)
+ if not unpack and not addon_details['unpack'] and xpifile:
+ if not os.path.exists(extensions_path):
+ os.makedirs(extensions_path)
+ shutil.copy(xpifile, addon_path + '.xpi')
+ else:
+ dir_util.copy_tree(addon, addon_path, preserve_symlinks=1)
+ self._addon_dirs.append(addon_path)
+
+ # remove the temporary directory, if any
+ if tmpdir:
+ dir_util.remove_tree(tmpdir)
+
+ # remove temporary file, if any
+ if tmpfile:
+ os.remove(tmpfile)
+
+ def clean_addons(self):
+ """Cleans up addons in the profile."""
+ for addon in self._addon_dirs:
+ if os.path.isdir(addon):
+ dir_util.remove_tree(addon)
Property changes on: third_party/mozprofile/mozprofile/addons.py
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « third_party/mozprofile/mozprofile/__init__.py ('k') | third_party/mozprofile/mozprofile/cli.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698