| OLD | NEW | 
|---|
| 1 # coding: utf-8 | 1 # coding: utf-8 | 
| 2 | 2 | 
| 3 # This file is part of the Adblock Plus build tools, | 3 # This file is part of the Adblock Plus build tools, | 
| 4 # Copyright (C) 2006-2012 Eyeo GmbH | 4 # Copyright (C) 2006-2012 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, sys, re, subprocess, jinja2, buildtools, codecs, hashlib, base64, shu
     til, urllib, json | 18 import os, sys, re, hashlib, base64, urllib, json | 
| 19 from ConfigParser import SafeConfigParser | 19 from ConfigParser import SafeConfigParser | 
| 20 from StringIO import StringIO | 20 from StringIO import StringIO | 
| 21 from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED | 21 from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED | 
| 22 import xml.dom.minidom as minidom | 22 import xml.dom.minidom as minidom | 
| 23 import buildtools.localeTools as localeTools | 23 import buildtools.localeTools as localeTools | 
| 24 | 24 | 
|  | 25 from packager import getDefaultFileName, readMetadata, getBuildVersion, getTempl
     ate | 
|  | 26 | 
| 25 KNOWN_APPS = { | 27 KNOWN_APPS = { | 
| 26   'conkeror':   '{a79fe89b-6662-4ff4-8e88-09950ad4dfde}', | 28   'conkeror':   '{a79fe89b-6662-4ff4-8e88-09950ad4dfde}', | 
| 27   'emusic':     'dlm@emusic.com', | 29   'emusic':     'dlm@emusic.com', | 
| 28   'fennec':     '{a23983c0-fd0e-11dc-95ff-0800200c9a66}', | 30   'fennec':     '{a23983c0-fd0e-11dc-95ff-0800200c9a66}', | 
| 29   'fennec2':    '{aa3c5121-dab2-40e2-81ca-7ea25febc110}', | 31   'fennec2':    '{aa3c5121-dab2-40e2-81ca-7ea25febc110}', | 
| 30   'firefox':    '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}', | 32   'firefox':    '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}', | 
| 31   'midbrowser': '{aa5ca914-c309-495d-91cf-3141bbb04115}', | 33   'midbrowser': '{aa5ca914-c309-495d-91cf-3141bbb04115}', | 
| 32   'prism':      'prism@developer.mozilla.org', | 34   'prism':      'prism@developer.mozilla.org', | 
| 33   'seamonkey':  '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}', | 35   'seamonkey':  '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}', | 
| 34   'songbird':   'songbird@songbirdnest.com', | 36   'songbird':   'songbird@songbirdnest.com', | 
| 35   'thunderbird':  '{3550f703-e582-4d05-9a08-453d09bdfdc6}', | 37   'thunderbird':  '{3550f703-e582-4d05-9a08-453d09bdfdc6}', | 
| 36   'toolkit':    'toolkit@mozilla.org', | 38   'toolkit':    'toolkit@mozilla.org', | 
| 37 } | 39 } | 
| 38 | 40 | 
| 39 defaultLocale = 'en-US' | 41 defaultLocale = 'en-US' | 
| 40 | 42 | 
| 41 def getDefaultFileName(baseDir, metadata, version, ext='xpi'): |  | 
| 42   return os.path.join(baseDir, '%s-%s.%s' % (metadata.get('general', 'basename')
     , version, ext)) |  | 
| 43 |  | 
| 44 def getMetadataPath(baseDir): |  | 
| 45   return os.path.join(baseDir, 'metadata') |  | 
| 46 |  | 
| 47 def getChromeDir(baseDir): | 43 def getChromeDir(baseDir): | 
| 48   return os.path.join(baseDir, 'chrome') | 44   return os.path.join(baseDir, 'chrome') | 
| 49 | 45 | 
| 50 def getLocalesDir(baseDir): | 46 def getLocalesDir(baseDir): | 
| 51   return os.path.join(getChromeDir(baseDir), 'locale') | 47   return os.path.join(getChromeDir(baseDir), 'locale') | 
| 52 | 48 | 
| 53 def getChromeSubdirs(baseDir, locales): | 49 def getChromeSubdirs(baseDir, locales): | 
| 54   result = {} | 50   result = {} | 
| 55   chromeDir = getChromeDir(baseDir) | 51   chromeDir = getChromeDir(baseDir) | 
| 56   for subdir in ('content', 'skin'): | 52   for subdir in ('content', 'skin'): | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 83     return False | 79     return False | 
| 84   return True | 80   return True | 
| 85 | 81 | 
| 86 def getLocales(baseDir, includeIncomplete=False): | 82 def getLocales(baseDir, includeIncomplete=False): | 
| 87   global defaultLocale | 83   global defaultLocale | 
| 88   localesDir = getLocalesDir(baseDir) | 84   localesDir = getLocalesDir(baseDir) | 
| 89   locales = filter(lambda dir:  isValidLocale(localesDir, dir, includeIncomplete
     ), os.listdir(localesDir)) | 85   locales = filter(lambda dir:  isValidLocale(localesDir, dir, includeIncomplete
     ), os.listdir(localesDir)) | 
