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

Delta Between Two Patch Sets: packagerChrome.py

Issue 29561557: Issue 5763 - Target languages supported by Firefox (Closed)
Left Patch Set: Created Oct. 1, 2017, 5:12 p.m.
Right Patch Set: Fixed undefined variable, put URLS in globals, removed redundand flake8 ignores Created Oct. 5, 2017, 8:54 p.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 | « localeTools.py ('k') | tox.ini » ('j') | tox.ini » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This Source Code Form is subject to the terms of the Mozilla Public 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 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 4
5 import errno 5 import errno
6 import io 6 import io
7 import json 7 import json
8 import os 8 import os
9 import re 9 import re
10 from StringIO import StringIO 10 from StringIO import StringIO
11 import struct 11 import struct
12 import sys 12 import sys
13 import collections 13 import collections
14 import glob
14 15
15 from packager import (readMetadata, getDefaultFileName, getBuildVersion, 16 from packager import (readMetadata, getDefaultFileName, getBuildVersion,
16 getTemplate, Files) 17 getTemplate, Files)
17 18
18 defaultLocale = 'en_US' 19 defaultLocale = 'en_US'
19 20
20 21
21 def getIgnoredFiles(params): 22 def getIgnoredFiles(params):
22 return {'store.description'} 23 return {'store.description'}
23 24
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 value = match.group(1) 207 value = match.group(1)
207 else: 208 else:
208 index = value.find('&') 209 index = value.find('&')
209 if index >= 0: 210 if index >= 0:
210 value = value[0:index] + value[index + 1:] 211 value = value[0:index] + value[index + 1:]
211 212
212 data[key] = {'message': value} 213 data[key] = {'message': value}
213 214
214 215
215 def import_locales(params, files): 216 def import_locales(params, files):
216 import localeTools 217 for item in params['metadata'].items('import_locales'):
217 218 filename, keys = item
218 # FIXME: localeTools doesn't use real Chrome locales, it uses dash as 219 for sourceFile in glob.glob(os.path.join(os.path.dirname(item.source),
219 # separator instead. 220 *filename.split('/'))):
220 convert_locale_code = lambda code: code.replace('-', '_') 221 parts = sourceFile.split(os.path.sep)
Sebastian Noack 2017/10/05 20:58:38 I just noticed that the variable "parts" is used b
tlucas 2017/10/06 08:53:53 Acknowledged.
221 222 locale = parts[-2].replace('-', '_')
222 # We need to map Chrome locales to Gecko locales. Start by mapping Chrome 223 targetFile = os.path.join('_locales', locale, 'messages.json')
223 # locales to themselves, merely with the dash as separator. 224 data = json.loads(files.get(targetFile, '{}').decode('utf-8'))
224 locale_mapping = {convert_locale_code(l): l for l in localeTools.chromeLocal es}
225
226 # Convert values to Crowdin locales first (use Chrome => Crowdin mapping).
227 for chrome_locale, crowdin_locale in localeTools.langMappingChrome.iteritems ():
228 locale_mapping[convert_locale_code(chrome_locale)] = crowdin_locale
229
230 # Now convert values to Gecko locales (use Gecko => Crowdin mapping).
231 reverse_mapping = {v: k for k, v in locale_mapping.iteritems()}
232 for gecko_locale, crowdin_locale in localeTools.langMappingGecko.iteritems() :
233 if crowdin_locale in reverse_mapping:
234 locale_mapping[reverse_mapping[crowdin_locale]] = gecko_locale
235
236 for target, source in locale_mapping.iteritems():
237 targetFile = '_locales/%s/messages.json' % target
238 if not targetFile in files:
239 continue
240
241 for item in params['metadata'].items('import_locales'):
242 fileName, keys = item
243 parts = map(lambda n: source if n == '*' else n, fileName.split('/') )
244 sourceFile = os.path.join(os.path.dirname(item.source), *parts)
245 incompleteMarker = os.path.join(os.path.dirname(sourceFile), '.incom plete')
246 if not os.path.exists(sourceFile) or os.path.exists(incompleteMarker ):
247 continue
248
249 data = json.loads(files[targetFile].decode('utf-8'))
250 225
251 try: 226 try:
252 # The WebExtensions (.json) and Gecko format provide 227 # The WebExtensions (.json) and Gecko format provide
253 # translations differently and/or provide additional 228 # translations differently and/or provide additional
254 # information like e.g. "placeholders". We want to adhere to 229 # information like e.g. "placeholders". We want to adhere to
255 # that and preserve the addtional info. 230 # that and preserve the addtional info.
256 if sourceFile.endswith('.json'): 231 if sourceFile.endswith('.json'):
257 with io.open(sourceFile, 'r', encoding='utf-8') as handle: 232 with io.open(sourceFile, 'r', encoding='utf-8') as handle:
258 sourceData = json.load(handle) 233 sourceData = json.load(handle)
259 import_string = import_string_webext 234 import_string = import_string_webext
260 else: 235 else:
236 import localeTools
261 sourceData = localeTools.readFile(sourceFile) 237 sourceData = localeTools.readFile(sourceFile)
262 import_string = import_string_gecko 238 import_string = import_string_gecko
263 239
264 # Resolve wildcard imports 240 # Resolve wildcard imports
265 if keys == '*' or keys == '=*': 241 if keys == '*' or keys == '=*':
266 importList = sourceData.keys() 242 importList = sourceData.keys()
267 importList = filter(lambda k: not k.startswith('_'), importL ist) 243 importList = filter(lambda k: not k.startswith('_'), importL ist)
268 if keys == '=*': 244 if keys == '=*':
269 importList = map(lambda k: '=' + k, importList) 245 importList = map(lambda k: '=' + k, importList)
270 keys = ' '.join(importList) 246 keys = ' '.join(importList)
(...skipping 18 matching lines...) Expand all
289 265
290 files[targetFile] = toJson(data) 266 files[targetFile] = toJson(data)
291 267
292 268
293 def truncate(text, length_limit): 269 def truncate(text, length_limit):
294 if len(text) <= length_limit: 270 if len(text) <= length_limit:
295 return text 271 return text
296 return text[:length_limit - 1].rstrip() + u'\u2026' 272 return text[:length_limit - 1].rstrip() + u'\u2026'
297 273
298 274
299 def fixTranslationsForChrome(files): 275 def fix_translations_for_chrome(files):
tlucas 2017/10/02 09:25:43 nit: when changing a function's name the new name
Sebastian Noack 2017/10/02 23:01:33 Done.
300 defaults = {} 276 defaults = {}
301 data = json.loads(files['_locales/%s/messages.json' % defaultLocale]) 277 data = json.loads(files['_locales/%s/messages.json' % defaultLocale])
302 for match in re.finditer(r'__MSG_(\S+)__', files['manifest.json']): 278 for match in re.finditer(r'__MSG_(\S+)__', files['manifest.json']):
303 name = match.group(1) 279 name = match.group(1)
304 defaults[name] = data[name] 280 defaults[name] = data[name]
305 281
306 limits = {} 282 limits = {}
307 manifest = json.loads(files['manifest.json']) 283 manifest = json.loads(files['manifest.json'])
308 for key, limit in (('name', 45), ('description', 132), ('short_name', 12)): 284 for key, limit in (('name', 45), ('description', 132), ('short_name', 12)):
309 match = re.search(r'__MSG_(\S+)__', manifest.get(key, '')) 285 match = re.search(r'__MSG_(\S+)__', manifest.get(key, ''))
310 if match: 286 if match:
311 limits[match.group(1)] = limit 287 limits[match.group(1)] = limit
312 288
313 for path in list(files): 289 for path in list(files):
314 match = re.search(r'^_locales/(?:es_(AR|CL|(MX))|[^/]+)/(.*)', path) 290 match = re.search(r'^_locales/(?:es_(AR|CL|(MX))|[^/]+)/(.*)', path)
315 if match: 291 if not match:
Vasily Kuznetsov 2017/10/02 21:13:32 This loop with a regexp search and then `if match`
Sebastian Noack 2017/10/02 23:01:33 The reason why I didn't bail out, but went for the
316 isLatAm, isMexican, filename = match.groups() 292 continue
Vasily Kuznetsov 2017/10/02 21:13:32 While PEP8 is annoyingly non-specific with regards
Sebastian Noack 2017/10/02 23:01:33 Yeah, this should be lowercase with underscores. D
317 293
318 # The Chrome Web Store requires messages used in manifest.json to be 294 # The Chrome Web Store requires messages used in manifest.json to
tlucas 2017/10/02 09:25:43 nit: this line is 1 character too long
Sebastian Noack 2017/10/02 23:01:33 Done.
319 # present in all languages, and enforces length limits on extension 295 # be present in all languages, and enforces length limits on
320 # name and description. 296 # extension name and description.
321 if filename == 'messages.json': 297 is_latam, is_mexican, filename = match.groups()
322 data = json.loads(files[path]) 298 if filename == 'messages.json':
323 for name, info in defaults.iteritems(): 299 data = json.loads(files[path])
324 data.setdefault(name, info) 300 for name, info in defaults.iteritems():
325 for name, limit in limits.iteritems(): 301 data.setdefault(name, info)
326 info = data.get(name) 302 for name, limit in limits.iteritems():
327 if info: 303 info = data.get(name)
328 info['message'] = truncate(info['message'], limit) 304 if info:
329 files[path] = toJson(data) 305 info['message'] = truncate(info['message'], limit)
330 306 files[path] = toJson(data)
331 # Chrome combines Latin American dialects of Spanish into es-419. 307
332 if isLatAm: 308 # Chrome combines Latin American dialects of Spanish into es-419.
333 data = files.pop(path) 309 if is_latam:
334 if isMexican: 310 data = files.pop(path)
335 files['_locales/es_419/' + filename] = data 311 if is_mexican:
312 files['_locales/es_419/' + filename] = data
336 313
337 314
338 def signBinary(zipdata, keyFile): 315 def signBinary(zipdata, keyFile):
339 from Crypto.Hash import SHA 316 from Crypto.Hash import SHA
340 from Crypto.PublicKey import RSA 317 from Crypto.PublicKey import RSA
341 from Crypto.Signature import PKCS1_v1_5 318 from Crypto.Signature import PKCS1_v1_5
342 319
343 try: 320 try:
344 with open(keyFile, 'rb') as file: 321 with open(keyFile, 'rb') as file:
345 key = RSA.importKey(file.read()) 322 key = RSA.importKey(file.read())
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 files.preprocess( 382 files.preprocess(
406 [f for f, _ in metadata.items('preprocess')], 383 [f for f, _ in metadata.items('preprocess')],
407 {'needsExt': True} 384 {'needsExt': True}
408 ) 385 )
409 386
410 if metadata.has_section('import_locales'): 387 if metadata.has_section('import_locales'):
411 import_locales(params, files) 388 import_locales(params, files)
412 389
413 files['manifest.json'] = createManifest(params, files) 390 files['manifest.json'] = createManifest(params, files)
414 if type == 'chrome': 391 if type == 'chrome':
415 fixTranslationsForChrome(files) 392 fix_translations_for_chrome(files)
416 393
417 if devenv: 394 if devenv:
418 import buildtools 395 import buildtools
419 import random 396 import random
420 files.read(os.path.join(buildtools.__path__[0], 'chromeDevenvPoller__.js '), relpath='devenvPoller__.js') 397 files.read(os.path.join(buildtools.__path__[0], 'chromeDevenvPoller__.js '), relpath='devenvPoller__.js')
421 files['devenvVersion__'] = str(random.random()) 398 files['devenvVersion__'] = str(random.random())
422 399
423 if metadata.has_option('general', 'testScripts'): 400 if metadata.has_option('general', 'testScripts'):
424 files['qunit/index.html'] = createScriptPage( 401 files['qunit/index.html'] = createScriptPage(
425 params, 'testIndex.html.tmpl', ('general', 'testScripts') 402 params, 'testIndex.html.tmpl', ('general', 'testScripts')
426 ) 403 )
427 404
428 zipdata = files.zipToString() 405 zipdata = files.zipToString()
429 signature = None 406 signature = None
430 pubkey = None 407 pubkey = None
431 if keyFile != None: 408 if keyFile != None:
432 signature = signBinary(zipdata, keyFile) 409 signature = signBinary(zipdata, keyFile)
433 pubkey = getPublicKey(keyFile) 410 pubkey = getPublicKey(keyFile)
434 writePackage(outFile, pubkey, signature, zipdata) 411 writePackage(outFile, pubkey, signature, zipdata)
LEFTRIGHT

Powered by Google App Engine
This is Rietveld