| 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.2' | 9 __version__ = '1.3' |
| 10 | 10 |
| 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow | 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow |
| 12 # caching (between all different invocations of presubmit scripts for a given | 12 # caching (between all different invocations of presubmit scripts for a given |
| 13 # change). We should add it as our presubmit scripts start feeling slow. | 13 # change). We should add it as our presubmit scripts start feeling slow. |
| 14 | 14 |
| 15 import cPickle # Exposed through the API. | 15 import cPickle # Exposed through the API. |
| 16 import cStringIO # Exposed through the API. | 16 import cStringIO # Exposed through the API. |
| 17 import exceptions | 17 import exceptions |
| 18 import fnmatch | 18 import fnmatch |
| 19 import glob | 19 import glob |
| 20 import marshal # Exposed through the API. | 20 import marshal # Exposed through the API. |
| 21 import optparse | 21 import optparse |
| 22 import os # Somewhat exposed through the API. | 22 import os # Somewhat exposed through the API. |
| 23 import pickle # Exposed through the API. | 23 import pickle # Exposed through the API. |
| 24 import re # Exposed through the API. | 24 import re # Exposed through the API. |
| 25 import subprocess # Exposed through the API. | 25 import subprocess # Exposed through the API. |
| 26 import sys # Parts exposed through API. | 26 import sys # Parts exposed through API. |
| 27 import tempfile # Exposed through the API. | 27 import tempfile # Exposed through the API. |
| 28 import traceback # Exposed through the API. |
| 28 import types | 29 import types |
| 29 import unittest # Exposed through the API. | 30 import unittest # Exposed through the API. |
| 30 import urllib2 # Exposed through the API. | 31 import urllib2 # Exposed through the API. |
| 31 import warnings | 32 import warnings |
| 32 | 33 |
| 33 # Local imports. | 34 # Local imports. |
| 34 # TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but | 35 # TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but |
| 35 # for now it would only be a couple of functions so hardly worth it. | 36 # for now it would only be a couple of functions so hardly worth it. |
| 36 import gcl | 37 import gcl |
| 37 import gclient | 38 import gclient |
| (...skipping 11 matching lines...) Expand all Loading... |
| 49 def normpath(path): | 50 def normpath(path): |
| 50 '''Version of os.path.normpath that also changes backward slashes to | 51 '''Version of os.path.normpath that also changes backward slashes to |
| 51 forward slashes when not running on Windows. | 52 forward slashes when not running on Windows. |
| 52 ''' | 53 ''' |
| 53 # This is safe to always do because the Windows version of os.path.normpath | 54 # This is safe to always do because the Windows version of os.path.normpath |
| 54 # will replace forward slashes with backward slashes. | 55 # will replace forward slashes with backward slashes. |
| 55 path = path.replace(os.sep, '/') | 56 path = path.replace(os.sep, '/') |
| 56 return os.path.normpath(path) | 57 return os.path.normpath(path) |
| 57 | 58 |
| 58 | 59 |
| 59 def deprecated(func): | |
| 60 """This is a decorator which can be used to mark functions as deprecated. | |
| 61 | |
| 62 It will result in a warning being emmitted when the function is used.""" | |
| 63 def newFunc(*args, **kwargs): | |
| 64 warnings.warn("Call to deprecated function %s." % func.__name__, | |
| 65 category=DeprecationWarning, | |
| 66 stacklevel=2) | |
| 67 return func(*args, **kwargs) | |
| 68 newFunc.__name__ = func.__name__ | |
| 69 newFunc.__doc__ = func.__doc__ | |
| 70 newFunc.__dict__.update(func.__dict__) | |
| 71 return newFunc | |
| 72 | |
| 73 | |
| 74 class OutputApi(object): | 60 class OutputApi(object): |
| 75 """This class (more like a module) gets passed to presubmit scripts so that | 61 """This class (more like a module) gets passed to presubmit scripts so that |
| 76 they can specify various types of results. | 62 they can specify various types of results. |
| 77 """ | 63 """ |
| 78 | 64 |
| 79 class PresubmitResult(object): | 65 class PresubmitResult(object): |
| 80 """Base class for result objects.""" | 66 """Base class for result objects.""" |
| 81 | 67 |
| 82 def __init__(self, message, items=None, long_text=''): | 68 def __init__(self, message, items=None, long_text=''): |
| 83 """ | 69 """ |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 """A warning that should be included in the review request email.""" | 130 """A warning that should be included in the review request email.""" |
| 145 def __init__(self, *args, **kwargs): | 131 def __init__(self, *args, **kwargs): |
| 146 raise NotImplementedException() # TODO(joi) Implement. | 132 raise NotImplementedException() # TODO(joi) Implement. |
| 147 | 133 |
| 148 | 134 |
| 149 class InputApi(object): | 135 class InputApi(object): |
| 150 """An instance of this object is passed to presubmit scripts so they can | 136 """An instance of this object is passed to presubmit scripts so they can |
| 151 know stuff about the change they're looking at. | 137 know stuff about the change they're looking at. |
| 152 """ | 138 """ |
| 153 | 139 |
| 154 def __init__(self, change, presubmit_path): | 140 def __init__(self, change, presubmit_path, is_committing): |
| 155 """Builds an InputApi object. | 141 """Builds an InputApi object. |
| 156 | 142 |
| 157 Args: | 143 Args: |
| 158 change: A presubmit.GclChange object. | 144 change: A presubmit.GclChange object. |
| 159 presubmit_path: The path to the presubmit script being processed. | 145 presubmit_path: The path to the presubmit script being processed. |
| 146 is_committing: True if the change is about to be committed. |
| 160 """ | 147 """ |
| 161 # Version number of the presubmit_support script. | 148 # Version number of the presubmit_support script. |
| 162 self.version = [int(x) for x in __version__.split('.')] | 149 self.version = [int(x) for x in __version__.split('.')] |
| 163 self.change = change | 150 self.change = change |
| 151 self.is_committing = is_committing |
| 164 | 152 |
| 165 # We expose various modules and functions as attributes of the input_api | 153 # We expose various modules and functions as attributes of the input_api |
| 166 # so that presubmit scripts don't have to import them. | 154 # so that presubmit scripts don't have to import them. |
| 167 self.basename = os.path.basename | 155 self.basename = os.path.basename |
| 168 self.cPickle = cPickle | 156 self.cPickle = cPickle |
| 169 self.cStringIO = cStringIO | 157 self.cStringIO = cStringIO |
| 170 self.os_path = os.path | 158 self.os_path = os.path |
| 171 self.pickle = pickle | 159 self.pickle = pickle |
| 172 self.marshal = marshal | 160 self.marshal = marshal |
| 173 self.re = re | 161 self.re = re |
| 174 self.subprocess = subprocess | 162 self.subprocess = subprocess |
| 175 self.tempfile = tempfile | 163 self.tempfile = tempfile |
| 164 self.traceback = traceback |
| 176 self.unittest = unittest | 165 self.unittest = unittest |
| 177 self.urllib2 = urllib2 | 166 self.urllib2 = urllib2 |
| 178 | 167 |
| 179 # InputApi.platform is the platform you're currently running on. | 168 # InputApi.platform is the platform you're currently running on. |
| 180 self.platform = sys.platform | 169 self.platform = sys.platform |
| 181 | 170 |
| 182 # The local path of the currently-being-processed presubmit script. | 171 # The local path of the currently-being-processed presubmit script. |
| 183 self._current_presubmit_path = os.path.dirname(presubmit_path) | 172 self._current_presubmit_path = os.path.dirname(presubmit_path) |
| 184 | 173 |
| 185 # We carry the canned checks so presubmit scripts can easily use them. | 174 # We carry the canned checks so presubmit scripts can easily use them. |
| (...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 """Executes a single presubmit script. | 585 """Executes a single presubmit script. |
| 597 | 586 |
| 598 Args: | 587 Args: |
| 599 script_text: The text of the presubmit script. | 588 script_text: The text of the presubmit script. |
| 600 presubmit_path: The path to the presubmit file (this will be reported via | 589 presubmit_path: The path to the presubmit file (this will be reported via |
| 601 input_api.PresubmitLocalPath()). | 590 input_api.PresubmitLocalPath()). |
| 602 | 591 |
| 603 Return: | 592 Return: |
| 604 A list of result objects, empty if no problems. | 593 A list of result objects, empty if no problems. |
| 605 """ | 594 """ |
| 606 input_api = InputApi(self.change, presubmit_path) | 595 input_api = InputApi(self.change, presubmit_path, self.committing) |
| 607 context = {} | 596 context = {} |
| 608 exec script_text in context | 597 exec script_text in context |
| 609 | 598 |
| 610 # These function names must change if we make substantial changes to | 599 # These function names must change if we make substantial changes to |
| 611 # the presubmit API that are not backwards compatible. | 600 # the presubmit API that are not backwards compatible. |
| 612 if self.committing: | 601 if self.committing: |
| 613 function_name = 'CheckChangeOnCommit' | 602 function_name = 'CheckChangeOnCommit' |
| 614 else: | 603 else: |
| 615 function_name = 'CheckChangeOnUpload' | 604 function_name = 'CheckChangeOnUpload' |
| 616 if function_name in context: | 605 if function_name in context: |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 return not DoPresubmitChecks(gcl.ChangeInfo(name='temp', files=files), | 734 return not DoPresubmitChecks(gcl.ChangeInfo(name='temp', files=files), |
| 746 options.commit, | 735 options.commit, |
| 747 options.verbose, | 736 options.verbose, |
| 748 sys.stdout, | 737 sys.stdout, |
| 749 sys.stdin, | 738 sys.stdin, |
| 750 default_presubmit=None) | 739 default_presubmit=None) |
| 751 | 740 |
| 752 | 741 |
| 753 if __name__ == '__main__': | 742 if __name__ == '__main__': |
| 754 sys.exit(Main(sys.argv)) | 743 sys.exit(Main(sys.argv)) |
| OLD | NEW |