| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Generic presubmit checks that can be reused by other presubmit checks.""" | 5 """Generic presubmit checks that can be reused by other presubmit checks.""" |
| 6 | 6 |
| 7 | 7 |
| 8 ### Description checks | 8 ### Description checks |
| 9 | 9 |
| 10 def CheckChangeHasTestField(input_api, output_api): | 10 def CheckChangeHasTestField(input_api, output_api): |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 return [] | 72 return [] |
| 73 | 73 |
| 74 | 74 |
| 75 ### Content checks | 75 ### Content checks |
| 76 | 76 |
| 77 def CheckDoNotSubmitInFiles(input_api, output_api): | 77 def CheckDoNotSubmitInFiles(input_api, output_api): |
| 78 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to any files.""" | 78 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to any files.""" |
| 79 # We want to check every text file, not just source files. | 79 # We want to check every text file, not just source files. |
| 80 file_filter = lambda x : x | 80 file_filter = lambda x : x |
| 81 keyword = 'DO NOT ' + 'SUBMIT' | 81 keyword = 'DO NOT ' + 'SUBMIT' |
| 82 errors = _FindNewViolationsOfRule(lambda line : keyword not in line, | 82 errors = _FindNewViolationsOfRule(lambda _, line : keyword not in line, |
| 83 input_api, file_filter) | 83 input_api, file_filter) |
| 84 text = '\n'.join('Found %s in %s' % (keyword, loc) for loc in errors) | 84 text = '\n'.join('Found %s in %s' % (keyword, loc) for loc in errors) |
| 85 if text: | 85 if text: |
| 86 return [output_api.PresubmitError(text)] | 86 return [output_api.PresubmitError(text)] |
| 87 return [] | 87 return [] |
| 88 | 88 |
| 89 | 89 |
| 90 def CheckChangeLintsClean(input_api, output_api, source_file_filter=None): | 90 def CheckChangeLintsClean(input_api, output_api, source_file_filter=None): |
| 91 """Checks that all '.cc' and '.h' files pass cpplint.py.""" | 91 """Checks that all '.cc' and '.h' files pass cpplint.py.""" |
| 92 _RE_IS_TEST = input_api.re.compile(r'.*tests?.(cc|h)$') | 92 _RE_IS_TEST = input_api.re.compile(r'.*tests?.(cc|h)$') |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 def _ReportErrorFileAndLine(filename, line_num, line): | 227 def _ReportErrorFileAndLine(filename, line_num, line): |
| 228 """Default error formatter for _FindNewViolationsOfRule.""" | 228 """Default error formatter for _FindNewViolationsOfRule.""" |
| 229 return '%s, line %s' % (filename, line_num) | 229 return '%s, line %s' % (filename, line_num) |
| 230 | 230 |
| 231 | 231 |
| 232 def _FindNewViolationsOfRule(callable_rule, input_api, source_file_filter=None, | 232 def _FindNewViolationsOfRule(callable_rule, input_api, source_file_filter=None, |
| 233 error_formatter=_ReportErrorFileAndLine): | 233 error_formatter=_ReportErrorFileAndLine): |
| 234 """Find all newly introduced violations of a per-line rule (a callable). | 234 """Find all newly introduced violations of a per-line rule (a callable). |
| 235 | 235 |
| 236 Arguments: | 236 Arguments: |
| 237 callable_rule: a callable taking a line of input and returning True | 237 callable_rule: a callable taking a file extension and line of input and |
| 238 if the rule is satisfied and False if there was a problem. | 238 returning True if the rule is satisfied and False if there was a problem. |
| 239 input_api: object to enumerate the affected files. | 239 input_api: object to enumerate the affected files. |
| 240 source_file_filter: a filter to be passed to the input api. | 240 source_file_filter: a filter to be passed to the input api. |
| 241 error_formatter: a callable taking (filename, line_number, line) and | 241 error_formatter: a callable taking (filename, line_number, line) and |
| 242 returning a formatted error string. | 242 returning a formatted error string. |
| 243 | 243 |
| 244 Returns: | 244 Returns: |
| 245 A list of the newly-introduced violations reported by the rule. | 245 A list of the newly-introduced violations reported by the rule. |
| 246 """ | 246 """ |
| 247 errors = [] | 247 errors = [] |
| 248 for f in input_api.AffectedFiles(include_deletes=False, | 248 for f in input_api.AffectedFiles(include_deletes=False, |
| 249 file_filter=source_file_filter): | 249 file_filter=source_file_filter): |
| 250 # For speed, we do two passes, checking first the full file. Shelling out | 250 # For speed, we do two passes, checking first the full file. Shelling out |
| 251 # to the SCM to determine the changed region can be quite expensive on | 251 # to the SCM to determine the changed region can be quite expensive on |
| 252 # Win32. Assuming that most files will be kept problem-free, we can | 252 # Win32. Assuming that most files will be kept problem-free, we can |
| 253 # skip the SCM operations most of the time. | 253 # skip the SCM operations most of the time. |
| 254 if all(callable_rule(line) for line in f.NewContents()): | 254 extension = str(f.LocalPath()).rsplit('.', 1)[-1] |
| 255 if all(callable_rule(extension, line) for line in f.NewContents()): |
| 255 continue # No violation found in full text: can skip considering diff. | 256 continue # No violation found in full text: can skip considering diff. |
| 256 | 257 |
| 257 for line_num, line in f.ChangedContents(): | 258 for line_num, line in f.ChangedContents(): |
| 258 if not callable_rule(line): | 259 if not callable_rule(extension, line): |
| 259 errors.append(error_formatter(f.LocalPath(), line_num, line)) | 260 errors.append(error_formatter(f.LocalPath(), line_num, line)) |
| 260 | 261 |
| 261 return errors | 262 return errors |
| 262 | 263 |
| 263 | 264 |
| 264 def CheckChangeHasNoTabs(input_api, output_api, source_file_filter=None): | 265 def CheckChangeHasNoTabs(input_api, output_api, source_file_filter=None): |
| 265 """Checks that there are no tab characters in any of the text files to be | 266 """Checks that there are no tab characters in any of the text files to be |
| 266 submitted. | 267 submitted. |
| 267 """ | 268 """ |
| 268 # In addition to the filter, make sure that makefiles are blacklisted. | 269 # In addition to the filter, make sure that makefiles are blacklisted. |
| 269 if not source_file_filter: | 270 if not source_file_filter: |
| 270 # It's the default filter. | 271 # It's the default filter. |
| 271 source_file_filter = input_api.FilterSourceFile | 272 source_file_filter = input_api.FilterSourceFile |
| 272 def filter_more(affected_file): | 273 def filter_more(affected_file): |
| 273 return (not input_api.os_path.basename(affected_file.LocalPath()) in | 274 return (not input_api.os_path.basename(affected_file.LocalPath()) in |
| 274 ('Makefile', 'makefile') and | 275 ('Makefile', 'makefile') and |
| 275 source_file_filter(affected_file)) | 276 source_file_filter(affected_file)) |
| 276 | 277 |
| 277 tabs = _FindNewViolationsOfRule(lambda line : '\t' not in line, | 278 tabs = _FindNewViolationsOfRule(lambda _, line : '\t' not in line, |
| 278 input_api, filter_more) | 279 input_api, filter_more) |
| 279 | 280 |
| 280 if tabs: | 281 if tabs: |
| 281 return [output_api.PresubmitPromptWarning('Found a tab character in:', | 282 return [output_api.PresubmitPromptWarning('Found a tab character in:', |
| 282 long_text='\n'.join(tabs))] | 283 long_text='\n'.join(tabs))] |
| 283 return [] | 284 return [] |
| 284 | 285 |
| 285 | 286 |
| 286 def CheckChangeTodoHasOwner(input_api, output_api, source_file_filter=None): | 287 def CheckChangeTodoHasOwner(input_api, output_api, source_file_filter=None): |
| 287 """Checks that the user didn't add TODO(name) without an owner.""" | 288 """Checks that the user didn't add TODO(name) without an owner.""" |
| 288 | 289 |
| 289 unowned_todo = input_api.re.compile('TO' + 'DO[^(]') | 290 unowned_todo = input_api.re.compile('TO' + 'DO[^(]') |
| 290 errors = _FindNewViolationsOfRule(lambda x : not unowned_todo.search(x), | 291 errors = _FindNewViolationsOfRule(lambda _, x : not unowned_todo.search(x), |
| 291 input_api, source_file_filter) | 292 input_api, source_file_filter) |
| 292 errors = ['Found TO' + 'DO with no owner in ' + x for x in errors] | 293 errors = ['Found TO' + 'DO with no owner in ' + x for x in errors] |
| 293 if errors: | 294 if errors: |
| 294 return [output_api.PresubmitPromptWarning('\n'.join(errors))] | 295 return [output_api.PresubmitPromptWarning('\n'.join(errors))] |
| 295 return [] | 296 return [] |
| 296 | 297 |
| 297 | 298 |
| 298 def CheckChangeHasNoStrayWhitespace(input_api, output_api, | 299 def CheckChangeHasNoStrayWhitespace(input_api, output_api, |
| 299 source_file_filter=None): | 300 source_file_filter=None): |
| 300 """Checks that there is no stray whitespace at source lines end.""" | 301 """Checks that there is no stray whitespace at source lines end.""" |
| 301 errors = _FindNewViolationsOfRule(lambda line : line.rstrip() == line, | 302 errors = _FindNewViolationsOfRule(lambda _, line : line.rstrip() == line, |
| 302 input_api, source_file_filter) | 303 input_api, source_file_filter) |
| 303 if errors: | 304 if errors: |
| 304 return [output_api.PresubmitPromptWarning( | 305 return [output_api.PresubmitPromptWarning( |
| 305 'Found line ending with white spaces in:', | 306 'Found line ending with white spaces in:', |
| 306 long_text='\n'.join(errors))] | 307 long_text='\n'.join(errors))] |
| 307 return [] | 308 return [] |
| 308 | 309 |
| 309 | 310 |
| 310 def CheckLongLines(input_api, output_api, maxlen=80, source_file_filter=None): | 311 def CheckLongLines(input_api, output_api, maxlen=80, source_file_filter=None): |
| 311 """Checks that there aren't any lines longer than maxlen characters in any of | 312 """Checks that there aren't any lines longer than maxlen characters in any of |
| 312 the text files to be submitted. | 313 the text files to be submitted. |
| 313 """ | 314 """ |
| 314 # Stupidly long symbols that needs to be worked around if takes 66% of line. | 315 maxlens = { |
| 315 long_symbol = maxlen * 2 / 3 | 316 'java': 100, |
| 316 # Hard line length limit at 50% more. | 317 '': maxlen, |
| 317 extra_maxlen = maxlen * 3 / 2 | 318 } |
| 318 # Note: these are C++ specific but processed on all languages. :( | 319 # Note: these are C++ specific but processed on all languages. :( |
| 319 MACROS = ('#define', '#include', '#import', '#pragma', '#if', '#endif') | 320 MACROS = ('#define', '#include', '#import', '#pragma', '#if', '#endif') |
| 320 | 321 |
| 321 def no_long_lines(line): | 322 def no_long_lines(file_extension, line): |
| 322 if len(line) <= maxlen: | 323 file_maxlen = maxlens.get(file_extension, maxlens['']) |
| 324 # Stupidly long symbols that needs to be worked around if takes 66% of line. |
| 325 long_symbol = file_maxlen * 2 / 3 |
| 326 # Hard line length limit at 50% more. |
| 327 extra_maxlen = file_maxlen * 3 / 2 |
| 328 |
| 329 line_len = len(line) |
| 330 if line_len <= file_maxlen: |
| 323 return True | 331 return True |
| 324 | 332 |
| 325 if len(line) > extra_maxlen: | 333 if line_len > extra_maxlen: |
| 326 return False | 334 return False |
| 327 | 335 |
| 328 return ( | 336 return ( |
| 329 line.startswith(MACROS) or | 337 line.startswith(MACROS) or |
| 330 any((url in line) for url in ('http://', 'https://')) or | 338 any((url in line) for url in ('http://', 'https://')) or |
| 331 input_api.re.match( | 339 input_api.re.match( |
| 332 r'.*[A-Za-z][A-Za-z_0-9]{%d,}.*' % long_symbol, line)) | 340 r'.*[A-Za-z][A-Za-z_0-9]{%d,}.*' % long_symbol, line)) |
| 333 | 341 |
| 334 def format_error(filename, line_num, line): | 342 def format_error(filename, line_num, line): |
| 335 return '%s, line %s, %s chars' % (filename, line_num, len(line)) | 343 return '%s, line %s, %s chars' % (filename, line_num, len(line)) |
| (...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( | 922 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( |
| 915 input_api, output_api)) | 923 input_api, output_api)) |
| 916 snapshot("checking license") | 924 snapshot("checking license") |
| 917 results.extend(input_api.canned_checks.CheckLicense( | 925 results.extend(input_api.canned_checks.CheckLicense( |
| 918 input_api, output_api, license_header, source_file_filter=sources)) | 926 input_api, output_api, license_header, source_file_filter=sources)) |
| 919 snapshot("checking was uploaded") | 927 snapshot("checking was uploaded") |
| 920 results.extend(input_api.canned_checks.CheckChangeWasUploaded( | 928 results.extend(input_api.canned_checks.CheckChangeWasUploaded( |
| 921 input_api, output_api)) | 929 input_api, output_api)) |
| 922 snapshot("done") | 930 snapshot("done") |
| 923 return results | 931 return results |
| OLD | NEW |