| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 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.5' | 9 __version__ = '1.3.5' |
| 10 | 10 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 import urllib2 # Exposed through the API. | 34 import urllib2 # Exposed through the API. |
| 35 from warnings import warn | 35 from warnings import warn |
| 36 | 36 |
| 37 try: | 37 try: |
| 38 import simplejson as json | 38 import simplejson as json |
| 39 except ImportError: | 39 except ImportError: |
| 40 try: | 40 try: |
| 41 import json | 41 import json |
| 42 # Some versions of python2.5 have an incomplete json module. Check to make | 42 # Some versions of python2.5 have an incomplete json module. Check to make |
| 43 # sure loads exists. | 43 # sure loads exists. |
| 44 # Statement seems to have no effect |
| 45 # pylint: disable=W0104 |
| 44 json.loads | 46 json.loads |
| 45 except (ImportError, AttributeError): | 47 except (ImportError, AttributeError): |
| 46 # Import the one included in depot_tools. | 48 # Import the one included in depot_tools. |
| 47 sys.path.append(os.path.join(os.path.dirname(__file__), 'third_party')) | 49 sys.path.append(os.path.join(os.path.dirname(__file__), 'third_party')) |
| 48 import simplejson as json | 50 import simplejson as json |
| 49 | 51 |
| 50 # Local imports. | 52 # Local imports. |
| 51 import gclient_utils | 53 import gclient_utils |
| 52 import presubmit_canned_checks | 54 import presubmit_canned_checks |
| 53 import scm | 55 import scm |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 line_number = 0 | 90 line_number = 0 |
| 89 for line in lines: | 91 for line in lines: |
| 90 line_number += 1 | 92 line_number += 1 |
| 91 yield (af, line_number, line) | 93 yield (af, line_number, line) |
| 92 | 94 |
| 93 | 95 |
| 94 class OutputApi(object): | 96 class OutputApi(object): |
| 95 """This class (more like a module) gets passed to presubmit scripts so that | 97 """This class (more like a module) gets passed to presubmit scripts so that |
| 96 they can specify various types of results. | 98 they can specify various types of results. |
| 97 """ | 99 """ |
| 98 | 100 # Method could be a function |
| 101 # pylint: disable=R0201 |
| 99 class PresubmitResult(object): | 102 class PresubmitResult(object): |
| 100 """Base class for result objects.""" | 103 """Base class for result objects.""" |
| 101 | 104 |
| 102 def __init__(self, message, items=None, long_text=''): | 105 def __init__(self, message, items=None, long_text=''): |
| 103 """ | 106 """ |
| 104 message: A short one-line message to indicate errors. | 107 message: A short one-line message to indicate errors. |
| 105 items: A list of short strings to indicate where errors occurred. | 108 items: A list of short strings to indicate where errors occurred. |
| 106 long_text: multi-line text output, e.g. from another tool | 109 long_text: multi-line text output, e.g. from another tool |
| 107 """ | 110 """ |
| 108 self._message = message | 111 self._message = message |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 """A warning that should be included in the review request email.""" | 173 """A warning that should be included in the review request email.""" |
| 171 def __init__(self, *args, **kwargs): | 174 def __init__(self, *args, **kwargs): |
| 172 super(OutputApi.MailTextResult, self).__init__() | 175 super(OutputApi.MailTextResult, self).__init__() |
| 173 raise NotImplementedException() | 176 raise NotImplementedException() |
| 174 | 177 |
| 175 | 178 |
| 176 class InputApi(object): | 179 class InputApi(object): |
| 177 """An instance of this object is passed to presubmit scripts so they can | 180 """An instance of this object is passed to presubmit scripts so they can |
| 178 know stuff about the change they're looking at. | 181 know stuff about the change they're looking at. |
| 179 """ | 182 """ |
| 183 # Method could be a function |
| 184 # pylint: disable=R0201 |
| 180 | 185 |
| 181 # File extensions that are considered source files from a style guide | 186 # File extensions that are considered source files from a style guide |
| 182 # perspective. Don't modify this list from a presubmit script! | 187 # perspective. Don't modify this list from a presubmit script! |
| 183 DEFAULT_WHITE_LIST = ( | 188 DEFAULT_WHITE_LIST = ( |
| 184 # C++ and friends | 189 # C++ and friends |
| 185 r".*\.c$", r".*\.cc$", r".*\.cpp$", r".*\.h$", r".*\.m$", r".*\.mm$", | 190 r".*\.c$", r".*\.cc$", r".*\.cpp$", r".*\.h$", r".*\.m$", r".*\.mm$", |
| 186 r".*\.inl$", r".*\.asm$", r".*\.hxx$", r".*\.hpp$", | 191 r".*\.inl$", r".*\.asm$", r".*\.hxx$", r".*\.hpp$", |
| 187 # Scripts | 192 # Scripts |
| 188 r".*\.js$", r".*\.py$", r".*\.sh$", r".*\.rb$", r".*\.pl$", r".*\.pm$", | 193 r".*\.js$", r".*\.py$", r".*\.sh$", r".*\.rb$", r".*\.pl$", r".*\.pm$", |
| 189 # No extension at all, note that ALL CAPS files are black listed in | 194 # No extension at all, note that ALL CAPS files are black listed in |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 """ | 390 """ |
| 386 if isinstance(file_item, AffectedFile): | 391 if isinstance(file_item, AffectedFile): |
| 387 file_item = file_item.AbsoluteLocalPath() | 392 file_item = file_item.AbsoluteLocalPath() |
| 388 if not file_item.startswith(self.change.RepositoryRoot()): | 393 if not file_item.startswith(self.change.RepositoryRoot()): |
| 389 raise IOError('Access outside the repository root is denied.') | 394 raise IOError('Access outside the repository root is denied.') |
| 390 return gclient_utils.FileRead(file_item, mode) | 395 return gclient_utils.FileRead(file_item, mode) |
| 391 | 396 |
| 392 | 397 |
| 393 class AffectedFile(object): | 398 class AffectedFile(object): |
| 394 """Representation of a file in a change.""" | 399 """Representation of a file in a change.""" |
| 395 | 400 # Method could be a function |
| 401 # pylint: disable=R0201 |
| 396 def __init__(self, path, action, repository_root=''): | 402 def __init__(self, path, action, repository_root=''): |
| 397 self._path = path | 403 self._path = path |
| 398 self._action = action | 404 self._action = action |
| 399 self._local_root = repository_root | 405 self._local_root = repository_root |
| 400 self._is_directory = None | 406 self._is_directory = None |
| 401 self._properties = {} | 407 self._properties = {} |
| 402 | 408 |
| 403 def ServerPath(self): | 409 def ServerPath(self): |
| 404 """Returns a path string that identifies the file in the SCM system. | 410 """Returns a path string that identifies the file in the SCM system. |
| 405 | 411 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 modify this file. | 479 modify this file. |
| 474 """ | 480 """ |
| 475 raise NotImplementedError() # Implement if/when needed. | 481 raise NotImplementedError() # Implement if/when needed. |
| 476 | 482 |
| 477 def __str__(self): | 483 def __str__(self): |
| 478 return self.LocalPath() | 484 return self.LocalPath() |
| 479 | 485 |
| 480 | 486 |
| 481 class SvnAffectedFile(AffectedFile): | 487 class SvnAffectedFile(AffectedFile): |
| 482 """Representation of a file in a change out of a Subversion checkout.""" | 488 """Representation of a file in a change out of a Subversion checkout.""" |
| 489 # Method 'NNN' is abstract in class 'NNN' but is not overridden |
| 490 # pylint: disable=W0223 |
| 483 | 491 |
| 484 def __init__(self, *args, **kwargs): | 492 def __init__(self, *args, **kwargs): |
| 485 AffectedFile.__init__(self, *args, **kwargs) | 493 AffectedFile.__init__(self, *args, **kwargs) |
| 486 self._server_path = None | 494 self._server_path = None |
| 487 self._is_text_file = None | 495 self._is_text_file = None |
| 488 | 496 |
| 489 def ServerPath(self): | 497 def ServerPath(self): |
| 490 if self._server_path is None: | 498 if self._server_path is None: |
| 491 self._server_path = scm.SVN.CaptureInfo( | 499 self._server_path = scm.SVN.CaptureInfo( |
| 492 self.AbsoluteLocalPath()).get('URL', '') | 500 self.AbsoluteLocalPath()).get('URL', '') |
| (...skipping 26 matching lines...) Expand all Loading... |
| 519 self._is_text_file = False | 527 self._is_text_file = False |
| 520 else: | 528 else: |
| 521 mime_type = scm.SVN.GetFileProperty(self.AbsoluteLocalPath(), | 529 mime_type = scm.SVN.GetFileProperty(self.AbsoluteLocalPath(), |
| 522 'svn:mime-type') | 530 'svn:mime-type') |
| 523 self._is_text_file = (not mime_type or mime_type.startswith('text/')) | 531 self._is_text_file = (not mime_type or mime_type.startswith('text/')) |
| 524 return self._is_text_file | 532 return self._is_text_file |
| 525 | 533 |
| 526 | 534 |
| 527 class GitAffectedFile(AffectedFile): | 535 class GitAffectedFile(AffectedFile): |
| 528 """Representation of a file in a change out of a git checkout.""" | 536 """Representation of a file in a change out of a git checkout.""" |
| 537 # Method 'NNN' is abstract in class 'NNN' but is not overridden |
| 538 # pylint: disable=W0223 |
| 529 | 539 |
| 530 def __init__(self, *args, **kwargs): | 540 def __init__(self, *args, **kwargs): |
| 531 AffectedFile.__init__(self, *args, **kwargs) | 541 AffectedFile.__init__(self, *args, **kwargs) |
| 532 self._server_path = None | 542 self._server_path = None |
| 533 self._is_text_file = None | 543 self._is_text_file = None |
| 534 | 544 |
| 535 def ServerPath(self): | 545 def ServerPath(self): |
| 536 if self._server_path is None: | 546 if self._server_path is None: |
| 537 raise NotImplementedException() # TODO(maruel) Implement. | 547 raise NotImplementedException() # TODO(maruel) Implement. |
| 538 return self._server_path | 548 return self._server_path |
| (...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 989 else: | 999 else: |
| 990 errors.append(result) | 1000 errors.append(result) |
| 991 | 1001 |
| 992 error_count = 0 | 1002 error_count = 0 |
| 993 for name, items in (('Messages', notifications), | 1003 for name, items in (('Messages', notifications), |
| 994 ('Warnings', warnings), | 1004 ('Warnings', warnings), |
| 995 ('ERRORS', errors)): | 1005 ('ERRORS', errors)): |
| 996 if items: | 1006 if items: |
| 997 output_stream.write('** Presubmit %s **\n' % name) | 1007 output_stream.write('** Presubmit %s **\n' % name) |
| 998 for item in items: | 1008 for item in items: |
| 1009 # Access to a protected member XXX of a client class |
| 1010 # pylint: disable=W0212 |
| 999 if not item._Handle(output_stream, input_stream, | 1011 if not item._Handle(output_stream, input_stream, |
| 1000 may_prompt=False): | 1012 may_prompt=False): |
| 1001 error_count += 1 | 1013 error_count += 1 |
| 1002 output_stream.write('\n') | 1014 output_stream.write('\n') |
| 1003 | 1015 |
| 1004 total_time = time.time() - start_time | 1016 total_time = time.time() - start_time |
| 1005 if total_time > 1.0: | 1017 if total_time > 1.0: |
| 1006 print "Presubmit checks took %.1fs to calculate." % total_time | 1018 print "Presubmit checks took %.1fs to calculate." % total_time |
| 1007 | 1019 |
| 1008 if not errors and warnings and may_prompt: | 1020 if not errors and warnings and may_prompt: |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1100 options.commit, | 1112 options.commit, |
| 1101 options.verbose, | 1113 options.verbose, |
| 1102 sys.stdout, | 1114 sys.stdout, |
| 1103 sys.stdin, | 1115 sys.stdin, |
| 1104 options.default_presubmit, | 1116 options.default_presubmit, |
| 1105 options.may_prompt) | 1117 options.may_prompt) |
| 1106 | 1118 |
| 1107 | 1119 |
| 1108 if __name__ == '__main__': | 1120 if __name__ == '__main__': |
| 1109 sys.exit(Main(sys.argv)) | 1121 sys.exit(Main(sys.argv)) |
| OLD | NEW |