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

Side by Side Diff: packagerGecko.py

Issue 9158140: Packager refactoring, moved common packager code into separate module (Closed)
Patch Set: Created Jan. 10, 2013, 7:57 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « packagerChrome.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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())
OLDNEW
« no previous file with comments | « packagerChrome.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld