summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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")