| 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 |