summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbitbake/bin/bitbake-diffsigs18
-rw-r--r--bitbake/lib/bb/siggen.py101
2 files changed, 85 insertions, 34 deletions
diff --git a/bitbake/bin/bitbake-diffsigs b/bitbake/bin/bitbake-diffsigs
index e9fdb48993..884be1e3c7 100755
--- a/bitbake/bin/bitbake-diffsigs
+++ b/bitbake/bin/bitbake-diffsigs
@@ -34,7 +34,7 @@ import bb.msg
34 34
35logger = bb.msg.logger_create('bitbake-diffsigs') 35logger = bb.msg.logger_create('bitbake-diffsigs')
36 36
37def find_compare_task(bbhandler, pn, taskname, sig1=None, sig2=None): 37def find_compare_task(bbhandler, pn, taskname, sig1=None, sig2=None, color=False):
38 """ Find the most recent signature files for the specified PN/task and compare them """ 38 """ Find the most recent signature files for the specified PN/task and compare them """
39 39
40 if not hasattr(bb.siggen, 'find_siginfo'): 40 if not hasattr(bb.siggen, 'find_siginfo'):
@@ -79,7 +79,7 @@ def find_compare_task(bbhandler, pn, taskname, sig1=None, sig2=None):
79 elif not hash2 in hashfiles: 79 elif not hash2 in hashfiles:
80 recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2)) 80 recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
81 else: 81 else:
82 out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb) 82 out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb, color=color)
83 for change in out2: 83 for change in out2:
84 for line in change.splitlines(): 84 for line in change.splitlines():
85 recout.append(' ' + line) 85 recout.append(' ' + line)
@@ -89,7 +89,7 @@ def find_compare_task(bbhandler, pn, taskname, sig1=None, sig2=None):
89 # Recurse into signature comparison 89 # Recurse into signature comparison
90 logger.debug("Signature file (previous): %s" % latestfiles[-2]) 90 logger.debug("Signature file (previous): %s" % latestfiles[-2])
91 logger.debug("Signature file (latest): %s" % latestfiles[-1]) 91 logger.debug("Signature file (latest): %s" % latestfiles[-1])
92 output = bb.siggen.compare_sigfiles(latestfiles[-2], latestfiles[-1], recursecb) 92 output = bb.siggen.compare_sigfiles(latestfiles[-2], latestfiles[-1], recursecb, color=color)
93 if output: 93 if output:
94 print('\n'.join(output)) 94 print('\n'.join(output))
95 sys.exit(0) 95 sys.exit(0)
@@ -103,6 +103,10 @@ parser.add_argument('-d', '--debug',
103 help='Enable debug output', 103 help='Enable debug output',
104 action='store_true') 104 action='store_true')
105 105
106parser.add_argument('--color',
107 help='Colorize output (where %(metavar)s is %(choices)s)',
108 choices=['auto', 'always', 'never'], default='auto', metavar='color')
109
106parser.add_argument("-t", "--task", 110parser.add_argument("-t", "--task",
107 help="find the signature data files for last two runs of the specified task and compare them", 111 help="find the signature data files for last two runs of the specified task and compare them",
108 action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname')) 112 action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
@@ -125,20 +129,22 @@ options = parser.parse_args()
125if options.debug: 129if options.debug:
126 logger.setLevel(logging.DEBUG) 130 logger.setLevel(logging.DEBUG)
127 131
132color = (options.color == 'always' or (options.color == 'auto' and sys.stdout.isatty()))
133
128if options.taskargs: 134if options.taskargs:
129 with bb.tinfoil.Tinfoil() as tinfoil: 135 with bb.tinfoil.Tinfoil() as tinfoil:
130 tinfoil.prepare(config_only=True) 136 tinfoil.prepare(config_only=True)
131 if options.sigargs: 137 if options.sigargs:
132 find_compare_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1]) 138 find_compare_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1], color=color)
133 else: 139 else:
134 find_compare_task(tinfoil, options.taskargs[0], options.taskargs[1]) 140 find_compare_task(tinfoil, options.taskargs[0], options.taskargs[1], color=color)
135else: 141else:
136 if options.sigargs: 142 if options.sigargs:
137 logger.error('-s/--signature can only be used together with -t/--task') 143 logger.error('-s/--signature can only be used together with -t/--task')
138 sys.exit(1) 144 sys.exit(1)
139 try: 145 try:
140 if options.sigdatafile1 and options.sigdatafile2: 146 if options.sigdatafile1 and options.sigdatafile2:
141 output = bb.siggen.compare_sigfiles(options.sigdatafile1, options.sigdatafile2) 147 output = bb.siggen.compare_sigfiles(options.sigdatafile1, options.sigdatafile2, color=color)
142 elif options.sigdatafile1: 148 elif options.sigdatafile1:
143 output = bb.siggen.dump_sigfile(options.sigdatafile1) 149 output = bb.siggen.dump_sigfile(options.sigdatafile1)
144 except IOError as e: 150 except IOError as e:
diff --git a/bitbake/lib/bb/siggen.py b/bitbake/lib/bb/siggen.py
index d40c721fbf..25ad3e9165 100644
--- a/bitbake/lib/bb/siggen.py
+++ b/bitbake/lib/bb/siggen.py
@@ -353,7 +353,23 @@ def dump_this_task(outfile, d):
353 referencestamp = bb.build.stamp_internal(task, d, None, True) 353 referencestamp = bb.build.stamp_internal(task, d, None, True)
354 bb.parse.siggen.dump_sigtask(fn, task, outfile, "customfile:" + referencestamp) 354 bb.parse.siggen.dump_sigtask(fn, task, outfile, "customfile:" + referencestamp)
355 355
356def worddiff_str(oldstr, newstr): 356def init_colors(enable_color):
357 """Initialise colour dict for passing to compare_sigfiles()"""
358 # First set up the colours
359 colors = {'color_title': '\033[1;37;40m',
360 'color_default': '\033[0;37;40m',
361 'color_add': '\033[1;32;40m',
362 'color_remove': '\033[1;31;40m',
363 }
364 # Leave all keys present but clear the values
365 if not enable_color:
366 for k in colors.keys():
367 colors[k] = ''
368 return colors
369
370def worddiff_str(oldstr, newstr, colors=None):
371 if not colors:
372 colors = init_colors(False)
357 diff = simplediff.diff(oldstr.split(' '), newstr.split(' ')) 373 diff = simplediff.diff(oldstr.split(' '), newstr.split(' '))
358 ret = [] 374 ret = []
359 for change, value in diff: 375 for change, value in diff:
@@ -361,17 +377,19 @@ def worddiff_str(oldstr, newstr):
361 if change == '=': 377 if change == '=':
362 ret.append(value) 378 ret.append(value)
363 elif change == '+': 379 elif change == '+':
364 item = '{+%s+}' % value 380 item = '{color_add}{{+{value}+}}{color_default}'.format(value=value, **colors)
365 ret.append(item) 381 ret.append(item)
366 elif change == '-': 382 elif change == '-':
367 item = '[-%s-]' % value 383 item = '{color_remove}[-{value}-]{color_default}'.format(value=value, **colors)
368 ret.append(item) 384 ret.append(item)
369 whitespace_note = '' 385 whitespace_note = ''
370 if oldstr != newstr and ' '.join(oldstr.split()) == ' '.join(newstr.split()): 386 if oldstr != newstr and ' '.join(oldstr.split()) == ' '.join(newstr.split()):
371 whitespace_note = ' (whitespace changed)' 387 whitespace_note = ' (whitespace changed)'
372 return '"%s"%s' % (' '.join(ret), whitespace_note) 388 return '"%s"%s' % (' '.join(ret), whitespace_note)
373 389
374def list_inline_diff(oldlist, newlist): 390def list_inline_diff(oldlist, newlist, colors=None):
391 if not colors:
392 colors = init_colors(False)
375 diff = simplediff.diff(oldlist, newlist) 393 diff = simplediff.diff(oldlist, newlist)
376 ret = [] 394 ret = []
377 for change, value in diff: 395 for change, value in diff:
@@ -379,10 +397,10 @@ def list_inline_diff(oldlist, newlist):
379 if change == '=': 397 if change == '=':
380 ret.append("'%s'" % value) 398 ret.append("'%s'" % value)
381 elif change == '+': 399 elif change == '+':
382 item = "+'%s'" % value 400 item = '{color_add}+{value}{color_default}'.format(value=value, **colors)
383 ret.append(item) 401 ret.append(item)
384 elif change == '-': 402 elif change == '-':
385 item = "-'%s'" % value 403 item = '{color_remove}-{value}{color_default}'.format(value=value, **colors)
386 ret.append(item) 404 ret.append(item)
387 return '[%s]' % (', '.join(ret)) 405 return '[%s]' % (', '.join(ret))
388 406
@@ -409,9 +427,26 @@ def clean_basepaths_list(a):
409 b.append(clean_basepath(x)) 427 b.append(clean_basepath(x))
410 return b 428 return b
411 429
412def compare_sigfiles(a, b, recursecb=None, collapsed=False): 430def compare_sigfiles(a, b, recursecb=None, color=False, collapsed=False):
413 output = [] 431 output = []
414 432
433 colors = init_colors(color)
434 def color_format(formatstr, **values):
435 """
436 Return colour formatted string.
437 NOTE: call with the format string, not an already formatted string
438 containing values (otherwise you could have trouble with { and }
439 characters)
440 """
441 if not formatstr.endswith('{color_default}'):
442 formatstr += '{color_default}'
443 # In newer python 3 versions you can pass both of these directly,
444 # but we only require 3.4 at the moment
445 formatparams = {}
446 formatparams.update(colors)
447 formatparams.update(values)
448 return formatstr.format(**formatparams)
449
415 with open(a, 'rb') as f: 450 with open(a, 'rb') as f:
416 p1 = pickle.Unpickler(f) 451 p1 = pickle.Unpickler(f)
417 a_data = p1.load() 452 a_data = p1.load()
@@ -465,33 +500,33 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
465 return changed, added, removed 500 return changed, added, removed
466 501
467 if 'basewhitelist' in a_data and a_data['basewhitelist'] != b_data['basewhitelist']: 502 if 'basewhitelist' in a_data and a_data['basewhitelist'] != b_data['basewhitelist']:
468 output.append("basewhitelist changed from '%s' to '%s'" % (a_data['basewhitelist'], b_data['basewhitelist'])) 503 output.append(color_format("{color_title}basewhitelist changed{color_default} from '%s' to '%s'") % (a_data['basewhitelist'], b_data['basewhitelist']))
469 if a_data['basewhitelist'] and b_data['basewhitelist']: 504 if a_data['basewhitelist'] and b_data['basewhitelist']:
470 output.append("changed items: %s" % a_data['basewhitelist'].symmetric_difference(b_data['basewhitelist'])) 505 output.append("changed items: %s" % a_data['basewhitelist'].symmetric_difference(b_data['basewhitelist']))
471 506
472 if 'taskwhitelist' in a_data and a_data['taskwhitelist'] != b_data['taskwhitelist']: 507 if 'taskwhitelist' in a_data and a_data['taskwhitelist'] != b_data['taskwhitelist']:
473 output.append("taskwhitelist changed from '%s' to '%s'" % (a_data['taskwhitelist'], b_data['taskwhitelist'])) 508 output.append(color_format("{color_title}taskwhitelist changed{color_default} from '%s' to '%s'") % (a_data['taskwhitelist'], b_data['taskwhitelist']))
474 if a_data['taskwhitelist'] and b_data['taskwhitelist']: 509 if a_data['taskwhitelist'] and b_data['taskwhitelist']:
475 output.append("changed items: %s" % a_data['taskwhitelist'].symmetric_difference(b_data['taskwhitelist'])) 510 output.append("changed items: %s" % a_data['taskwhitelist'].symmetric_difference(b_data['taskwhitelist']))
476 511
477 if a_data['taskdeps'] != b_data['taskdeps']: 512 if a_data['taskdeps'] != b_data['taskdeps']:
478 output.append("Task dependencies changed from:\n%s\nto:\n%s" % (sorted(a_data['taskdeps']), sorted(b_data['taskdeps']))) 513 output.append(color_format("{color_title}Task dependencies changed{color_default} from:\n%s\nto:\n%s") % (sorted(a_data['taskdeps']), sorted(b_data['taskdeps'])))
479 514
480 if a_data['basehash'] != b_data['basehash'] and not collapsed: 515 if a_data['basehash'] != b_data['basehash'] and not collapsed:
481 output.append("basehash changed from %s to %s" % (a_data['basehash'], b_data['basehash'])) 516 output.append(color_format("{color_title}basehash changed{color_default} from %s to %s") % (a_data['basehash'], b_data['basehash']))
482 517
483 changed, added, removed = dict_diff(a_data['gendeps'], b_data['gendeps'], a_data['basewhitelist'] & b_data['basewhitelist']) 518 changed, added, removed = dict_diff(a_data['gendeps'], b_data['gendeps'], a_data['basewhitelist'] & b_data['basewhitelist'])
484 if changed: 519 if changed:
485 for dep in changed: 520 for dep in changed:
486 output.append("List of dependencies for variable %s changed from '%s' to '%s'" % (dep, a_data['gendeps'][dep], b_data['gendeps'][dep])) 521 output.append(color_format("{color_title}List of dependencies for variable %s changed from '{color_default}%s{color_title}' to '{color_default}%s{color_title}'") % (dep, a_data['gendeps'][dep], b_data['gendeps'][dep]))
487 if a_data['gendeps'][dep] and b_data['gendeps'][dep]: 522 if a_data['gendeps'][dep] and b_data['gendeps'][dep]:
488 output.append("changed items: %s" % a_data['gendeps'][dep].symmetric_difference(b_data['gendeps'][dep])) 523 output.append("changed items: %s" % a_data['gendeps'][dep].symmetric_difference(b_data['gendeps'][dep]))
489 if added: 524 if added:
490 for dep in added: 525 for dep in added:
491 output.append("Dependency on variable %s was added" % (dep)) 526 output.append(color_format("{color_title}Dependency on variable %s was added") % (dep))
492 if removed: 527 if removed:
493 for dep in removed: 528 for dep in removed:
494 output.append("Dependency on Variable %s was removed" % (dep)) 529 output.append(color_format("{color_title}Dependency on Variable %s was removed") % (dep))
495 530
496 531
497 changed, added, removed = dict_diff(a_data['varvals'], b_data['varvals']) 532 changed, added, removed = dict_diff(a_data['varvals'], b_data['varvals'])
@@ -504,11 +539,20 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
504 # Cut off the first two lines, since we aren't interested in 539 # Cut off the first two lines, since we aren't interested in
505 # the old/new filename (they are blank anyway in this case) 540 # the old/new filename (they are blank anyway in this case)
506 difflines = list(diff)[2:] 541 difflines = list(diff)[2:]
507 output.append("Variable %s value changed:\n%s" % (dep, '\n'.join(difflines))) 542 if color:
543 # Add colour to diff output
544 for i, line in enumerate(difflines):
545 if line.startswith('+'):
546 line = color_format('{color_add}{line}', line=line)
547 difflines[i] = line
548 elif line.startswith('-'):
549 line = color_format('{color_remove}{line}', line=line)
550 difflines[i] = line
551 output.append(color_format("{color_title}Variable {var} value changed:{color_default}\n{diff}", var=dep, diff='\n'.join(difflines)))
508 elif newval and oldval and (' ' in oldval or ' ' in newval): 552 elif newval and oldval and (' ' in oldval or ' ' in newval):
509 output.append("Variable %s value changed:\n%s" % (dep, worddiff_str(oldval, newval))) 553 output.append(color_format("{color_title}Variable {var} value changed:{color_default}\n{diff}", var=dep, diff=worddiff_str(oldval, newval, colors)))
510 else: 554 else:
511 output.append("Variable %s value changed from '%s' to '%s'" % (dep, oldval, newval)) 555 output.append(color_format("{color_title}Variable {var} value changed from '{color_default}{oldval}{color_title}' to '{color_default}{newval}{color_title}'{color_default}", var=dep, oldval=oldval, newval=newval))
512 556
513 if not 'file_checksum_values' in a_data: 557 if not 'file_checksum_values' in a_data:
514 a_data['file_checksum_values'] = {} 558 a_data['file_checksum_values'] = {}
@@ -518,13 +562,13 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
518 changed, added, removed = file_checksums_diff(a_data['file_checksum_values'], b_data['file_checksum_values']) 562 changed, added, removed = file_checksums_diff(a_data['file_checksum_values'], b_data['file_checksum_values'])
519 if changed: 563 if changed:
520 for f, old, new in changed: 564 for f, old, new in changed:
521 output.append("Checksum for file %s changed from %s to %s" % (f, old, new)) 565 output.append(color_format("{color_title}Checksum for file %s changed{color_default} from %s to %s") % (f, old, new))
522 if added: 566 if added:
523 for f in added: 567 for f in added:
524 output.append("Dependency on checksum of file %s was added" % (f)) 568 output.append(color_format("{color_title}Dependency on checksum of file %s was added") % (f))
525 if removed: 569 if removed:
526 for f in removed: 570 for f in removed:
527 output.append("Dependency on checksum of file %s was removed" % (f)) 571 output.append(color_format("{color_title}Dependency on checksum of file %s was removed") % (f))
528 572
529 if not 'runtaskdeps' in a_data: 573 if not 'runtaskdeps' in a_data:
530 a_data['runtaskdeps'] = {} 574 a_data['runtaskdeps'] = {}
@@ -539,18 +583,19 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
539 for idx, task in enumerate(a_data['runtaskdeps']): 583 for idx, task in enumerate(a_data['runtaskdeps']):
540 a = a_data['runtaskdeps'][idx] 584 a = a_data['runtaskdeps'][idx]
541 b = b_data['runtaskdeps'][idx] 585 b = b_data['runtaskdeps'][idx]
542 if a_data['runtaskhashes'][a] != b_data['runtaskhashes'][b]: 586 if a_data['runtaskhashes'][a] != b_data['runtaskhashes'][b] and not collapsed:
543 changed.append("%s with hash %s\n changed to\n%s with hash %s" % (a, a_data['runtaskhashes'][a], b, b_data['runtaskhashes'][b])) 587 changed.append("%s with hash %s\n changed to\n%s with hash %s" % (clean_basepath(a), a_data['runtaskhashes'][a], clean_basepath(b), b_data['runtaskhashes'][b]))
544 588
545 if changed: 589 if changed:
546 clean_a = clean_basepaths_list(a_data['runtaskdeps']) 590 clean_a = clean_basepaths_list(a_data['runtaskdeps'])
547 clean_b = clean_basepaths_list(b_data['runtaskdeps']) 591 clean_b = clean_basepaths_list(b_data['runtaskdeps'])
548 if clean_a != clean_b: 592 if clean_a != clean_b:
549 output.append("runtaskdeps changed:\n%s" % list_inline_diff(clean_a, clean_b)) 593 output.append(color_format("{color_title}runtaskdeps changed:{color_default}\n%s") % list_inline_diff(clean_a, clean_b, colors))
550 else: 594 else:
551 output.append("runtaskdeps changed:") 595 output.append(color_format("{color_title}runtaskdeps changed:"))
552 output.append("\n".join(changed)) 596 output.append("\n".join(changed))
553 597
598
554 if 'runtaskhashes' in a_data and 'runtaskhashes' in b_data: 599 if 'runtaskhashes' in a_data and 'runtaskhashes' in b_data:
555 a = a_data['runtaskhashes'] 600 a = a_data['runtaskhashes']
556 b = b_data['runtaskhashes'] 601 b = b_data['runtaskhashes']
@@ -564,7 +609,7 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
564 #output.append("Dependency on task %s was replaced by %s with same hash" % (dep, bdep)) 609 #output.append("Dependency on task %s was replaced by %s with same hash" % (dep, bdep))
565 bdep_found = True 610 bdep_found = True
566 if not bdep_found: 611 if not bdep_found:
567 output.append("Dependency on task %s was added with hash %s" % (clean_basepath(dep), b[dep])) 612 output.append(color_format("{color_title}Dependency on task %s was added{color_default} with hash %s") % (clean_basepath(dep), b[dep]))
568 if removed: 613 if removed:
569 for dep in removed: 614 for dep in removed:
570 adep_found = False 615 adep_found = False
@@ -574,11 +619,11 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
574 #output.append("Dependency on task %s was replaced by %s with same hash" % (adep, dep)) 619 #output.append("Dependency on task %s was replaced by %s with same hash" % (adep, dep))
575 adep_found = True 620 adep_found = True
576 if not adep_found: 621 if not adep_found:
577 output.append("Dependency on task %s was removed with hash %s" % (clean_basepath(dep), a[dep])) 622 output.append(color_format("{color_title}Dependency on task %s was removed{color_default} with hash %s") % (clean_basepath(dep), a[dep]))
578 if changed: 623 if changed:
579 for dep in changed: 624 for dep in changed:
580 if not collapsed: 625 if not collapsed:
581 output.append("Hash for dependent task %s changed from %s to %s" % (clean_basepath(dep), a[dep], b[dep])) 626 output.append(color_format("{color_title}Hash for dependent task %s changed{color_default} from %s to %s") % (clean_basepath(dep), a[dep], b[dep]))
582 if callable(recursecb): 627 if callable(recursecb):
583 recout = recursecb(dep, a[dep], b[dep]) 628 recout = recursecb(dep, a[dep], b[dep])
584 if recout: 629 if recout:
@@ -592,7 +637,7 @@ def compare_sigfiles(a, b, recursecb=None, collapsed=False):
592 a_taint = a_data.get('taint', None) 637 a_taint = a_data.get('taint', None)
593 b_taint = b_data.get('taint', None) 638 b_taint = b_data.get('taint', None)
594 if a_taint != b_taint: 639 if a_taint != b_taint:
595 output.append("Taint (by forced/invalidated task) changed from %s to %s" % (a_taint, b_taint)) 640 output.append(color_format("{color_title}Taint (by forced/invalidated task) changed{color_default} from %s to %s") % (a_taint, b_taint))
596 641
597 return output 642 return output
598 643