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

Side by Side Diff: packagerGecko.py

Issue 9199007: Unified in-memory file processing between Gecko and Chrome (Closed)
Patch Set: Created Jan. 14, 2013, 11:14 a.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, hashlib, base64, 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
22 import xml.dom.minidom as minidom 21 import xml.dom.minidom as minidom
23 import buildtools.localeTools as localeTools 22 import buildtools.localeTools as localeTools
24 23
25 from packager import getDefaultFileName, readMetadata, getBuildVersion, getTempl ate 24 from packager import getDefaultFileName, readMetadata, getBuildVersion, getTempl ate, Files
26 25
27 KNOWN_APPS = { 26 KNOWN_APPS = {
28 'conkeror': '{a79fe89b-6662-4ff4-8e88-09950ad4dfde}', 27 'conkeror': '{a79fe89b-6662-4ff4-8e88-09950ad4dfde}',
29 'emusic': 'dlm@emusic.com', 28 'emusic': 'dlm@emusic.com',
30 'fennec': '{a23983c0-fd0e-11dc-95ff-0800200c9a66}', 29 'fennec': '{a23983c0-fd0e-11dc-95ff-0800200c9a66}',
31 'fennec2': '{aa3c5121-dab2-40e2-81ca-7ea25febc110}', 30 'fennec2': '{aa3c5121-dab2-40e2-81ca-7ea25febc110}',
32 'firefox': '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}', 31 'firefox': '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}',
33 'midbrowser': '{aa5ca914-c309-495d-91cf-3141bbb04115}', 32 'midbrowser': '{aa5ca914-c309-495d-91cf-3141bbb04115}',
34 'prism': 'prism@developer.mozilla.org', 33 'prism': 'prism@developer.mozilla.org',
35 'seamonkey': '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}', 34 'seamonkey': '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}',
(...skipping 12 matching lines...) Expand all
48 47
49 def getChromeSubdirs(baseDir, locales): 48 def getChromeSubdirs(baseDir, locales):
50 result = {} 49 result = {}
51 chromeDir = getChromeDir(baseDir) 50 chromeDir = getChromeDir(baseDir)
52 for subdir in ('content', 'skin'): 51 for subdir in ('content', 'skin'):
53 result[subdir] = os.path.join(chromeDir, subdir) 52 result[subdir] = os.path.join(chromeDir, subdir)
54 for locale in locales: 53 for locale in locales:
55 result['locale/%s' % locale] = os.path.join(chromeDir, 'locale', locale) 54 result['locale/%s' % locale] = os.path.join(chromeDir, 'locale', locale)
56 return result 55 return result
57 56
58 def getXPIFiles(baseDir): 57 def getPackageFiles(params):
59 for file in ('components', 'modules', 'lib', 'resources', 'defaults', 'chrome. manifest', 'icon.png', 'icon64.png'): 58 result = set(('chrome', 'components', 'modules', 'lib', 'resources', 'defaults ', 'chrome.manifest', 'icon.png', 'icon64.png',))
60 yield os.path.join(baseDir, file) 59
60 baseDir = params['baseDir']
61 for file in os.listdir(baseDir): 61 for file in os.listdir(baseDir):
62 if file.endswith('.js') or file.endswith('.xml'): 62 if file.endswith('.js') or file.endswith('.xml'):
63 yield os.path.join(baseDir, file) 63 result.add(file)
64 return result
64 65
65 def getIgnoredFiles(params): 66 def getIgnoredFiles(params):
66 result = ['.incomplete', 'meta.properties'] 67 result = set(('.incomplete', 'meta.properties',))
67 if params['releaseBuild']: 68 if params['releaseBuild']:
68 result.append('timeline.js') 69 result.add('timeline.js')
69 return result 70 return result
70 71
71 def isValidLocale(localesDir, dir, includeIncomplete=False): 72 def isValidLocale(localesDir, dir, includeIncomplete=False):
72 if re.search(r'[^\w\-]', dir): 73 if re.search(r'[^\w\-]', dir):
73 return False 74 return False
74 if not os.path.isdir(os.path.join(localesDir, dir)): 75 if not os.path.isdir(os.path.join(localesDir, dir)):
75 return False 76 return False
76 if not includeIncomplete and os.path.exists(os.path.join(localesDir, dir, '.in complete')): 77 if not includeIncomplete and os.path.exists(os.path.join(localesDir, dir, '.in complete')):
77 return False 78 return False
78 return True 79 return True
79 80
80 def getLocales(baseDir, includeIncomplete=False): 81 def getLocales(baseDir, includeIncomplete=False):
81 global defaultLocale 82 global defaultLocale
82 localesDir = getLocalesDir(baseDir) 83 localesDir = getLocalesDir(baseDir)
83 locales = filter(lambda dir: isValidLocale(localesDir, dir, includeIncomplete ), os.listdir(localesDir)) 84 locales = filter(lambda dir: isValidLocale(localesDir, dir, includeIncomplete ), os.listdir(localesDir))
84 locales.sort(key=lambda x: '!' if x == defaultLocale else x) 85 locales.sort(key=lambda x: '!' if x == defaultLocale else x)
85 return locales 86 return locales
86 87
87 def processFile(path, data, params): 88 def processFile(path, data, params):
88 if not re.search(r'\.(manifest|xul|jsm?|xml|xhtml|rdf|dtd|properties|css)$', p ath):
89 return data
90
91 data = re.sub(r'\r', '', data)
92 data = data.replace('{{VERSION}}', params['version'])
93
94 whitespaceRegExp = re.compile(r'^( )+', re.M)
95 data = re.sub(whitespaceRegExp, lambda match: '\t' * (len(match.group(0)) / 2) , data)
96
97 if path.endswith('.manifest') and data.find('{{LOCALE}}') >= 0: 89 if path.endswith('.manifest') and data.find('{{LOCALE}}') >= 0:
98 localesRegExp = re.compile(r'^(.*?){{LOCALE}}(.*?){{LOCALE}}(.*)$', re.M) 90 localesRegExp = re.compile(r'^(.*?){{LOCALE}}(.*?){{LOCALE}}(.*)$', re.M)
99 replacement = '\n'.join(map(lambda locale: r'\1%s\2%s\3' % (locale, locale), params['locales'])) 91 replacement = '\n'.join(map(lambda locale: r'\1%s\2%s\3' % (locale, locale), params['locales']))
100 data = re.sub(localesRegExp, replacement, data) 92 data = re.sub(localesRegExp, replacement, data)
101 93
102 if params['releaseBuild'] and path.endswith('.js'): 94 if params['releaseBuild'] and path.endswith('.js'):
103 # Remove timeline calls from release builds 95 # Remove timeline calls from release builds
104 timelineRegExp1 = re.compile(r'^.*\b[tT]imeLine\.(\w+)\(.*', re.M) 96 timelineRegExp1 = re.compile(r'^.*\b[tT]imeLine\.(\w+)\(.*', re.M)
105 timelineRegExp2 = re.compile(r'^.*\brequire\(\"timeline\"\).*', re.M) 97 timelineRegExp2 = re.compile(r'^.*\brequire\(\"timeline\"\).*', re.M)
106 data = re.sub(timelineRegExp1, '', data) 98 data = re.sub(timelineRegExp1, '', data)
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 main.append(value) 141 main.append(value)
150 return main + sorted(additional, key=unicode.lower) 142 return main + sorted(additional, key=unicode.lower)
151 143
152 def initTranslators(localeMetadata): 144 def initTranslators(localeMetadata):
153 for locale in localeMetadata.itervalues(): 145 for locale in localeMetadata.itervalues():
154 if 'translator' in locale: 146 if 'translator' in locale:
155 locale['translators'] = sorted(map(lambda t: t.strip(), locale['translator '].split(',')), key=unicode.lower) 147 locale['translators'] = sorted(map(lambda t: t.strip(), locale['translator '].split(',')), key=unicode.lower)
156 else: 148 else:
157 locale['translators'] = [] 149 locale['translators'] = []
158 150
159 def createManifest(baseDir, params): 151 def createManifest(params):
160 global KNOWN_APPS, defaultLocale 152 global KNOWN_APPS, defaultLocale
161 template = getTemplate('install.rdf.tmpl', autoEscape=True) 153 template = getTemplate('install.rdf.tmpl', autoEscape=True)
162 templateData = dict(params) 154 templateData = dict(params)
163 templateData['localeMetadata'] = readLocaleMetadata(baseDir, params['locales'] ) 155 templateData['localeMetadata'] = readLocaleMetadata(params['baseDir'], params[ 'locales'])
164 initTranslators(templateData['localeMetadata']) 156 initTranslators(templateData['localeMetadata'])
165 templateData['KNOWN_APPS'] = KNOWN_APPS 157 templateData['KNOWN_APPS'] = KNOWN_APPS
166 templateData['defaultLocale'] = defaultLocale 158 templateData['defaultLocale'] = defaultLocale
167 return template.render(templateData).encode('utf-8') 159 return template.render(templateData).encode('utf-8')
168 160
169 def readFile(files, params, path, name): 161 def fixupLocales(params, files):
170 ignoredFiles = getIgnoredFiles(params)
171 if os.path.isdir(path):
172 for file in os.listdir(path):
173 if file in ignoredFiles:
174 continue
175 readFile(files, params, os.path.join(path, file), '%s/%s' % (name, file))
176 else:
177 file = open(path, 'rb')
178 data = processFile(path, file.read(), params)
179 file.close()
180 files[name] = data
181
182 def fixupLocales(baseDir, files, params):
183 global defaultLocale 162 global defaultLocale
184 163
185 # Read in default locale data, it might not be included in files 164 # Read in default locale data, it might not be included in files
186 defaultLocaleDir = os.path.join(getLocalesDir(baseDir), defaultLocale) 165 defaultLocaleDir = os.path.join(getLocalesDir(params['baseDir']), defaultLocal e)
187 reference = {} 166 reference = {}
188 ignoredFiles = getIgnoredFiles(params) 167 ignoredFiles = getIgnoredFiles(params)
189 for file in os.listdir(defaultLocaleDir): 168 for file in os.listdir(defaultLocaleDir):
190 path = os.path.join(defaultLocaleDir, file) 169 path = os.path.join(defaultLocaleDir, file)
191 if file in ignoredFiles or not os.path.isfile(path): 170 if file in ignoredFiles or not os.path.isfile(path):
192 continue 171 continue
193 data = localeTools.readFile(path) 172 data = localeTools.readFile(path)
194 if data: 173 if data:
195 reference[file] = data 174 reference[file] = data
196 175
197 for locale in params['locales']: 176 for locale in params['locales']:
198 for file in reference.iterkeys(): 177 for file in reference.iterkeys():
199 path = 'chrome/locale/%s/%s' % (locale, file) 178 path = 'chrome/locale/%s/%s' % (locale, file)
200 if path in files: 179 if path in files:
201 data = localeTools.parseString(files[path].decode('utf-8'), path) 180 data = localeTools.parseString(files[path].decode('utf-8'), path)
202 for key, value in reference[file].iteritems(): 181 for key, value in reference[file].iteritems():
203 if not key in data: 182 if not key in data:
204 files[path] += localeTools.generateStringEntry(key, value, path).enc ode('utf-8') 183 files[path] += localeTools.generateStringEntry(key, value, path).enc ode('utf-8')
205 else: 184 else:
206 files[path] = reference[file]['_origData'].encode('utf-8') 185 files[path] = reference[file]['_origData'].encode('utf-8')
207 186
208 def readXPIFiles(baseDir, params, files): 187 def addMissingFiles(params, files):
209 for path in getXPIFiles(baseDir):
210 if os.path.exists(path):
211 readFile(files, params, path, os.path.basename(path))
212
213 def addMissingFiles(baseDir, params, files):
214 templateData = { 188 templateData = {
215 'hasChrome': False, 189 'hasChrome': False,
216 'hasChromeRequires': False, 190 'hasChromeRequires': False,
217 'hasShutdownHandlers': False, 191 'hasShutdownHandlers': False,
218 'hasVersionPref': False, 192 'hasVersionPref': False,
219 'chromeWindows': [], 193 'chromeWindows': [],
220 'requires': {}, 194 'requires': {},
221 'metadata': params['metadata'], 195 'metadata': params['metadata'],
222 'multicompartment': params['multicompartment'], 196 'multicompartment': params['multicompartment'],
223 'applications': dict((v, k) for k, v in KNOWN_APPS.iteritems()), 197 'applications': dict((v, k) for k, v in KNOWN_APPS.iteritems()),
(...skipping 27 matching lines...) Expand all
251 for module in templateData['requires']: 225 for module in templateData['requires']:
252 moduleFile = 'lib/' + module + '.js' 226 moduleFile = 'lib/' + module + '.js'
253 if not moduleFile in files: 227 if not moduleFile in files:
254 import buildtools 228 import buildtools
255 path = os.path.join(buildtools.__path__[0], moduleFile) 229 path = os.path.join(buildtools.__path__[0], moduleFile)
256 if os.path.exists(path): 230 if os.path.exists(path):
257 missing.append((path, moduleFile)) 231 missing.append((path, moduleFile))
258 if not len(missing): 232 if not len(missing):
259 break 233 break
260 for path, moduleFile in missing: 234 for path, moduleFile in missing:
261 readFile(files, params, path, moduleFile) 235 files.read(path, moduleFile)
262 checkScript(moduleFile) 236 checkScript(moduleFile)
263 237
264 template = getTemplate('bootstrap.js.tmpl') 238 template = getTemplate('bootstrap.js.tmpl')
265 files['bootstrap.js'] = processFile('bootstrap.js', template.render(templateDa ta).encode('utf-8'), params) 239 files['bootstrap.js'] = template.render(templateData).encode('utf-8')
266 240
267 def signFiles(files, keyFile): 241 def signFiles(files, keyFile):
268 import M2Crypto 242 import M2Crypto
269 manifest = [] 243 manifest = []
270 signature = [] 244 signature = []
271 245
272 def getDigest(data): 246 def getDigest(data):
273 md5 = hashlib.md5() 247 md5 = hashlib.md5()
274 md5.update(data) 248 md5.update(data)
275 sha1 = hashlib.sha1() 249 sha1 = hashlib.sha1()
(...skipping 30 matching lines...) Expand all
306 280
307 mime = M2Crypto.SMIME.SMIME() 281 mime = M2Crypto.SMIME.SMIME()
308 mime.load_key(keyFile) 282 mime.load_key(keyFile)
309 mime.set_x509_stack(stack) 283 mime.set_x509_stack(stack)
310 signature = mime.sign(M2Crypto.BIO.MemoryBuffer(files['META-INF/zigbert.sf'].e ncode('utf-8')), M2Crypto.SMIME.PKCS7_DETACHED | M2Crypto.SMIME.PKCS7_BINARY) 284 signature = mime.sign(M2Crypto.BIO.MemoryBuffer(files['META-INF/zigbert.sf'].e ncode('utf-8')), M2Crypto.SMIME.PKCS7_DETACHED | M2Crypto.SMIME.PKCS7_BINARY)
311 285
312 buffer = M2Crypto.BIO.MemoryBuffer() 286 buffer = M2Crypto.BIO.MemoryBuffer()
313 signature.write_der(buffer) 287 signature.write_der(buffer)
314 files['META-INF/zigbert.rsa'] = buffer.read() 288 files['META-INF/zigbert.rsa'] = buffer.read()
315 289
316 def writeXPI(files, outFile):
317 zip = ZipFile(outFile, 'w', ZIP_DEFLATED)
318 names = files.keys()
319 names.sort(key=lambda x: '!' if x == 'META-INF/zigbert.rsa' else x)
320 for name in names:
321 zip.writestr(name, files[name])
322 zip.close()
323
324 def createBuild(baseDir, outFile=None, locales=None, buildNum=None, releaseBuild =False, keyFile=None, multicompartment=False): 290 def createBuild(baseDir, outFile=None, locales=None, buildNum=None, releaseBuild =False, keyFile=None, multicompartment=False):
325 if locales == None: 291 if locales == None:
326 locales = getLocales(baseDir) 292 locales = getLocales(baseDir)
327 elif locales == 'all': 293 elif locales == 'all':
328 locales = getLocales(baseDir, True) 294 locales = getLocales(baseDir, True)
329 295
330 metadata = readMetadata(baseDir) 296 metadata = readMetadata(baseDir)
331 version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum) 297 version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum)
332 298
333 if outFile == None: 299 if outFile == None:
334 outFile = getDefaultFileName(baseDir, metadata, version, 'xpi') 300 outFile = getDefaultFileName(baseDir, metadata, version, 'xpi')
335 301
336 contributors = getContributors(baseDir, metadata) 302 contributors = getContributors(baseDir, metadata)
337 303
338 params = { 304 params = {
305 'baseDir': baseDir,
339 'locales': locales, 306 'locales': locales,
340 'releaseBuild': releaseBuild, 307 'releaseBuild': releaseBuild,
341 'version': version.encode('utf-8'), 308 'version': version.encode('utf-8'),
342 'metadata': metadata, 309 'metadata': metadata,
343 'contributors': contributors, 310 'contributors': contributors,
344 'multicompartment': multicompartment, 311 'multicompartment': multicompartment,
345 } 312 }
346 files = {} 313
347 files['install.rdf'] = createManifest(baseDir, params) 314 files = Files(getPackageFiles(params), getIgnoredFiles(params),
315 process=lambda path, data: processFile(path, data, params))
316 files['install.rdf'] = createManifest(params)
317 files.read(baseDir, skip=('chrome'))
348 for name, path in getChromeSubdirs(baseDir, params['locales']).iteritems(): 318 for name, path in getChromeSubdirs(baseDir, params['locales']).iteritems():
349 if os.path.isdir(path): 319 if os.path.isdir(path):
350 readFile(files, params, path, 'chrome/%s' % name) 320 files.read(path, 'chrome/%s' % name)
351 fixupLocales(baseDir, files, params) 321 fixupLocales(params, files)
352 readXPIFiles(baseDir, params, files)
353 if not 'bootstrap.js' in files: 322 if not 'bootstrap.js' in files:
354 addMissingFiles(baseDir, params, files) 323 addMissingFiles(params, files)
355 if keyFile: 324 if keyFile:
356 signFiles(files, keyFile) 325 signFiles(files, keyFile)
357 writeXPI(files, outFile) 326 files.zip(outFile, sortKey=lambda x: '!' if x == 'META-INF/zigbert.rsa' else x )
358 327
359 def autoInstall(baseDir, host, port, multicompartment=False): 328 def autoInstall(baseDir, host, port, multicompartment=False):
360 fileBuffer = StringIO() 329 fileBuffer = StringIO()
361 createBuild(baseDir, outFile=fileBuffer, multicompartment=multicompartment) 330 createBuild(baseDir, outFile=fileBuffer, multicompartment=multicompartment)
362 urllib.urlopen('http://%s:%s/' % (host, port), data=fileBuffer.getvalue()) 331 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