OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Compare the artifacts from two builds.""" | 6 """Compare the artifacts from two builds.""" |
7 | 7 |
8 import difflib | 8 import difflib |
9 import json | 9 import json |
10 import optparse | 10 import optparse |
11 import os | 11 import os |
12 import re | |
13 import subprocess | |
12 import struct | 14 import struct |
13 import sys | 15 import sys |
14 import time | 16 import time |
15 | 17 |
16 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 18 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
17 | 19 |
18 | 20 |
19 # List of files that are known to be non deterministic. This is a "temporary" | 21 # List of files that are known to be non deterministic. This is a "temporary" |
20 # workaround to find regression on the deterministic builders. | 22 # workaround to find regression on the deterministic builders. |
21 # | 23 # |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
488 # else, falls through binary comparison, it must be binary equal too. | 490 # else, falls through binary comparison, it must be binary equal too. |
489 | 491 |
490 file_len = os.stat(first_filepath).st_size | 492 file_len = os.stat(first_filepath).st_size |
491 if file_len != os.stat(second_filepath).st_size: | 493 if file_len != os.stat(second_filepath).st_size: |
492 return 'different size: %d != %d' % ( | 494 return 'different size: %d != %d' % ( |
493 file_len, os.stat(second_filepath).st_size) | 495 file_len, os.stat(second_filepath).st_size) |
494 | 496 |
495 return diff_binary(first_filepath, second_filepath, file_len) | 497 return diff_binary(first_filepath, second_filepath, file_len) |
496 | 498 |
497 | 499 |
500 def get_deps(build_dir, target): | |
501 """Returns list of object files needed to build target.""" | |
502 NODE_PATTERN = re.compile(r'label="([a-zA-Z0-9_\\/.-]+)"') | |
503 CHECK_EXTS = ('.o', '.obj') | |
504 try: | |
505 out = subprocess.check_output(['ninja', '-C', build_dir, | |
M-A Ruel
2016/08/24 18:47:27
There's a problem as the directory was renamed, so
Yoshisato Yanagisawa
2016/08/25 08:47:29
I have never seen absolute object file path names
M-A Ruel
2016/08/25 15:46:26
zforman@ worked on making this work on linux but t
Yoshisato Yanagisawa
2016/08/29 05:44:49
I checked the code seems to work on Win.
| |
506 '-t', 'graph', target]) | |
507 except subprocess.CalledProcessError as e: | |
508 print >> sys.stderr, 'error to get graph for %s: %s' % (target, e) | |
509 return [] | |
510 files = [] | |
511 for line in out.splitlines(): | |
512 matched = NODE_PATTERN.search(line) | |
513 if matched: | |
514 path = matched.group(1) | |
515 if not os.path.splitext(path)[1] in CHECK_EXTS: | |
516 continue | |
517 files.append(path) | |
518 return files | |
519 | |
520 | |
521 def compare_deps(first_dir, second_dir, targets): | |
522 """Print difference of dependent files.""" | |
523 for target in targets: | |
524 print 'Checking %s difference:' % target | |
525 first_deps = get_deps(first_dir, target) | |
526 second_deps = get_deps(second_dir, target) | |
527 deps = set(first_deps).union(set(second_deps)) | |
M-A Ruel
2016/08/24 18:47:27
the difference should be empty ?
Yoshisato Yanagisawa
2016/08/25 08:47:29
I am not confident. However, I will simplify the
M-A Ruel
2016/08/25 15:46:26
I guess my question was more to print out the diff
Yoshisato Yanagisawa
2016/08/29 05:44:49
I think current code still help us to find this ki
| |
528 for d in deps: | |
529 first_file = os.path.join(first_dir, d) | |
530 second_file = os.path.join(second_dir, d) | |
531 if not os.path.exists(first_file): | |
532 print '%s: not found' % first_file | |
533 continue | |
534 if not os.path.exists(second_file): | |
535 print '%s: not found' % second_file | |
536 continue | |
537 compare_files(first_file, second_file) | |
538 | |
539 | |
498 def compare_build_artifacts(first_dir, second_dir, target_platform, | 540 def compare_build_artifacts(first_dir, second_dir, target_platform, |
499 recursive=False): | 541 recursive=False): |
500 """Compares the artifacts from two distinct builds.""" | 542 """Compares the artifacts from two distinct builds.""" |
501 if not os.path.isdir(first_dir): | 543 if not os.path.isdir(first_dir): |
502 print >> sys.stderr, '%s isn\'t a valid directory.' % first_dir | 544 print >> sys.stderr, '%s isn\'t a valid directory.' % first_dir |
503 return 1 | 545 return 1 |
504 if not os.path.isdir(second_dir): | 546 if not os.path.isdir(second_dir): |
505 print >> sys.stderr, '%s isn\'t a valid directory.' % second_dir | 547 print >> sys.stderr, '%s isn\'t a valid directory.' % second_dir |
506 return 1 | 548 return 1 |
507 | 549 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
554 print('Unexpected diffs: %d' % len(unexpected_diffs)) | 596 print('Unexpected diffs: %d' % len(unexpected_diffs)) |
555 if unexpected_diffs: | 597 if unexpected_diffs: |
556 print('Unexpected files with diffs:\n') | 598 print('Unexpected files with diffs:\n') |
557 for u in unexpected_diffs: | 599 for u in unexpected_diffs: |
558 print(' %s' % u) | 600 print(' %s' % u) |
559 if unexpected_equals: | 601 if unexpected_equals: |
560 print('Unexpected files with no diffs:\n') | 602 print('Unexpected files with no diffs:\n') |
561 for u in unexpected_equals: | 603 for u in unexpected_equals: |
562 print(' %s' % u) | 604 print(' %s' % u) |
563 | 605 |
606 if unexpected_diffs: | |
607 diffs_to_investigate = set(unexpected_diffs).difference( | |
608 set(missing_files)) | |
609 compare_deps(first_dir, second_dir, diffs_to_investigate) | |
610 | |
564 return int(bool(unexpected_diffs)) | 611 return int(bool(unexpected_diffs)) |
565 | 612 |
566 | 613 |
567 def main(): | 614 def main(): |
568 parser = optparse.OptionParser(usage='%prog [options]') | 615 parser = optparse.OptionParser(usage='%prog [options]') |
569 parser.add_option( | 616 parser.add_option( |
570 '-f', '--first-build-dir', help='The first build directory.') | 617 '-f', '--first-build-dir', help='The first build directory.') |
571 parser.add_option( | 618 parser.add_option( |
572 '-s', '--second-build-dir', help='The second build directory.') | 619 '-s', '--second-build-dir', help='The second build directory.') |
573 parser.add_option('-r', '--recursive', action='store_true', default=False, | 620 parser.add_option('-r', '--recursive', action='store_true', default=False, |
574 help='Indicates if the comparison should be recursive.') | 621 help='Indicates if the comparison should be recursive.') |
575 target = { | 622 target = { |
576 'darwin': 'mac', 'linux2': 'linux', 'win32': 'win' | 623 'darwin': 'mac', 'linux2': 'linux', 'win32': 'win' |
577 }.get(sys.platform, sys.platform) | 624 }.get(sys.platform, sys.platform) |
578 parser.add_option('-t', '--target-platform', help='The target platform.' | 625 parser.add_option('-t', '--target-platform', help='The target platform.', |
579 default=target, choices=('android', 'mac', 'linux', 'win')) | 626 default=target, choices=('android', 'mac', 'linux', 'win')) |
580 options, _ = parser.parse_args() | 627 options, _ = parser.parse_args() |
581 | 628 |
582 if not options.first_build_dir: | 629 if not options.first_build_dir: |
583 parser.error('--first-build-dir is required') | 630 parser.error('--first-build-dir is required') |
584 if not options.second_build_dir: | 631 if not options.second_build_dir: |
585 parser.error('--second-build-dir is required') | 632 parser.error('--second-build-dir is required') |
586 if not options.target_platform: | 633 if not options.target_platform: |
587 parser.error('--target-platform is required') | 634 parser.error('--target-platform is required') |
588 | 635 |
589 return compare_build_artifacts(os.path.abspath(options.first_build_dir), | 636 return compare_build_artifacts(os.path.abspath(options.first_build_dir), |
590 os.path.abspath(options.second_build_dir), | 637 os.path.abspath(options.second_build_dir), |
591 options.target_platform, | 638 options.target_platform, |
592 options.recursive) | 639 options.recursive) |
593 | 640 |
594 | 641 |
595 if __name__ == '__main__': | 642 if __name__ == '__main__': |
596 sys.exit(main()) | 643 sys.exit(main()) |
OLD | NEW |