Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: sitescripts/extensions/utils.py

Issue 6291923287408640: Issue 1093 - Separate update manifest generation (Closed)
Left Patch Set: Created July 22, 2014, 8:03 a.m.
Right Patch Set: Fix issue Created July 23, 2014, 4:50 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « sitescripts/extensions/bin/updateUpdateManifests.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # coding: utf-8 1 # coding: utf-8
2 2
3 # This file is part of the Adblock Plus web scripts, 3 # This file is part of the Adblock Plus web scripts,
4 # Copyright (C) 2006-2014 Eyeo GmbH 4 # Copyright (C) 2006-2014 Eyeo GmbH
5 # 5 #
6 # Adblock Plus is free software: you can redistribute it and/or modify 6 # Adblock Plus is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3 as 7 # it under the terms of the GNU General Public License version 3 as
8 # published by the Free Software Foundation. 8 # published by the Free Software Foundation.
9 # 9 #
10 # Adblock Plus is distributed in the hope that it will be useful, 10 # Adblock Plus is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details. 13 # GNU General Public License for more details.
14 # 14 #
15 # You should have received a copy of the GNU General Public License 15 # You should have received a copy of the GNU General Public License
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
17 17
18 import os
18 import re 19 import re
19 import os
20 import subprocess 20 import subprocess
21 import time
21 import urlparse 22 import urlparse
23 import urllib
24 import urllib2
25 import xml.dom.minidom as dom
22 from ConfigParser import SafeConfigParser, NoOptionError 26 from ConfigParser import SafeConfigParser, NoOptionError
23 from StringIO import StringIO 27 from StringIO import StringIO
24 from sitescripts.utils import get_config 28 from sitescripts.utils import get_config
25 from sitescripts.extensions.android import get_min_sdk_version
26 from buildtools.packagerGecko import KNOWN_APPS
27 29
28 def compareVersionParts(part1, part2): 30 def compareVersionParts(part1, part2):
29 def convertInt(value, default): 31 def convertInt(value, default):
30 try: 32 try:
31 return int(value) 33 return int(value)
32 except ValueError: 34 except ValueError:
33 return default 35 return default
34 36
35 def convertVersionPart(part): 37 def convertVersionPart(part):
36 if part == '*': 38 if part == '*':
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 raise Exception('No safari developer certificate found in chain') 255 raise Exception('No safari developer certificate found in chain')
254 256
255 subject = cert.get_subject() 257 subject = cert.get_subject()
256 for entry in subject.get_entries_by_nid(subject.nid['CN']): 258 for entry in subject.get_entries_by_nid(subject.nid['CN']):
257 m = re.match(r'Safari Developer: \((.*?)\)', entry.get_data().as_text()) 259 m = re.match(r'Safari Developer: \((.*?)\)', entry.get_data().as_text())
258 if m: 260 if m:
259 return m.group(1) 261 return m.group(1)
260 finally: 262 finally:
261 bio.close() 263 bio.close()
262 264
265 def _urlencode(value):
266 return urllib.quote(value.encode('utf-8'), '')
267
268 def _urlopen(url, attempts=3):
269 """
270 Tries to open a particular URL, retries on failure.
271 """
272 for i in range(attempts):
273 try:
274 return urllib.urlopen(url)
275 except IOError, e:
276 error = e
277 time.sleep(5)
278 raise error
279
280 def _getMozillaDownloadLink(galleryID):
281 """
282 gets download link for a Gecko add-on from the Mozilla Addons site
283 """
284 url = 'https://services.addons.mozilla.org/en-US/firefox/api/1/addon/%s' % _ur lencode(galleryID)
285 document = dom.parse(_urlopen(url))
286 linkTags = document.getElementsByTagName('install')
287 linkTag = linkTags[0] if len(linkTags) > 0 else None
288 versionTags = document.getElementsByTagName('version')
289 versionTag = versionTags[0] if len(versionTags) > 0 else None
290 if linkTag and versionTag and linkTag.firstChild and versionTag.firstChild:
291 return (linkTag.firstChild.data, versionTag.firstChild.data)
292 else:
293 return (None, None)
294
295 def _getGoogleDownloadLink(galleryID):
296 """
297 gets download link for a Chrome add-on from the Chrome Gallery site
298 """
299 galleryID = _urlencode(galleryID)
300
301 url = 'https://clients2.google.com/service/update2/crx?x=%s' % _urlencode('id= %s&uc' % galleryID)
302 document = dom.parse(_urlopen(url))
303 updateTags = document.getElementsByTagName('updatecheck')
304 version = updateTags and updateTags[0].getAttribute('version')
305
306 if not version:
307 return (None, None)
308
309 request = urllib2.Request('https://chrome.google.com/webstore/detail/_/' + gal leryID)
310 request.get_method = lambda : 'HEAD'
311 url = urllib2.urlopen(request).geturl()
312
313 return (url, version)
314
315 def _getOperaDownloadLink(galleryID):
316 """
317 gets download link for an Opera add-on from the Opera Addons site
318 """
319 galleryID = _urlencode(galleryID)
320
321 request = urllib2.Request('https://addons.opera.com/extensions/download/%s/' % galleryID)
322 request.get_method = lambda : 'HEAD'
323 response = urllib2.urlopen(request)
324
325 content_disposition = response.info().getheader('Content-Disposition')
326 if content_disposition:
327 match = re.search(r'filename=\S+-([\d.]+)-\d+\.crx$', content_disposition)
328 if match:
329 return ('https://addons.opera.com/extensions/details/%s/' % galleryID , ma tch.group(1))
330
331 return (None, None)
332
263 def _getLocalLink(repo): 333 def _getLocalLink(repo):
Felix Dahlke 2014/07/22 08:11:11 These functions have just been moved. The only cha
264 """ 334 """
265 gets the link for the newest download of an add-on in the local downloads 335 gets the link for the newest download of an add-on in the local downloads
266 repository 336 repository
267 """ 337 """
268 highestURL = None 338 highestURL = None
269 highestVersion = None 339 highestVersion = None
270 340
271 for filename, version in repo.getDownloads(): 341 for filename, version in repo.getDownloads():
272 if not highestVersion or compareVersions(version, highestVersion) > 0: 342 if not highestVersion or compareVersions(version, highestVersion) > 0:
273 highestURL = urlparse.urljoin(repo.downloadsURL, filename) 343 highestURL = urlparse.urljoin(repo.downloadsURL, filename)
274 highestVersion = version 344 highestVersion = version
275 345
276 return (highestURL, highestVersion) 346 return (highestURL, highestVersion)
277 347
278 def _getDownloadLink(repo): 348 def _getDownloadLink(repo):
279 """ 349 """
280 gets the download link to the most current version of an extension 350 gets the download link to the most current version of an extension
281 """ 351 """
282 # you can't easily install extensions from third-party sources on Chrome 352 # you can't easily install extensions from third-party sources on Chrome
283 # and Opera. So always get the link for the version on the Web Store. 353 # and Opera. So always get the link for the version on the Web Store.
284 if repo.galleryID: 354 if repo.galleryID:
285 if repo.type == "chrome": 355 if repo.type == "chrome":
286 return getGoogleDownloadLink(repo.galleryID) 356 return _getGoogleDownloadLink(repo.galleryID)
287 if repo.type == "opera": 357 if repo.type == "opera":
288 return getOperaDownloadLink(repo.galleryID) 358 return _getOperaDownloadLink(repo.galleryID)
289 359
290 (localURL, localVersion) = _getLocalLink(repo) 360 (localURL, localVersion) = _getLocalLink(repo)
291 361
292 # get a link to Firefox Add-Ons, if the latest version has been published ther e 362 # get a link to Firefox Add-Ons, if the latest version has been published ther e
293 if repo.type == 'gecko' and repo.galleryID: 363 if repo.type == 'gecko' and repo.galleryID:
294 (galleryURL, galleryVersion) = getMozillaDownloadLink(repo.galleryID) 364 (galleryURL, galleryVersion) = _getMozillaDownloadLink(repo.galleryID)
295 if not localVersion or (galleryVersion and 365 if not localVersion or (galleryVersion and
296 compareVersions(galleryVersion, localVersion) >= 0): 366 compareVersions(galleryVersion, localVersion) >= 0):
297 return (galleryURL, galleryVersion) 367 return (galleryURL, galleryVersion)
298 368
299 return (localURL, localVersion) 369 return (localURL, localVersion)
300 370
301 def _getQRCode(text): 371 def _getQRCode(text):
302 try: 372 try:
303 import qrcode 373 import qrcode
304 import base64 374 import base64
(...skipping 15 matching lines...) Expand all
320 if downloadURL == None: 390 if downloadURL == None:
321 continue 391 continue
322 if not result.has_section(repo.repositoryName): 392 if not result.has_section(repo.repositoryName):
323 result.add_section(repo.repositoryName) 393 result.add_section(repo.repositoryName)
324 result.set(repo.repositoryName, "downloadURL", downloadURL) 394 result.set(repo.repositoryName, "downloadURL", downloadURL)
325 result.set(repo.repositoryName, "version", version) 395 result.set(repo.repositoryName, "version", version)
326 396
327 qrcode = _getQRCode(downloadURL) 397 qrcode = _getQRCode(downloadURL)
328 if qrcode != None: 398 if qrcode != None:
329 result.set(repo.repositoryName, "qrcode", qrcode) 399 result.set(repo.repositoryName, "qrcode", qrcode)
330
331 def readMetadata(repo, version):
332 """
333 reads extension ID and compatibility information from metadata file in the
334 extension's repository
335 """
336 if repo.type == 'android':
337 command = ['hg', '-R', repo.repository, 'id', '-r', version, '-n']
338 result = subprocess.check_output(command)
339 revision = re.sub(r'\D', '', result)
340
341 return {
342 'revision': revision,
343 'minSdkVersion': get_min_sdk_version(repo, version),
344 }
345 elif repo.type == 'safari':
346 metadata = repo.readMetadata(version)
347 return {
348 'certificateID': getSafariCertificateID(repo.keyFile),
349 'version': version,
350 'shortVersion': version,
351 'basename': metadata.get('general', 'basename'),
352 }
353 elif repo.type == 'gecko':
354 metadata = repo.readMetadata(version)
355 result = {
356 'extensionID': metadata.get('general', 'id'),
357 'version': version,
358 'compat': []
359 }
360 for key, value in KNOWN_APPS.iteritems():
361 if metadata.has_option('compat', key):
362 minVersion, maxVersion = metadata.get('compat', key).split('/')
363 result['compat'].append({'id': value, 'minVersion': minVersion, 'maxVers ion': maxVersion})
364 return result
365 else:
366 raise Exception('unknown repository type %r' % repo.type)
LEFTRIGHT

Powered by Google App Engine
This is Rietveld