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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/mozprofile/mozprofile/__init__.py ('k') | third_party/mozprofile/mozprofile/cli.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 # You can obtain one at http://mozilla.org/MPL/2.0/.
4
5 import os
6 import shutil
7 import tempfile
8 import urllib2
9 import zipfile
10 from distutils import dir_util
11 from manifestparser import ManifestParser
12 from xml.dom import minidom
13
14 # Needed for the AMO's rest API - https://developer.mozilla.org/en/addons.mozill a.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API
15 AMO_API_VERSION = "1.5"
16
17 class AddonManager(object):
18 """
19 Handles all operations regarding addons including: installing and cleaning a ddons
20 """
21
22 def __init__(self, profile):
23 """
24 profile - the path to the profile for which we install addons
25 """
26 self.profile = profile
27
28 # information needed for profile reset:
29 # https://github.com/mozilla/mozbase/blob/270a857328b130860d1b1b512e2389 9557a3c8f7/mozprofile/mozprofile/profile.py#L93
30 self.installed_addons = []
31 self.installed_manifests = []
32
33 # addons that we've installed; needed for cleanup
34 self._addon_dirs = []
35
36 def install_addons(self, addons=None, manifests=None):
37 """
38 Installs all types of addons
39 addons - a list of addon paths to install
40 manifest - a list of addon manifests to install
41 """
42 # install addon paths
43 if addons:
44 if isinstance(addons, basestring):
45 addons = [addons]
46 self.installed_addons.extend(addons)
47 for addon in addons:
48 self.install_from_path(addon)
49 # install addon manifests
50 if manifests:
51 if isinstance(manifests, basestring):
52 manifests = [manifests]
53 for manifest in manifests:
54 self.install_from_manifest(manifest)
55 self.installed_manifests.extended(manifests)
56
57 def install_from_manifest(self, filepath):
58 """
59 Installs addons from a manifest
60 filepath - path to the manifest of addons to install
61 """
62 manifest = ManifestParser()
63 manifest.read(filepath)
64 addons = manifest.get()
65
66 for addon in addons:
67 if '://' in addon['path'] or os.path.exists(addon['path']):
68 self.install_from_path(addon['path'])
69 continue
70
71 # No path specified, try to grab it off AMO
72 locale = addon.get('amo_locale', 'en_US')
73
74 query = 'https://services.addons.mozilla.org/' + locale + '/firefox/ api/' + AMO_API_VERSION + '/'
75 if 'amo_id' in addon:
76 query += 'addon/' + addon['amo_id'] # this query grabs information on the addon base on its id
77 else:
78 query += 'search/' + addon['name'] + '/default/1' # this query grabs information on the first addon returned from a search
79 install_path = AddonManager.get_amo_install_path(query)
80 self.install_from_path(install_path)
81
82 @classmethod
83 def get_amo_install_path(self, query):
84 """
85 Return the addon xpi install path for the specified AMO query.
86 See: https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_D evelopers%27_Guide/The_generic_AMO_API
87 for query documentation.
88 """
89 response = urllib2.urlopen(query)
90 dom = minidom.parseString(response.read())
91 for node in dom.getElementsByTagName('install')[0].childNodes:
92 if node.nodeType == node.TEXT_NODE:
93 return node.data
94
95 @classmethod
96 def addon_details(cls, addon_path):
97 """
98 returns a dictionary of details about the addon
99 - addon_path : path to the addon directory
100 Returns:
101 {'id': u'rainbow@colors.org', # id of the addon
102 'version': u'1.4', # version of the addon
103 'name': u'Rainbow', # name of the addon
104 'unpack': False } # whether to unpack the addon
105 """
106
107 # TODO: We don't use the unpack variable yet, but we should: bug 662683
108 details = {
109 'id': None,
110 'unpack': False,
111 'name': None,
112 'version': None
113 }
114
115 def get_namespace_id(doc, url):
116 attributes = doc.documentElement.attributes
117 namespace = ""
118 for i in range(attributes.length):
119 if attributes.item(i).value == url:
120 if ":" in attributes.item(i).name:
121 # If the namespace is not the default one remove 'xlmns: '
122 namespace = attributes.item(i).name.split(':')[1] + ":"
123 break
124 return namespace
125
126 def get_text(element):
127 """Retrieve the text value of a given node"""
128 rc = []
129 for node in element.childNodes:
130 if node.nodeType == node.TEXT_NODE:
131 rc.append(node.data)
132 return ''.join(rc).strip()
133
134 doc = minidom.parse(os.path.join(addon_path, 'install.rdf'))
135
136 # Get the namespaces abbreviations
137 em = get_namespace_id(doc, "http://www.mozilla.org/2004/em-rdf#")
138 rdf = get_namespace_id(doc, "http://www.w3.org/1999/02/22-rdf-syntax-ns# ")
139
140 description = doc.getElementsByTagName(rdf + "Description").item(0)
141 for node in description.childNodes:
142 # Remove the namespace prefix from the tag for comparison
143 entry = node.nodeName.replace(em, "")
144 if entry in details.keys():
145 details.update({ entry: get_text(node) })
146
147 # turn unpack into a true/false value
148 if isinstance(details['unpack'], basestring):
149 details['unpack'] = details['unpack'].lower() == 'true'
150
151 return details
152
153 def install_from_path(self, path, unpack=False):
154 """
155 Installs addon from a filepath, url
156 or directory of addons in the profile.
157 - path: url, path to .xpi, or directory of addons
158 - unpack: whether to unpack unless specified otherwise in the install.rd f
159 """
160
161 # if the addon is a url, download it
162 # note that this won't work with protocols urllib2 doesn't support
163 if '://' in path:
164 response = urllib2.urlopen(path)
165 fd, path = tempfile.mkstemp(suffix='.xpi')
166 os.write(fd, response.read())
167 os.close(fd)
168 tmpfile = path
169 else:
170 tmpfile = None
171
172 # if the addon is a directory, install all addons in it
173 addons = [path]
174 if not path.endswith('.xpi') and not os.path.exists(os.path.join(path, ' install.rdf')):
175 # If the path doesn't exist, then we don't really care, just return
176 if not os.path.isdir(path):
177 return
178 addons = [os.path.join(path, x) for x in os.listdir(path) if
179 os.path.isdir(os.path.join(path, x))]
180
181 # install each addon
182 for addon in addons:
183 tmpdir = None
184 xpifile = None
185 if addon.endswith('.xpi'):
186 tmpdir = tempfile.mkdtemp(suffix = '.' + os.path.split(addon)[-1 ])
187 compressed_file = zipfile.ZipFile(addon, 'r')
188 for name in compressed_file.namelist():
189 if name.endswith('/'):
190 os.makedirs(os.path.join(tmpdir, name))
191 else:
192 if not os.path.isdir(os.path.dirname(os.path.join(tmpdir , name))):
193 os.makedirs(os.path.dirname(os.path.join(tmpdir, nam e)))
194 data = compressed_file.read(name)
195 f = open(os.path.join(tmpdir, name), 'wb')
196 f.write(data)
197 f.close()
198 xpifile = addon
199 addon = tmpdir
200
201 # determine the addon id
202 addon_details = AddonManager.addon_details(addon)
203 addon_id = addon_details.get('id')
204 assert addon_id, 'The addon id could not be found: %s' % addon
205
206 # copy the addon to the profile
207 extensions_path = os.path.join(self.profile, 'extensions', 'staged')
208 addon_path = os.path.join(extensions_path, addon_id)
209 if not unpack and not addon_details['unpack'] and xpifile:
210 if not os.path.exists(extensions_path):
211 os.makedirs(extensions_path)
212 shutil.copy(xpifile, addon_path + '.xpi')
213 else:
214 dir_util.copy_tree(addon, addon_path, preserve_symlinks=1)
215 self._addon_dirs.append(addon_path)
216
217 # remove the temporary directory, if any
218 if tmpdir:
219 dir_util.remove_tree(tmpdir)
220
221 # remove temporary file, if any
222 if tmpfile:
223 os.remove(tmpfile)
224
225 def clean_addons(self):
226 """Cleans up addons in the profile."""
227 for addon in self._addon_dirs:
228 if os.path.isdir(addon):
229 dir_util.remove_tree(addon)
OLDNEW
« 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