OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Enables directory-specific presubmit checks to run at upload and/or commit. | 6 """Enables directory-specific presubmit checks to run at upload and/or commit. |
7 """ | 7 """ |
8 | 8 |
9 __version__ = '1.8.0' | 9 __version__ = '1.8.0' |
10 | 10 |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 if len(tests) > 1 and parallel: | 501 if len(tests) > 1 and parallel: |
502 # async recipe works around multiprocessing bug handling Ctrl-C | 502 # async recipe works around multiprocessing bug handling Ctrl-C |
503 msgs.extend(self._run_tests_pool.map_async(CallCommand, tests).get(99999)) | 503 msgs.extend(self._run_tests_pool.map_async(CallCommand, tests).get(99999)) |
504 else: | 504 else: |
505 msgs.extend(map(CallCommand, tests)) | 505 msgs.extend(map(CallCommand, tests)) |
506 return [m for m in msgs if m] | 506 return [m for m in msgs if m] |
507 | 507 |
508 | 508 |
509 class _DiffCache(object): | 509 class _DiffCache(object): |
510 """Caches diffs retrieved from a particular SCM.""" | 510 """Caches diffs retrieved from a particular SCM.""" |
511 def __init__(self, upstream=None): | 511 def __init__(self, upstream=None, *args, **kwargs): |
512 """Stores the upstream revision against which all diffs will be computed.""" | 512 """Stores the upstream revision against which all diffs will be computed.""" |
513 self._upstream = upstream | 513 self._upstream = upstream |
514 | 514 |
515 def GetDiff(self, path, local_root): | 515 def GetDiff(self, path, local_root): |
516 """Get the diff for a particular path.""" | 516 """Get the diff for a particular path.""" |
517 raise NotImplementedError() | 517 raise NotImplementedError() |
518 | 518 |
519 | 519 |
520 class _SvnDiffCache(_DiffCache): | 520 class _SvnDiffCache(_DiffCache): |
521 """DiffCache implementation for subversion.""" | 521 """DiffCache implementation for subversion.""" |
522 def __init__(self, *args, **kwargs): | 522 def __init__(self, upstream=None, *args, **kwargs): |
523 super(_SvnDiffCache, self).__init__(*args, **kwargs) | 523 super(_SvnDiffCache, self).__init__(upstream, *args, **kwargs) |
524 self._diffs_by_file = {} | 524 self._diffs_by_file = {} |
525 | 525 |
526 def GetDiff(self, path, local_root): | 526 def GetDiff(self, path, local_root): |
527 if path not in self._diffs_by_file: | 527 if path not in self._diffs_by_file: |
528 self._diffs_by_file[path] = scm.SVN.GenerateDiff([path], local_root, | 528 self._diffs_by_file[path] = scm.SVN.GenerateDiff([path], local_root, |
529 False, None) | 529 False, None) |
530 return self._diffs_by_file[path] | 530 return self._diffs_by_file[path] |
531 | 531 |
532 | 532 |
533 class _GitDiffCache(_DiffCache): | 533 class _GitDiffCache(_DiffCache): |
534 """DiffCache implementation for git; gets all file diffs at once.""" | 534 """DiffCache implementation for git; gets all file diffs at once.""" |
535 def __init__(self, upstream): | 535 def __init__(self, upstream=None, *args, **kwargs): |
536 super(_GitDiffCache, self).__init__(upstream=upstream) | 536 super(_GitDiffCache, self).__init__(upstream, *args, **kwargs) |
537 self._diffs_by_file = None | 537 self._diffs_by_file = None |
| 538 self._local_ref = kwargs.get('local_ref', 'HEAD') |
538 | 539 |
539 def GetDiff(self, path, local_root): | 540 def GetDiff(self, path, local_root): |
540 if not self._diffs_by_file: | 541 if not self._diffs_by_file: |
541 # Compute a single diff for all files and parse the output; should | 542 # Compute a single diff for all files and parse the output; with git |
542 # with git this is much faster than computing one diff for each file. | 543 # this is much faster than computing one diff for each file. |
543 diffs = {} | 544 diffs = {} |
544 | 545 |
545 # Don't specify any filenames below, because there are command line length | 546 # Don't specify any filenames below, because there are command line length |
546 # limits on some platforms and GenerateDiff would fail. | 547 # limits on some platforms and GenerateDiff would fail. |
547 unified_diff = scm.GIT.GenerateDiff(local_root, files=[], full_move=True, | 548 unified_diff = scm.GIT.GenerateDiff(local_root, files=[], full_move=True, |
548 branch=self._upstream) | 549 branch=self._upstream, |
| 550 branch_head=self._local_ref) |
549 | 551 |
550 # This regex matches the path twice, separated by a space. Note that | 552 # This regex matches the path twice, separated by a space. Note that |
551 # filename itself may contain spaces. | 553 # filename itself may contain spaces. |
552 file_marker = re.compile('^diff --git (?P<filename>.*) (?P=filename)$') | 554 file_marker = re.compile('^diff --git (?P<filename>.*) (?P=filename)$') |
553 current_diff = [] | 555 current_diff = [] |
554 keep_line_endings = True | 556 keep_line_endings = True |
555 for x in unified_diff.splitlines(keep_line_endings): | 557 for x in unified_diff.splitlines(keep_line_endings): |
556 match = file_marker.match(x) | 558 match = file_marker.match(x) |
557 if match: | 559 if match: |
558 # Marks the start of a new per-file section. | 560 # Marks the start of a new per-file section. |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 | 797 |
796 _AFFECTED_FILES = AffectedFile | 798 _AFFECTED_FILES = AffectedFile |
797 | 799 |
798 # Matches key/value (or "tag") lines in changelist descriptions. | 800 # Matches key/value (or "tag") lines in changelist descriptions. |
799 TAG_LINE_RE = re.compile( | 801 TAG_LINE_RE = re.compile( |
800 '^[ \t]*(?P<key>[A-Z][A-Z_0-9]*)[ \t]*=[ \t]*(?P<value>.*?)[ \t]*$') | 802 '^[ \t]*(?P<key>[A-Z][A-Z_0-9]*)[ \t]*=[ \t]*(?P<value>.*?)[ \t]*$') |
801 scm = '' | 803 scm = '' |
802 | 804 |
803 def __init__( | 805 def __init__( |
804 self, name, description, local_root, files, issue, patchset, author, | 806 self, name, description, local_root, files, issue, patchset, author, |
805 upstream=None): | 807 upstream=None, local_ref='HEAD'): |
806 if files is None: | 808 if files is None: |
807 files = [] | 809 files = [] |
808 self._name = name | 810 self._name = name |
809 # Convert root into an absolute path. | 811 # Convert root into an absolute path. |
810 self._local_root = os.path.abspath(local_root) | 812 self._local_root = os.path.abspath(local_root) |
811 self._upstream = upstream | 813 self._upstream = upstream |
| 814 self._local_ref = local_ref |
812 self.issue = issue | 815 self.issue = issue |
813 self.patchset = patchset | 816 self.patchset = patchset |
814 self.author_email = author | 817 self.author_email = author |
815 | 818 |
816 self._full_description = '' | 819 self._full_description = '' |
817 self.tags = {} | 820 self.tags = {} |
818 self._description_without_tags = '' | 821 self._description_without_tags = '' |
819 self.SetDescriptionText(description) | 822 self.SetDescriptionText(description) |
820 | 823 |
821 assert all( | 824 assert all( |
822 (isinstance(f, (list, tuple)) and len(f) == 2) for f in files), files | 825 (isinstance(f, (list, tuple)) and len(f) == 2) for f in files), files |
823 | 826 |
824 diff_cache = self._AFFECTED_FILES.DIFF_CACHE(self._upstream) | 827 diff_cache = self._AFFECTED_FILES.DIFF_CACHE(self._upstream, |
| 828 local_ref=self._local_ref) |
825 self._affected_files = [ | 829 self._affected_files = [ |
826 self._AFFECTED_FILES(path, action.strip(), self._local_root, diff_cache) | 830 self._AFFECTED_FILES(path, action.strip(), self._local_root, diff_cache) |
827 for action, path in files | 831 for action, path in files |
828 ] | 832 ] |
829 | 833 |
830 def Name(self): | 834 def Name(self): |
831 """Returns the change name.""" | 835 """Returns the change name.""" |
832 return self._name | 836 return self._name |
833 | 837 |
834 def DescriptionText(self): | 838 def DescriptionText(self): |
(...skipping 892 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1727 return 2 | 1731 return 2 |
1728 | 1732 |
1729 | 1733 |
1730 if __name__ == '__main__': | 1734 if __name__ == '__main__': |
1731 fix_encoding.fix_encoding() | 1735 fix_encoding.fix_encoding() |
1732 try: | 1736 try: |
1733 sys.exit(main()) | 1737 sys.exit(main()) |
1734 except KeyboardInterrupt: | 1738 except KeyboardInterrupt: |
1735 sys.stderr.write('interrupted\n') | 1739 sys.stderr.write('interrupted\n') |
1736 sys.exit(1) | 1740 sys.exit(1) |
OLD | NEW |