summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2017-04-07 09:52:11 +1200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-04-10 23:00:32 +0100
commitb372e85d9b41ab8ceb4695c223fdf4c35913323b (patch)
tree08605d698e8aa954071c5cff9e12c0dccf4239dd /bitbake
parent5f7bf1f66d21155dfa5328aa57b4302cc64c132b (diff)
downloadpoky-b372e85d9b41ab8ceb4695c223fdf4c35913323b.tar.gz
bitbake: bitbake-diffsigs: colourise output
If the output is a TTY, add colour to the output in order to make it easier to read. At the moment this is fairly basic, just add colour to the "titles" of each change and to the diff output. I tried to introduce this without changing the code too much - rather than moving everything over to the new python formatting style, I've introduced a color_format() function which takes care of the colour formatting, either accepting additional format arguments or alternatively leaving the caller to use the old-style formatting (%) to insert values. (Bitbake rev: 04a023c8fdea1e1812fcdcaf00345aab59f9abe1) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-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