| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 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.3.2' | 9 __version__ = '1.3.2' |
| 10 | 10 |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 return "" | 382 return "" |
| 383 | 383 |
| 384 def LocalPath(self): | 384 def LocalPath(self): |
| 385 """Returns the path of this file on the local disk relative to client root. | 385 """Returns the path of this file on the local disk relative to client root. |
| 386 """ | 386 """ |
| 387 return normpath(self._path) | 387 return normpath(self._path) |
| 388 | 388 |
| 389 def AbsoluteLocalPath(self): | 389 def AbsoluteLocalPath(self): |
| 390 """Returns the absolute path of this file on the local disk. | 390 """Returns the absolute path of this file on the local disk. |
| 391 """ | 391 """ |
| 392 return normpath(os.path.join(self._local_root, self.LocalPath())) | 392 return os.path.abspath(os.path.join(self._local_root, self.LocalPath())) |
| 393 | 393 |
| 394 def IsDirectory(self): | 394 def IsDirectory(self): |
| 395 """Returns true if this object is a directory.""" | 395 """Returns true if this object is a directory.""" |
| 396 if self._is_directory is None: | 396 if self._is_directory is None: |
| 397 path = self.AbsoluteLocalPath() | 397 path = self.AbsoluteLocalPath() |
| 398 self._is_directory = (os.path.exists(path) and | 398 self._is_directory = (os.path.exists(path) and |
| 399 os.path.isdir(path)) | 399 os.path.isdir(path)) |
| 400 return self._is_directory | 400 return self._is_directory |
| 401 | 401 |
| 402 def Action(self): | 402 def Action(self): |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 | 555 |
| 556 # Matches key/value (or "tag") lines in changelist descriptions. | 556 # Matches key/value (or "tag") lines in changelist descriptions. |
| 557 _TAG_LINE_RE = re.compile( | 557 _TAG_LINE_RE = re.compile( |
| 558 '^\s*(?P<key>[A-Z][A-Z_0-9]*)\s*=\s*(?P<value>.*?)\s*$') | 558 '^\s*(?P<key>[A-Z][A-Z_0-9]*)\s*=\s*(?P<value>.*?)\s*$') |
| 559 | 559 |
| 560 def __init__(self, name, description, local_root, files, issue, patchset): | 560 def __init__(self, name, description, local_root, files, issue, patchset): |
| 561 if files is None: | 561 if files is None: |
| 562 files = [] | 562 files = [] |
| 563 self._name = name | 563 self._name = name |
| 564 self._full_description = description | 564 self._full_description = description |
| 565 self._local_root = local_root | 565 # Convert root into an absolute path. |
| 566 self._local_root = os.path.abspath(local_root) |
| 566 self.issue = issue | 567 self.issue = issue |
| 567 self.patchset = patchset | 568 self.patchset = patchset |
| 568 self.scm = '' | 569 self.scm = '' |
| 569 | 570 |
| 570 # From the description text, build up a dictionary of key/value pairs | 571 # From the description text, build up a dictionary of key/value pairs |
| 571 # plus the description minus all key/value or "tag" lines. | 572 # plus the description minus all key/value or "tag" lines. |
| 572 self._description_without_tags = [] | 573 self._description_without_tags = [] |
| 573 self.tags = {} | 574 self.tags = {} |
| 574 for line in self._full_description.splitlines(): | 575 for line in self._full_description.splitlines(): |
| 575 m = self._TAG_LINE_RE.match(line) | 576 m = self._TAG_LINE_RE.match(line) |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 """Executes a single presubmit script. | 758 """Executes a single presubmit script. |
| 758 | 759 |
| 759 Args: | 760 Args: |
| 760 script_text: The text of the presubmit script. | 761 script_text: The text of the presubmit script. |
| 761 presubmit_path: The path to the presubmit file (this will be reported via | 762 presubmit_path: The path to the presubmit file (this will be reported via |
| 762 input_api.PresubmitLocalPath()). | 763 input_api.PresubmitLocalPath()). |
| 763 | 764 |
| 764 Return: | 765 Return: |
| 765 A list of result objects, empty if no problems. | 766 A list of result objects, empty if no problems. |
| 766 """ | 767 """ |
| 768 |
| 769 # Change to the presubmit file's directory to support local imports. |
| 770 main_path = os.getcwd() |
| 771 os.chdir(os.path.dirname(presubmit_path)) |
| 772 |
| 773 # Load the presubmit script into context. |
| 767 input_api = InputApi(self.change, presubmit_path, self.committing) | 774 input_api = InputApi(self.change, presubmit_path, self.committing) |
| 768 context = {} | 775 context = {} |
| 769 exec script_text in context | 776 exec script_text in context |
| 770 | 777 |
| 771 # These function names must change if we make substantial changes to | 778 # These function names must change if we make substantial changes to |
| 772 # the presubmit API that are not backwards compatible. | 779 # the presubmit API that are not backwards compatible. |
| 773 if self.committing: | 780 if self.committing: |
| 774 function_name = 'CheckChangeOnCommit' | 781 function_name = 'CheckChangeOnCommit' |
| 775 else: | 782 else: |
| 776 function_name = 'CheckChangeOnUpload' | 783 function_name = 'CheckChangeOnUpload' |
| 777 if function_name in context: | 784 if function_name in context: |
| 778 context['__args'] = (input_api, OutputApi()) | 785 context['__args'] = (input_api, OutputApi()) |
| 779 result = eval(function_name + '(*__args)', context) | 786 result = eval(function_name + '(*__args)', context) |
| 780 if not (isinstance(result, types.TupleType) or | 787 if not (isinstance(result, types.TupleType) or |
| 781 isinstance(result, types.ListType)): | 788 isinstance(result, types.ListType)): |
| 782 raise exceptions.RuntimeError( | 789 raise exceptions.RuntimeError( |
| 783 'Presubmit functions must return a tuple or list') | 790 'Presubmit functions must return a tuple or list') |
| 784 for item in result: | 791 for item in result: |
| 785 if not isinstance(item, OutputApi.PresubmitResult): | 792 if not isinstance(item, OutputApi.PresubmitResult): |
| 786 raise exceptions.RuntimeError( | 793 raise exceptions.RuntimeError( |
| 787 'All presubmit results must be of types derived from ' | 794 'All presubmit results must be of types derived from ' |
| 788 'output_api.PresubmitResult') | 795 'output_api.PresubmitResult') |
| 789 else: | 796 else: |
| 790 result = () # no error since the script doesn't care about current event. | 797 result = () # no error since the script doesn't care about current event. |
| 791 | 798 |
| 799 # Return the process to the original working directory. |
| 800 os.chdir(main_path) |
| 792 return result | 801 return result |
| 793 | 802 |
| 794 | 803 |
| 795 def DoPresubmitChecks(change, | 804 def DoPresubmitChecks(change, |
| 796 committing, | 805 committing, |
| 797 verbose, | 806 verbose, |
| 798 output_stream, | 807 output_stream, |
| 799 input_stream, | 808 input_stream, |
| 800 default_presubmit, | 809 default_presubmit, |
| 801 may_prompt): | 810 may_prompt): |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 options, args = parser.parse_args(argv[1:]) | 941 options, args = parser.parse_args(argv[1:]) |
| 933 if not options.root: | 942 if not options.root: |
| 934 options.root = os.getcwd() | 943 options.root = os.getcwd() |
| 935 if os.path.isdir(os.path.join(options.root, '.git')): | 944 if os.path.isdir(os.path.join(options.root, '.git')): |
| 936 change_class = GitChange | 945 change_class = GitChange |
| 937 if not options.files: | 946 if not options.files: |
| 938 if args: | 947 if args: |
| 939 options.files = ParseFiles(args, options.recursive) | 948 options.files = ParseFiles(args, options.recursive) |
| 940 else: | 949 else: |
| 941 # Grab modified files. | 950 # Grab modified files. |
| 942 raise NotImplementedException() # TODO(maruel) Implement. | 951 options.files = gclient_scm.CaptureGitStatus([options.root]) |
| 943 elif os.path.isdir(os.path.join(options.root, '.svn')): | 952 elif os.path.isdir(os.path.join(options.root, '.svn')): |
| 944 change_class = SvnChange | 953 change_class = SvnChange |
| 945 if not options.files: | 954 if not options.files: |
| 946 if args: | 955 if args: |
| 947 options.files = ParseFiles(args, options.recursive) | 956 options.files = ParseFiles(args, options.recursive) |
| 948 else: | 957 else: |
| 949 # Grab modified files. | 958 # Grab modified files. |
| 950 files = gclient_scm.CaptureSVNStatus([options.root]) | 959 options.files = gclient_scm.CaptureSVNStatus([options.root]) |
| 951 else: | 960 else: |
| 952 # Doesn't seem under source control. | 961 # Doesn't seem under source control. |
| 953 change_class = Change | 962 change_class = Change |
| 954 if options.verbose: | 963 if options.verbose: |
| 955 print "Found %d files." % len(options.files) | 964 if len(options.files) != 1: |
| 965 print "Found %d files." % len(options.files) |
| 966 else: |
| 967 print "Found 1 file." |
| 956 return not DoPresubmitChecks(change_class(options.name, | 968 return not DoPresubmitChecks(change_class(options.name, |
| 957 options.description, | 969 options.description, |
| 958 options.root, | 970 options.root, |
| 959 options.files, | 971 options.files, |
| 960 options.issue, | 972 options.issue, |
| 961 options.patchset), | 973 options.patchset), |
| 962 options.commit, | 974 options.commit, |
| 963 options.verbose, | 975 options.verbose, |
| 964 sys.stdout, | 976 sys.stdout, |
| 965 sys.stdin, | 977 sys.stdin, |
| 966 options.default_presubmit, | 978 options.default_presubmit, |
| 967 options.may_prompt) | 979 options.may_prompt) |
| 968 | 980 |
| 969 | 981 |
| 970 if __name__ == '__main__': | 982 if __name__ == '__main__': |
| 971 sys.exit(Main(sys.argv)) | 983 sys.exit(Main(sys.argv)) |
| OLD | NEW |