271
277
self.details[file][category] = [data]
272
278
self.summary[file.locale]['errors'] += 1
279
elif category == 'warning':
281
self.details[file][category].append(data)
283
self.details[file][category] = [data]
284
self.summary[file.locale]['warnings'] += 1
288
for locale in sorted(self.summary.iterkeys()):
289
summary = self.summary[locale]
290
if locale is not None:
291
item = {'id': 'xxx/' + locale,
298
item['type'] = 'Build'
299
total = sum([summary[k]
300
for k in ('changed','unchanged','report','missing',
303
rate = (('changed' in summary and summary['changed'] * 100)
305
item.update((k, summary.get(k, 0))
306
for k in ('changed','unchanged'))
307
item.update((k, summary[k])
308
for k in ('report','errors','warnings')
310
item['missing'] = summary.get('missing', 0) + \
311
summary.get('missingInFiles', 0)
312
item['completion'] = rate
313
item['total'] = total
315
if item.get('warnings',0):
317
if item.get('errors',0) or item.get('missing',0):
319
item['result'] = result
321
data = {"properties": dict.fromkeys(
322
("completion", "errors", "warnings", "missing", "report",
323
"unchanged", "changed", "obsolete"),
324
{"valueType": "number"}),
326
"Build": {"pluralLabel": "Builds"}
328
data['items'] = items
329
return dumps(data, indent=2)
274
330
def serialize(self, type="text/plain"):
331
if type=="application/json":
332
return self.toExhibit()
276
334
if t[1] == 'key':
277
335
return ' ' * t[0] + '/'.join(t[2])
279
337
indent = ' ' * (t[0] + 1)
280
338
if 'error' in t[2]:
281
339
o += [indent + 'ERROR: ' + e for e in t[2]['error']]
340
if 'warning' in t[2]:
341
o += [indent + 'WARNING: ' + e for e in t[2]['warning']]
282
342
if 'missingEntity' in t[2] or 'obsoleteEntity' in t[2]:
283
343
missingEntities = ('missingEntity' in t[2] and t[2]['missingEntity']) \
315
375
class ContentComparer:
316
376
keyRE = re.compile('[kK]ey')
377
nl = re.compile('\n', re.M)
317
378
def __init__(self, filterObserver):
318
379
'''Create a ContentComparer.
319
380
filterObserver is usually a instance of Observer. The return values
331
392
self.observers.append(obs)
332
393
def set_merge_stage(self, merge_stage):
333
394
self.merge_stage = merge_stage
334
def merge(self, ref_entities, ref_map, ref_file, l10n_file, missing, p):
395
def merge(self, ref_entities, ref_map, ref_file, l10n_file, missing, skips,
335
397
outfile = os.path.join(self.merge_stage, l10n_file.module, l10n_file.file)
336
398
outdir = os.path.dirname(outfile)
337
399
if not os.path.isdir(outdir):
340
402
shutil.copyfile(ref_file.fullpath, outfile)
341
403
print "copied reference to " + outfile
343
trailing = [ref_entities[ref_map[key]].all for key in missing]
344
shutil.copyfile(l10n_file.fullpath, outfile)
406
[ref_entities[ref_map[key]].all for key in missing] +
407
[ref_entities[ref_map[skip.key]].all for skip in skips])
409
# we need to skip a few errornous blocks in the input, copy by hand
410
f = codecs.open(outfile, 'wb', p.encoding)
414
f.write(p.contents[offset:chunk[0]])
416
f.write(p.contents[offset:])
418
shutil.copyfile(l10n_file.fullpath, outfile)
419
f = codecs.open(outfile, 'ab', p.encoding)
345
420
print "adding to " + outfile
346
f = codecs.open(outfile, 'ab', p.encoding)
347
f.write(''.join(trailing))
421
def ensureNewline(s):
422
if not s.endswith('\n'):
425
f.write(''.join(map(ensureNewline,trailing)))
349
427
def notify(self, category, file, data):
350
'''Check filterObserver for the found data, and if it's
428
"""Check filterObserver for the found data, and if it's
351
429
not to ignore, notify observers.
353
431
rv = self.filterObserver.notify(category, file, data)
354
432
if rv == 'ignore':
363
441
def compare(self, ref_file, l10n):
365
443
p = Parser.getParser(ref_file.file)
444
checks = Checks.getChecks(ref_file)
366
445
except UserWarning:
367
446
# no comparison, XXX report?
383
462
except Exception, e:
384
463
self.notify('error', l10n, str(e))
466
def _getLine(offset):
469
for m in self.nl.finditer(p.contents):
470
lines.append(m.end())
472
for i in xrange(len(lines), 0, -1):
473
if offset >= lines[i-1]:
474
return (i, offset - lines[i-1])
386
476
l10n_list = l10n_map.keys()
415
506
# entity found in both ref and l10n, check for changed
416
507
entity = item_or_pair[0]
508
refent = ref[0][ref[1][entity]]
509
l10nent = l10n_entities[l10n_map[entity]]
417
510
if self.keyRE.search(entity):
420
refent = ref[0][ref[1][entity]]
421
l10nent = l10n_entities[l10n_map[entity]]
422
513
if refent.val == l10nent.val:
423
514
self.doUnchanged(l10nent)
426
517
self.doChanged(ref_file, refent, l10nent)
521
for tp, pos, msg, cat in checks(refent, l10nent):
522
# compute real src position, if first line, col needs adjustment
523
_l, _offset = _getLine(l10nent.val_span[0])
524
if isinstance(pos, tuple):
527
col = pos[1] + _offset
532
_l, col = _getLine(l10nent.val_span[0] + pos)
533
# skip error entities when merging
534
if tp == 'error' and self.merge_stage is not None:
535
skips.append(l10nent)
536
self.notify(tp, l10n,
537
u"%s at line %d, column %d for %s" %
538
(msg, _l, col, refent.key))
430
541
self.notify('missing', l10n, missing)
431
if self.merge_stage is not None and missings:
432
self.merge(ref[0], ref[1], ref_file, l10n, missings, p)
542
if self.merge_stage is not None and (missings or skips):
543
self.merge(ref[0], ref[1], ref_file, l10n, missings, skips, p)
434
545
self.notify('report', l10n, report)
464
575
# overload this if needed
467
def compareApp(app, otherObserver = None, merge_stage = None):
578
def compareApp(app, otherObserver = None, merge_stage = None, clobber = False):
468
579
'''Compare locales set in app.
470
581
Optional arguments are:
473
584
The return values of that callback are ignored.
474
585
- merge_stage. A directory to be used for staging the output of
587
- clobber. Clobber the module subdirectories of the merge dir as we go.
588
Use wisely, as it might cause data loss.
478
591
cc = ContentComparer(o)
481
594
cc.set_merge_stage(merge_stage)
482
595
o.filter = app.filter
483
596
for module, reference, locales in app:
597
if merge_stage is not None and clobber:
598
# if clobber and merge is on, remove the stage for the module if it exists
599
clobberdir = os.path.join(merge_stage, module)
600
if os.path.exists(clobberdir):
601
shutil.rmtree(clobberdir)
602
print "clobbered " + clobberdir
484
603
dc = DirectoryCompare(reference)
485
604
dc.setWatcher(cc)
486
605
for locale, localization in locales: