diff options
-rw-r--r-- | meta/lib/oe/buildhistory_analysis.py | 92 | ||||
-rwxr-xr-x | scripts/buildhistory-diff | 7 |
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 | |||
13 | import difflib | 13 | import difflib |
14 | import git | 14 | import git |
15 | import re | 15 | import re |
16 | import hashlib | ||
17 | import collections | ||
16 | import bb.utils | 18 | import bb.utils |
19 | import 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 | ||
413 | def compare_siglists(a_blob, b_blob): | 416 | def 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 | ||
451 | def process_changes(repopath, revision1, revision2='HEAD', report_all=False, report_ver=False, sigs=False): | 511 | def 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") |