| 90   locales.sort(key=lambda x: '!' if x == defaultLocale else x) | 86   locales.sort(key=lambda x: '!' if x == defaultLocale else x) | 
| 91   return locales | 87   return locales | 
| 92 | 88 | 
| 93 def getBuildNum(baseDir): |  | 
| 94   try: |  | 
| 95     (result, dummy) = subprocess.Popen(['hg', 'id', '-n'], stdout=subprocess.PIP
     E).communicate() |  | 
| 96     return re.sub(r'\W', '', result) |  | 
| 97   except Exception: |  | 
| 98     return '0' |  | 
| 99 |  | 
| 100 def readMetadata(baseDir): |  | 
| 101   metadata = SafeConfigParser() |  | 
| 102   metadata.optionxform = str |  | 
| 103   file = codecs.open(getMetadataPath(baseDir), 'rb', encoding='utf-8') |  | 
| 104   metadata.readfp(file) |  | 
| 105   file.close() |  | 
| 106   return metadata |  | 
| 107 |  | 
| 108 def processFile(path, data, params): | 89 def processFile(path, data, params): | 
| 109   if not re.search(r'\.(manifest|xul|jsm?|xml|xhtml|rdf|dtd|properties|css)$', p
     ath): | 90   if not re.search(r'\.(manifest|xul|jsm?|xml|xhtml|rdf|dtd|properties|css)$', p
     ath): | 
| 110     return data | 91     return data | 
| 111 | 92 | 
| 112   data = re.sub(r'\r', '', data) | 93   data = re.sub(r'\r', '', data) | 
| 113   data = data.replace('{{BUILD}}', params['buildNum']) |  | 
| 114   data = data.replace('{{VERSION}}', params['version']) | 94   data = data.replace('{{VERSION}}', params['version']) | 
| 115 | 95 | 
| 116   whitespaceRegExp = re.compile(r'^(  )+', re.M) | 96   whitespaceRegExp = re.compile(r'^(  )+', re.M) | 
| 117   data = re.sub(whitespaceRegExp, lambda match: '\t' * (len(match.group(0)) / 2)
     , data) | 97   data = re.sub(whitespaceRegExp, lambda match: '\t' * (len(match.group(0)) / 2)
     , data) | 
| 118 | 98 | 
| 119   if path.endswith('.manifest') and data.find('{{LOCALE}}') >= 0: | 99   if path.endswith('.manifest') and data.find('{{LOCALE}}') >= 0: | 
| 120     localesRegExp = re.compile(r'^(.*?){{LOCALE}}(.*?){{LOCALE}}(.*)$', re.M) | 100     localesRegExp = re.compile(r'^(.*?){{LOCALE}}(.*?){{LOCALE}}(.*)$', re.M) | 
| 121     replacement = '\n'.join(map(lambda locale: r'\1%s\2%s\3' % (locale, locale),
      params['locales'])) | 101     replacement = '\n'.join(map(lambda locale: r'\1%s\2%s\3' % (locale, locale),
      params['locales'])) | 
