summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2017-04-07 16:57:21 +1200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-04-11 18:10:17 +0100
commit1f19d9dfe59d5d627bc7ce0b20bd762e5b304dca (patch)
treeac4aae13f7c9702b97f22515c6c095785e0d2990
parent9049c09793eddd7e314d4ae9cca73e1274dcf6f8 (diff)
downloadpoky-1f19d9dfe59d5d627bc7ce0b20bd762e5b304dca.tar.gz
buildhistory-diff: add option to compare actual signature differences
Use the code underpinning bitbake-diffsigs to add an option to buildhistory-diff to determine and display the differences between the actual signature inputs, with a twist - we collapse identical changes across different tasks, showing only the most recent task to have that difference, meaning that there's less noise to wade through when you just want to know what changed in order to cause some rebuilding you're seeing. (From OE-Core rev: 86cb4b01f2020553902554e512c02147eb4e0f51) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/lib/oe/buildhistory_analysis.py92
-rwxr-xr-xscripts/buildhistory-diff7
2 files changed, 81 insertions, 18 deletions
diff --git a/meta/lib/oe/buildhistory_analysis.py b/meta/lib/oe/buildhistory_analysis.py
index 449446f33b..3a5b7b6b44 100644
--- a/meta/lib/oe/buildhistory_analysis.py
+++ b/meta/lib/oe/buildhistory_analysis.py
@@ -13,7 +13,10 @@ import os.path
13import difflib 13import difflib
14import git 14import git
15import re 15import re
16import hashlib
17import collections
16import bb.utils 18import bb.utils
19import bb.tinfoil
17 20
18 21
19# How to display fields 22# How to display fields
@@ -410,7 +413,7 @@ def compare_dict_blobs(path, ablob, bblob, report_all, report_ver):
410 return changes 413 return changes
411 414
412 415
413def compare_siglists(a_blob, b_blob): 416def compare_siglists(a_blob, b_blob, taskdiff=False):
414 # FIXME collapse down a recipe's tasks? 417 # FIXME collapse down a recipe's tasks?
415 alines = a_blob.data_stream.read().decode('utf-8').splitlines() 418 alines = a_blob.data_stream.read().decode('utf-8').splitlines()
416 blines = b_blob.data_stream.read().decode('utf-8').splitlines() 419 blines = b_blob.data_stream.read().decode('utf-8').splitlines()
@@ -429,26 +432,83 @@ def compare_siglists(a_blob, b_blob):
429 adict = readsigs(alines) 432 adict = readsigs(alines)
430 bdict = readsigs(blines) 433 bdict = readsigs(blines)
431 out = [] 434 out = []
435
432 changecount = 0 436 changecount = 0
433 addcount = 0 437 addcount = 0
434 removecount = 0 438 removecount = 0
435 for key in keys: 439 if taskdiff:
436 siga = adict.get(key, None) 440 with bb.tinfoil.Tinfoil() as tinfoil:
437 sigb = bdict.get(key, None) 441 tinfoil.prepare(config_only=True)
438 if siga is not None and sigb is not None and siga != sigb: 442
439 out.append('%s changed from %s to %s' % (key, siga, sigb)) 443 changes = collections.OrderedDict()
440 changecount += 1 444
441 elif siga is None: 445 def compare_hashfiles(pn, taskname, hash1, hash2):
442 out.append('%s was added' % key) 446 hashes = [hash1, hash2]
443 addcount += 1 447 hashfiles = bb.siggen.find_siginfo(pn, taskname, hashes, tinfoil.config_data)
444 elif sigb is None: 448
445 removecount += 1 449 if not taskname:
446 out.append('%s was removed' % key) 450 (pn, taskname) = pn.rsplit('.', 1)
451 pn = pnmap.get(pn, pn)
452 desc = '%s.%s' % (pn, taskname)
453
454 if len(hashfiles) == 0:
455 out.append("Unable to find matching sigdata for %s with hashes %s or %s" % (desc, hash1, hash2))
456 elif not hash1 in hashfiles:
457 out.append("Unable to find matching sigdata for %s with hash %s" % (desc, hash1))
458 elif not hash2 in hashfiles:
459 out.append("Unable to find matching sigdata for %s with hash %s" % (desc, hash2))
460 else:
461 out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb, collapsed=True)
462 for line in out2:
463 m = hashlib.sha256()
464 m.update(line.encode('utf-8'))
465 entry = changes.get(m.hexdigest(), (line, []))
466 if desc not in entry[1]:
467 changes[m.hexdigest()] = (line, entry[1] + [desc])
468
469 # Define recursion callback
470 def recursecb(key, hash1, hash2):
471 compare_hashfiles(key, None, hash1, hash2)
472 return []
473
474 for key in keys:
475 siga = adict.get(key, None)
476 sigb = bdict.get(key, None)
477 if siga is not None and sigb is not None and siga != sigb:
478 changecount += 1
479 (pn, taskname) = key.rsplit('.', 1)
480 compare_hashfiles(pn, taskname, siga, sigb)
481 elif siga is None:
482 addcount += 1
483 elif sigb is None:
484 removecount += 1
485 for key, item in changes.items():
486 line, tasks = item
487 if len(tasks) == 1:
488 desc = tasks[0]
489 elif len(tasks) == 2:
490 desc = '%s and %s' % (tasks[0], tasks[1])
491 else:
492 desc = '%s and %d others' % (tasks[-1], len(tasks)-1)
493 out.append('%s: %s' % (desc, line))
494 else:
495 for key in keys:
496 siga = adict.get(key, None)
497 sigb = bdict.get(key, None)
498 if siga is not None and sigb is not None and siga != sigb:
499 out.append('%s changed from %s to %s' % (key, siga, sigb))
500 changecount += 1
501 elif siga is None:
502 out.append('%s was added' % key)
503 addcount += 1
504 elif sigb is None:
505 out.append('%s was removed' % key)
506 removecount += 1
447 out.append('Summary: %d tasks added, %d tasks removed, %d tasks modified (%.1f%%)' % (addcount, removecount, changecount, (changecount / float(len(bdict)) * 100))) 507 out.append('Summary: %d tasks added, %d tasks removed, %d tasks modified (%.1f%%)' % (addcount, removecount, changecount, (changecount / float(len(bdict)) * 100)))
448 return '\n'.join(out) 508 return '\n'.join(out)
449 509
450 510
451def process_changes(repopath, revision1, revision2='HEAD', report_all=False, report_ver=False, sigs=False): 511def process_changes(repopath, revision1, revision2='HEAD', report_all=False, report_ver=False, sigs=False, sigsdiff=False):
452 repo = git.Repo(repopath) 512 repo = git.Repo(repopath)
453 assert repo.bare == False 513 assert repo.bare == False
454 commit = repo.commit(revision1) 514 commit = repo.commit(revision1)
@@ -456,10 +516,10 @@ def process_changes(repopath, revision1, revision2='HEAD', report_all=False, rep
456 516
457 changes = [] 517 changes = []
458 518
459 if sigs: 519 if sigs or sigsdiff:
460 for d in diff.iter_change_type('M'): 520 for d in diff.iter_change_type('M'):
461 if d.a_blob.path == 'siglist.txt': 521 if d.a_blob.path == 'siglist.txt':
462 changes.append(compare_siglists(d.a_blob, d.b_blob)) 522 changes.append(compare_siglists(d.a_blob, d.b_blob, taskdiff=sigsdiff))
463 return changes 523 return changes
464 524
465 for d in diff.iter_change_type('M'): 525 for d in diff.iter_change_type('M'):
diff --git a/scripts/buildhistory-diff b/scripts/buildhistory-diff
index e8e3e11649..dd9745e80c 100755
--- a/scripts/buildhistory-diff
+++ b/scripts/buildhistory-diff
@@ -34,8 +34,11 @@ def main():
34 help = "Report all changes, not just the default significant ones", 34 help = "Report all changes, not just the default significant ones",
35 action="store_true", dest="report_all", default=False) 35 action="store_true", dest="report_all", default=False)
36 parser.add_option("-s", "--signatures", 36 parser.add_option("-s", "--signatures",
37 help = "Report on signature differences instead of output", 37 help = "Report list of signatures differing instead of output",
38 action="store_true", dest="sigs", default=False) 38 action="store_true", dest="sigs", default=False)
39 parser.add_option("-S", "--signatures-with-diff",
40 help = "Report on actual signature differences instead of output (requires signature data to have been generated, either by running the actual tasks or using bitbake -S)",
41 action="store_true", dest="sigsdiff", default=False)
39 42
40 options, args = parser.parse_args(sys.argv) 43 options, args = parser.parse_args(sys.argv)
41 44
@@ -89,7 +92,7 @@ def main():
89 92
90 import gitdb 93 import gitdb
91 try: 94 try:
92 changes = oe.buildhistory_analysis.process_changes(options.buildhistory_dir, fromrev, torev, options.report_all, options.report_ver, options.sigs) 95 changes = oe.buildhistory_analysis.process_changes(options.buildhistory_dir, fromrev, torev, options.report_all, options.report_ver, options.sigs, options.sigsdiff)
93 except gitdb.exc.BadObject as e: 96 except gitdb.exc.BadObject as e:
94 if len(args) == 1: 97 if len(args) == 1:
95 sys.stderr.write("Unable to find previous build revision in buildhistory repository\n\n") 98 sys.stderr.write("Unable to find previous build revision in buildhistory repository\n\n")