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.1' | 9 __version__ = '1.3.1' |
10 | 10 |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 """A warning that should be included in the review request email.""" | 130 """A warning that should be included in the review request email.""" |
131 def __init__(self, *args, **kwargs): | 131 def __init__(self, *args, **kwargs): |
132 raise NotImplementedException() # TODO(joi) Implement. | 132 raise NotImplementedException() # TODO(joi) Implement. |
133 | 133 |
134 | 134 |
135 class InputApi(object): | 135 class InputApi(object): |
136 """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 |
137 know stuff about the change they're looking at. | 137 know stuff about the change they're looking at. |
138 """ | 138 """ |
139 | 139 |
| 140 # File extensions that are considered source files from a style guide |
| 141 # perspective. Don't modify this list from a presubmit script! |
| 142 DEFAULT_WHITE_LIST = [ |
| 143 # C++ and friends |
| 144 r".*\.c", r".*\.cc", r".*\.cpp", r".*\.h", r".*\.m", r".*\.mm", |
| 145 r".*\.inl", r".*\.asm", r".*\.hxx", r".*\.hpp", |
| 146 # Scripts |
| 147 r".*\.js", r".*\.py", r".*\.json", r".*\.sh", r".*\.rb", |
| 148 # No extension at all |
| 149 r"(^|.*[\\\/])[^.]+$", |
| 150 # Other |
| 151 r".*\.java", r".*\.mk", r".*\.am", |
| 152 ] |
| 153 |
| 154 # Path regexp that should be excluded from being considered containing source |
| 155 # files. Don't modify this list from a presubmit script! |
| 156 DEFAULT_BLACK_LIST = [ |
| 157 r".*\bexperimental[\\\/].*", |
| 158 r".*\bthird_party[\\\/].*", |
| 159 # Output directories (just in case) |
| 160 r".*\bDebug[\\\/].*", |
| 161 r".*\bRelease[\\\/].*", |
| 162 r".*\bxcodebuild[\\\/].*", |
| 163 r".*\bsconsbuild[\\\/].*", |
| 164 # All caps files like README and LICENCE. |
| 165 r".*\b[A-Z0-9_]+", |
| 166 # SCM (can happen in dual SCM configuration) |
| 167 r".*\b\.git[\\\/].*", |
| 168 r".*\b\.svn[\\\/].*", |
| 169 ] |
| 170 |
140 def __init__(self, change, presubmit_path, is_committing): | 171 def __init__(self, change, presubmit_path, is_committing): |
141 """Builds an InputApi object. | 172 """Builds an InputApi object. |
142 | 173 |
143 Args: | 174 Args: |
144 change: A presubmit.GclChange object. | 175 change: A presubmit.GclChange object. |
145 presubmit_path: The path to the presubmit script being processed. | 176 presubmit_path: The path to the presubmit script being processed. |
146 is_committing: True if the change is about to be committed. | 177 is_committing: True if the change is about to be committed. |
147 """ | 178 """ |
148 # Version number of the presubmit_support script. | 179 # Version number of the presubmit_support script. |
149 self.version = [int(x) for x in __version__.split('.')] | 180 self.version = [int(x) for x in __version__.split('.')] |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 thereof. | 274 thereof. |
244 """ | 275 """ |
245 if include_deletes is not None: | 276 if include_deletes is not None: |
246 warnings.warn("AffectedTextFiles(include_deletes=%s)" | 277 warnings.warn("AffectedTextFiles(include_deletes=%s)" |
247 " is deprecated and ignored" % str(include_deletes), | 278 " is deprecated and ignored" % str(include_deletes), |
248 category=DeprecationWarning, | 279 category=DeprecationWarning, |
249 stacklevel=2) | 280 stacklevel=2) |
250 return filter(lambda x: x.IsTextFile(), | 281 return filter(lambda x: x.IsTextFile(), |
251 self.AffectedFiles(include_dirs=False, include_deletes=False)) | 282 self.AffectedFiles(include_dirs=False, include_deletes=False)) |
252 | 283 |
253 def RightHandSideLines(self): | 284 def FilterSourceFile(self, affected_file, white_list=None, black_list=None): |
| 285 """Filters out files that aren't considered "source file". |
| 286 |
| 287 If white_list or black_list is None, InputApi.DEFAULT_WHITE_LIST |
| 288 and InputApi.DEFAULT_BLACK_LIST is used respectively. |
| 289 |
| 290 The lists will be compiled as regular expression and |
| 291 AffectedFile.LocalPath() needs to pass both list. |
| 292 |
| 293 Note: Copy-paste this function to suit your needs or use a lambda function. |
| 294 """ |
| 295 def Find(affected_file, list): |
| 296 for item in list: |
| 297 if self.re.match(item, affected_file.LocalPath()): |
| 298 return True |
| 299 return False |
| 300 return (Find(affected_file, white_list or self.DEFAULT_WHITE_LIST) and |
| 301 not Find(affected_file, black_list or self.DEFAULT_BLACK_LIST)) |
| 302 |
| 303 def AffectedSourceFiles(self, source_file): |
| 304 """Filter the list of AffectedTextFiles by the function source_file. |
| 305 |
| 306 If source_file is None, InputApi.FilterSourceFile() is used. |
| 307 """ |
| 308 if not source_file: |
| 309 source_file = self.FilterSourceFile |
| 310 return filter(source_file, self.AffectedTextFiles()) |
| 311 |
| 312 def RightHandSideLines(self, source_file_filter=None): |
254 """An iterator over all text lines in "new" version of changed files. | 313 """An iterator over all text lines in "new" version of changed files. |
255 | 314 |
256 Only lists lines from new or modified text files in the change that are | 315 Only lists lines from new or modified text files in the change that are |
257 contained by the directory of the currently executing presubmit script. | 316 contained by the directory of the currently executing presubmit script. |
258 | 317 |
259 This is useful for doing line-by-line regex checks, like checking for | 318 This is useful for doing line-by-line regex checks, like checking for |
260 trailing whitespace. | 319 trailing whitespace. |
261 | 320 |
262 Yields: | 321 Yields: |
263 a 3 tuple: | 322 a 3 tuple: |
264 the AffectedFile instance of the current file; | 323 the AffectedFile instance of the current file; |
265 integer line number (1-based); and | 324 integer line number (1-based); and |
266 the contents of the line as a string. | 325 the contents of the line as a string. |
267 | 326 |
268 Note: The cariage return (LF or CR) is stripped off. | 327 Note: The cariage return (LF or CR) is stripped off. |
269 """ | 328 """ |
270 return InputApi._RightHandSideLinesImpl( | 329 files = self.AffectedSourceFiles(source_file_filter) |
271 filter(lambda x: x.IsTextFile(), | 330 return InputApi._RightHandSideLinesImpl(files) |
272 self.AffectedFiles(include_deletes=False))) | |
273 | 331 |
274 def ReadFile(self, file, mode='r'): | 332 def ReadFile(self, file, mode='r'): |
275 """Reads an arbitrary file. | 333 """Reads an arbitrary file. |
276 | 334 |
277 Deny reading anything outside the repository. | 335 Deny reading anything outside the repository. |
278 """ | 336 """ |
279 if isinstance(file, AffectedFile): | 337 if isinstance(file, AffectedFile): |
280 file = file.AbsoluteLocalPath() | 338 file = file.AbsoluteLocalPath() |
281 if not file.startswith(self.change.RepositoryRoot()): | 339 if not file.startswith(self.change.RepositoryRoot()): |
282 raise IOError('Access outside the repository root is denied.') | 340 raise IOError('Access outside the repository root is denied.') |
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 return not DoPresubmitChecks(gcl.ChangeInfo('No name', 0, 0, '', files), | 803 return not DoPresubmitChecks(gcl.ChangeInfo('No name', 0, 0, '', files), |
746 options.commit, | 804 options.commit, |
747 options.verbose, | 805 options.verbose, |
748 sys.stdout, | 806 sys.stdout, |
749 sys.stdin, | 807 sys.stdin, |
750 default_presubmit=None) | 808 default_presubmit=None) |
751 | 809 |
752 | 810 |
753 if __name__ == '__main__': | 811 if __name__ == '__main__': |
754 sys.exit(Main(sys.argv)) | 812 sys.exit(Main(sys.argv)) |
OLD | NEW |