| 122     data = re.sub(localesRegExp, replacement, data) | 102     data = re.sub(localesRegExp, replacement, data) | 
| 123 | 103 | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 173 | 153 | 
| 174 def initTranslators(localeMetadata): | 154 def initTranslators(localeMetadata): | 
| 175   for locale in localeMetadata.itervalues(): | 155   for locale in localeMetadata.itervalues(): | 
| 176     if 'translator' in locale: | 156     if 'translator' in locale: | 
| 177       locale['translators'] = sorted(map(lambda t: t.strip(), locale['translator
     '].split(',')), key=unicode.lower) | 157       locale['translators'] = sorted(map(lambda t: t.strip(), locale['translator
     '].split(',')), key=unicode.lower) | 
| 178     else: | 158     else: | 
| 179       locale['translators'] = [] | 159       locale['translators'] = [] | 
| 180 | 160 | 
| 181 def createManifest(baseDir, params): | 161 def createManifest(baseDir, params): | 
| 182   global KNOWN_APPS, defaultLocale | 162   global KNOWN_APPS, defaultLocale | 
| 183   env = jinja2.Environment(loader=jinja2.FileSystemLoader(buildtools.__path__[0]
     ), autoescape=True, extensions=['jinja2.ext.autoescape']) | 163   template = getTemplate('install.rdf.tmpl', autoEscape=True) | 
| 184   template = env.get_template('install.rdf.tmpl') |  | 
| 185   templateData = dict(params) | 164   templateData = dict(params) | 
| 186   templateData['localeMetadata'] = readLocaleMetadata(baseDir, params['locales']
     ) | 165   templateData['localeMetadata'] = readLocaleMetadata(baseDir, params['locales']
     ) | 
| 187   initTranslators(templateData['localeMetadata']) | 166   initTranslators(templateData['localeMetadata']) | 
| 188   templateData['KNOWN_APPS'] = KNOWN_APPS | 167   templateData['KNOWN_APPS'] = KNOWN_APPS | 
| 189   templateData['defaultLocale'] = defaultLocale | 168   templateData['defaultLocale'] = defaultLocale | 
| 190   return template.render(templateData).encode('utf-8') | 169   return template.render(templateData).encode('utf-8') | 
| 191 | 170 | 
| 192 def readFile(files, params, path, name): | 171 def readFile(files, params, path, name): | 
| 193   ignoredFiles = getIgnoredFiles(params) | 172   ignoredFiles = getIgnoredFiles(params) | 
| 194   if os.path.isdir(path): | 173   if os.path.isdir(path): | 
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 267     elif name.endswith('.xul'): | 246     elif name.endswith('.xul'): | 
| 268       match = re.search(r'<(?:window|dialog)\s[^>]*\bwindowtype="([^">]+)"', con
     tent) | 247       match = re.search(r'<(?:window|dialog)\s[^>]*\bwindowtype="([^">]+)"', con
     tent) | 
| 269       if match: | 248       if match: | 
| 270         templateData['chromeWindows'].append(match.group(1)) | 249         templateData['chromeWindows'].append(match.group(1)) | 
| 271 | 250 | 
| 272   while True: | 251   while True: | 
| 273     missing = [] | 252     missing = [] | 
| 274     for module in templateData['requires']: | 253     for module in templateData['requires']: | 
| 275       moduleFile = 'lib/' + module + '.js' | 254       moduleFile = 'lib/' + module + '.js' | 
| 276       if not moduleFile in files: | 255       if not moduleFile in files: | 
|  | 256         import buildtools | 
| 277         path = os.path.join(buildtools.__path__[0], moduleFile) | 257         path = os.path.join(buildtools.__path__[0], moduleFile) | 
| 278         if os.path.exists(path): | 258         if os.path.exists(path): | 
| 279           missing.append((path, moduleFile)) | 259           missing.append((path, moduleFile)) | 
| 280     if not len(missing): | 260     if not len(missing): | 
| 281       break | 261       break | 
| 282     for path, moduleFile in missing: | 262     for path, moduleFile in missing: | 
| 283       readFile(files, params, path, moduleFile) | 263       readFile(files, params, path, moduleFile) | 
| 284       checkScript(moduleFile) | 264       checkScript(moduleFile) | 
| 285 | 265 | 
| 286   env = jinja2.Environment(loader=jinja2.FileSystemLoader(buildtools.__path__[0]
     )) | 266   template = getTemplate('bootstrap.js.tmpl') | 
| 287   env.filters['json'] = json.dumps |  | 
| 288   template = env.get_template('bootstrap.js.tmpl') |  | 
| 289   files['bootstrap.js'] = processFile('bootstrap.js', template.render(templateDa
     ta).encode('utf-8'), params) | 267   files['bootstrap.js'] = processFile('bootstrap.js', template.render(templateDa
     ta).encode('utf-8'), params) | 
| 290 | 268 | 
| 291 def signFiles(files, keyFile): | 269 def signFiles(files, keyFile): | 
| 292   import M2Crypto | 270   import M2Crypto | 
| 293   manifest = [] | 271   manifest = [] | 
| 294   signature = [] | 272   signature = [] | 
| 295 | 273 | 
| 296   def getDigest(data): | 274   def getDigest(data): | 
| 297     md5 = hashlib.md5() | 275     md5 = hashlib.md5() | 
| 298     md5.update(data) | 276     md5.update(data) | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 339 | 317 | 
| 340 def writeXPI(files, outFile): | 318 def writeXPI(files, outFile): | 
| 341   zip = ZipFile(outFile, 'w', ZIP_DEFLATED) | 319   zip = ZipFile(outFile, 'w', ZIP_DEFLATED) | 
| 342   names = files.keys() | 320   names = files.keys() | 
| 343   names.sort(key=lambda x: '!' if x == 'META-INF/zigbert.rsa' else x) | 321   names.sort(key=lambda x: '!' if x == 'META-INF/zigbert.rsa' else x) | 
| 344   for name in names: | 322   for name in names: | 
| 345     zip.writestr(name, files[name]) | 323     zip.writestr(name, files[name]) | 
| 346   zip.close() | 324   zip.close() | 
| 347 | 325 | 
| 348 def createBuild(baseDir, outFile=None, locales=None, buildNum=None, releaseBuild
     =False, keyFile=None, limitMetadata=False, multicompartment=False): | 326 def createBuild(baseDir, outFile=None, locales=None, buildNum=None, releaseBuild
     =False, keyFile=None, limitMetadata=False, multicompartment=False): | 
| 349   if buildNum == None: |  | 
| 350     buildNum = getBuildNum(baseDir) |  | 
| 351   if locales == None: | 327   if locales == None: | 
| 352     locales = getLocales(baseDir) | 328     locales = getLocales(baseDir) | 
| 353   elif locales == 'all': | 329   elif locales == 'all': | 
| 354     locales = getLocales(baseDir, True) | 330     locales = getLocales(baseDir, True) | 
| 355 | 331 | 
| 356   metadata = readMetadata(baseDir) | 332   metadata = readMetadata(baseDir) | 
| 357   version = metadata.get('general', 'version') | 333   version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum) | 
| 358   if not releaseBuild: |  | 
| 359     version += '.' + buildNum |  | 
| 360 | 334 | 
| 361   if limitMetadata: | 335   if limitMetadata: | 
| 362     for option in metadata.options('compat'): | 336     for option in metadata.options('compat'): | 
| 363       if not option in ('firefox', 'thunderbird', 'seamonkey'): | 337       if not option in ('firefox', 'thunderbird', 'seamonkey'): | 
| 364         metadata.remove_option('compat', option) | 338         metadata.remove_option('compat', option) | 
| 365 | 339 | 
| 366   if outFile == None: | 340   if outFile == None: | 
| 367     outFile = getDefaultFileName(baseDir, metadata, version) | 341     outFile = getDefaultFileName(baseDir, metadata, version, 'xpi') | 
| 368 | 342 | 
| 369   contributors = getContributors(baseDir, metadata) | 343   contributors = getContributors(baseDir, metadata) | 
| 370 | 344 | 
| 371   params = { | 345   params = { | 
| 372     'locales': locales, | 346     'locales': locales, | 
| 373     'releaseBuild': releaseBuild, | 347     'releaseBuild': releaseBuild, | 
| 374     'buildNum': buildNum, |  | 
| 375     'version': version.encode('utf-8'), | 348     'version': version.encode('utf-8'), | 
| 376     'metadata': metadata, | 349     'metadata': metadata, | 
| 377     'limitMetadata': limitMetadata, | 350     'limitMetadata': limitMetadata, | 
| 378     'contributors': contributors, | 351     'contributors': contributors, | 
| 379     'multicompartment': multicompartment, | 352     'multicompartment': multicompartment, | 
| 380   } | 353   } | 
| 381   files = {} | 354   files = {} | 
| 382   files['install.rdf'] = createManifest(baseDir, params) | 355   files['install.rdf'] = createManifest(baseDir, params) | 
| 383   for name, path in getChromeSubdirs(baseDir, params['locales']).iteritems(): | 356   for name, path in getChromeSubdirs(baseDir, params['locales']).iteritems(): | 
| 384     if os.path.isdir(path): | 357     if os.path.isdir(path): | 
| 385       readFile(files, params, path, 'chrome/%s' % name) | 358       readFile(files, params, path, 'chrome/%s' % name) | 
| 386   if not params['limitMetadata']: | 359   if not params['limitMetadata']: | 
| 387     fixupLocales(baseDir, files, params) | 360     fixupLocales(baseDir, files, params) | 
| 388   readXPIFiles(baseDir, params, files) | 361   readXPIFiles(baseDir, params, files) | 
| 389   if not 'bootstrap.js' in files: | 362   if not 'bootstrap.js' in files: | 
| 390     addMissingFiles(baseDir, params, files) | 363     addMissingFiles(baseDir, params, files) | 
| 391   if keyFile: | 364   if keyFile: | 
| 392     signFiles(files, keyFile) | 365     signFiles(files, keyFile) | 
| 393   writeXPI(files, outFile) | 366   writeXPI(files, outFile) | 
| 394 | 367 | 
| 395 def autoInstall(baseDir, host, port, multicompartment=False): | 368 def autoInstall(baseDir, host, port, multicompartment=False): | 
| 396   fileBuffer = StringIO() | 369   fileBuffer = StringIO() | 
| 397   createBuild(baseDir, outFile=fileBuffer, multicompartment=multicompartment) | 370   createBuild(baseDir, outFile=fileBuffer, multicompartment=multicompartment) | 
| 398   urllib.urlopen('http://%s:%s/' % (host, port), data=fileBuffer.getvalue()) | 371   urllib.urlopen('http://%s:%s/' % (host, port), data=fileBuffer.getvalue()) | 
| OLD | NEW | 
|---|