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 |