diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2017-04-07 16:57:21 +1200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2017-04-11 18:10:17 +0100 |
commit | 1f19d9dfe59d5d627bc7ce0b20bd762e5b304dca (patch) | |
tree | ac4aae13f7c9702b97f22515c6c095785e0d2990 /meta | |
parent | 9049c09793eddd7e314d4ae9cca73e1274dcf6f8 (diff) | |
download | poky-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>
Diffstat (limited to 'meta')
-rw-r--r-- | meta/lib/oe/buildhistory_analysis.py | 92 |
1 files changed, 76 insertions, 16 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'): |