blob: 252b836826b0ba674d23e9cb4f996c239981986a [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
[email protected]50d7d721e2009-11-15 17:56:188for more details about the presubmit API built into gcl.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]9d16ad12011-12-14 20:49:4712import re
[email protected]fbcafe5a2012-08-08 15:31:2213import subprocess
[email protected]55f9f382012-07-31 11:02:1814import sys
[email protected]9d16ad12011-12-14 20:49:4715
16
[email protected]379e7dd2010-01-28 17:39:2117_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5418 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0019 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
20 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]a18130a2012-01-03 17:52:0821 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5422 r"^skia[\\\/].*",
23 r"^v8[\\\/].*",
24 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5325 r".+_autogen\.h$",
[email protected]94f206c12012-08-25 00:09:1426 r"^cc[\\\/].*",
[email protected]39849c6c2012-09-14 22:15:5927 r"^webkit[\\\/]compositor_bindings[\\\/].*",
[email protected]ce145c02012-09-06 09:49:3428 r".+[\\\/]pnacl_shim\.c$",
[email protected]4306417642009-06-11 00:33:4029)
[email protected]ca8d19842009-02-19 16:33:1230
[email protected]ca8d19842009-02-19 16:33:1231
[email protected]eea609a2011-11-18 13:10:1232_TEST_ONLY_WARNING = (
33 'You might be calling functions intended only for testing from\n'
34 'production code. It is OK to ignore this warning if you know what\n'
35 'you are doing, as the heuristics used to detect the situation are\n'
36 'not perfect. The commit queue will not block on this warning.\n'
37 'Email [email protected] if you have questions.')
38
39
[email protected]cf9b78f2012-11-14 11:40:2840_INCLUDE_ORDER_WARNING = (
41 'Your #include order seems to be broken. Send mail to\n'
42 '[email protected] if this is not the case.')
43
44
[email protected]127f18ec2012-06-16 05:05:5945_BANNED_OBJC_FUNCTIONS = (
46 (
47 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2048 (
49 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5950 'prohibited. Please use CrTrackingArea instead.',
51 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
52 ),
53 False,
54 ),
55 (
56 'NSTrackingArea',
[email protected]23e6cbc2012-06-16 18:51:2057 (
58 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5959 'instead.',
60 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
61 ),
62 False,
63 ),
64 (
65 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2066 (
67 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5968 'Please use |convertPoint:(point) fromView:nil| instead.',
69 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
70 ),
71 True,
72 ),
73 (
74 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2075 (
76 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5977 'Please use |convertPoint:(point) toView:nil| instead.',
78 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
79 ),
80 True,
81 ),
82 (
83 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2084 (
85 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5986 'Please use |convertRect:(point) fromView:nil| instead.',
87 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
88 ),
89 True,
90 ),
91 (
92 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:2093 (
94 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5995 'Please use |convertRect:(point) toView:nil| instead.',
96 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
97 ),
98 True,
99 ),
100 (
101 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20102 (
103 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59104 'Please use |convertSize:(point) fromView:nil| instead.',
105 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
106 ),
107 True,
108 ),
109 (
110 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20111 (
112 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59113 'Please use |convertSize:(point) toView:nil| instead.',
114 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
115 ),
116 True,
117 ),
118)
119
120
121_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20122 # Make sure that gtest's FRIEND_TEST() macro is not used; the
123 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30124 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20125 (
126 'FRIEND_TEST(',
127 (
[email protected]e3c945502012-06-26 20:01:49128 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20129 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
130 ),
131 False,
[email protected]7345da02012-11-27 14:31:49132 (),
[email protected]23e6cbc2012-06-16 18:51:20133 ),
134 (
135 'ScopedAllowIO',
136 (
[email protected]e3c945502012-06-26 20:01:49137 'New code should not use ScopedAllowIO. Post a task to the blocking',
138 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20139 ),
[email protected]e3c945502012-06-26 20:01:49140 True,
[email protected]7345da02012-11-27 14:31:49141 (
142 r"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
143 ),
[email protected]23e6cbc2012-06-16 18:51:20144 ),
145 (
146 'FilePathWatcher::Delegate',
147 (
[email protected]e3c945502012-06-26 20:01:49148 'New code should not use FilePathWatcher::Delegate. Use the callback',
[email protected]23e6cbc2012-06-16 18:51:20149 'interface instead.',
150 ),
151 False,
[email protected]7345da02012-11-27 14:31:49152 (),
[email protected]23e6cbc2012-06-16 18:51:20153 ),
[email protected]e3c945502012-06-26 20:01:49154 (
[email protected]e3c945502012-06-26 20:01:49155 'browser::FindOrCreateTabbedBrowser',
156 (
157 'This function is deprecated and we\'re working on removing it. Pass',
158 'more context to get a Browser*, like a WebContents, window, or session',
[email protected]1099dbd2012-11-01 19:56:02159 'id. Talk to robertshield@ for more information.',
[email protected]e3c945502012-06-26 20:01:49160 ),
161 True,
[email protected]7345da02012-11-27 14:31:49162 (),
[email protected]e3c945502012-06-26 20:01:49163 ),
164 (
[email protected]bb5eff1cc2012-11-01 20:46:29165 'RunAllPending()',
166 (
167 'This function is deprecated and we\'re working on removing it. Rename',
168 'to RunUntilIdle',
169 ),
170 True,
[email protected]7345da02012-11-27 14:31:49171 (),
[email protected]bb5eff1cc2012-11-01 20:46:29172 ),
[email protected]127f18ec2012-06-16 05:05:59173)
174
175
[email protected]eea609a2011-11-18 13:10:12176
[email protected]55459852011-08-10 15:17:19177def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
178 """Attempts to prevent use of functions intended only for testing in
179 non-testing code. For now this is just a best-effort implementation
180 that ignores header files and may have some false positives. A
181 better implementation would probably need a proper C++ parser.
182 """
183 # We only scan .cc files and the like, as the declaration of
184 # for-testing functions in header files are hard to distinguish from
185 # calls to such functions without a proper C++ parser.
[email protected]403bfbc92012-06-11 23:30:09186 platform_specifiers = r'(_(android|chromeos|gtk|mac|posix|win))?'
[email protected]55459852011-08-10 15:17:19187 source_extensions = r'\.(cc|cpp|cxx|mm)$'
188 file_inclusion_pattern = r'.+%s' % source_extensions
[email protected]19e77fd2011-10-20 05:24:05189 file_exclusion_patterns = (
[email protected]44e376e2012-10-26 19:40:21190 r'.*[/\\](fake_|test_|mock_).+%s' % source_extensions,
[email protected]c762d252012-02-28 02:07:24191 r'.+_test_(base|support|util)%s' % source_extensions,
[email protected]403bfbc92012-06-11 23:30:09192 r'.+_(api|browser|perf|unit|ui)?test%s%s' % (platform_specifiers,
193 source_extensions),
[email protected]19e77fd2011-10-20 05:24:05194 r'.+profile_sync_service_harness%s' % source_extensions,
195 )
196 path_exclusion_patterns = (
197 r'.*[/\\](test|tool(s)?)[/\\].*',
198 # At request of folks maintaining this folder.
199 r'chrome[/\\]browser[/\\]automation[/\\].*',
200 )
[email protected]55459852011-08-10 15:17:19201
202 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
203 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
204 exclusion_pattern = input_api.re.compile(
205 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
206 base_function_pattern, base_function_pattern))
207
208 def FilterFile(affected_file):
[email protected]19e77fd2011-10-20 05:24:05209 black_list = (file_exclusion_patterns + path_exclusion_patterns +
[email protected]3afb12a42011-08-15 13:48:33210 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19211 return input_api.FilterSourceFile(
212 affected_file,
213 white_list=(file_inclusion_pattern, ),
214 black_list=black_list)
215
216 problems = []
217 for f in input_api.AffectedSourceFiles(FilterFile):
218 local_path = f.LocalPath()
219 lines = input_api.ReadFile(f).splitlines()
220 line_number = 0
221 for line in lines:
222 if (inclusion_pattern.search(line) and
223 not exclusion_pattern.search(line)):
224 problems.append(
225 '%s:%d\n %s' % (local_path, line_number, line.strip()))
226 line_number += 1
227
228 if problems:
[email protected]eea609a2011-11-18 13:10:12229 if not input_api.is_committing:
230 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
231 else:
232 # We don't warn on commit, to avoid stopping commits going through CQ.
233 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
[email protected]55459852011-08-10 15:17:19234 else:
235 return []
236
237
[email protected]10689ca2011-09-02 02:31:54238def _CheckNoIOStreamInHeaders(input_api, output_api):
239 """Checks to make sure no .h files include <iostream>."""
240 files = []
241 pattern = input_api.re.compile(r'^#include\s*<iostream>',
242 input_api.re.MULTILINE)
243 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
244 if not f.LocalPath().endswith('.h'):
245 continue
246 contents = input_api.ReadFile(f)
247 if pattern.search(contents):
248 files.append(f)
249
250 if len(files):
251 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06252 'Do not #include <iostream> in header files, since it inserts static '
253 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54254 '#include <ostream>. See http://crbug.com/94794',
255 files) ]
256 return []
257
258
[email protected]72df4e782012-06-21 16:28:18259def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
260 """Checks to make sure no source files use UNIT_TEST"""
261 problems = []
262 for f in input_api.AffectedFiles():
263 if (not f.LocalPath().endswith(('.cc', '.mm'))):
264 continue
265
266 for line_num, line in f.ChangedContents():
267 if 'UNIT_TEST' in line:
268 problems.append(' %s:%d' % (f.LocalPath(), line_num))
269
270 if not problems:
271 return []
272 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
273 '\n'.join(problems))]
274
275
[email protected]8ea5d4b2011-09-13 21:49:22276def _CheckNoNewWStrings(input_api, output_api):
277 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27278 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22279 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20280 if (not f.LocalPath().endswith(('.cc', '.h')) or
281 f.LocalPath().endswith('test.cc')):
282 continue
[email protected]8ea5d4b2011-09-13 21:49:22283
[email protected]a11dbe9b2012-08-07 01:32:58284 allowWString = False
[email protected]b5c24292011-11-28 14:38:20285 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58286 if 'presubmit: allow wstring' in line:
287 allowWString = True
288 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27289 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58290 allowWString = False
291 else:
292 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22293
[email protected]55463aa62011-10-12 00:48:27294 if not problems:
295 return []
296 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58297 ' If you are calling a cross-platform API that accepts a wstring, '
298 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27299 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22300
301
[email protected]2a8ac9c2011-10-19 17:20:44302def _CheckNoDEPSGIT(input_api, output_api):
303 """Make sure .DEPS.git is never modified manually."""
304 if any(f.LocalPath().endswith('.DEPS.git') for f in
305 input_api.AffectedFiles()):
306 return [output_api.PresubmitError(
307 'Never commit changes to .DEPS.git. This file is maintained by an\n'
308 'automated system based on what\'s in DEPS and your changes will be\n'
309 'overwritten.\n'
310 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
311 'for more information')]
312 return []
313
314
[email protected]127f18ec2012-06-16 05:05:59315def _CheckNoBannedFunctions(input_api, output_api):
316 """Make sure that banned functions are not used."""
317 warnings = []
318 errors = []
319
320 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
321 for f in input_api.AffectedFiles(file_filter=file_filter):
322 for line_num, line in f.ChangedContents():
323 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
324 if func_name in line:
325 problems = warnings;
326 if error:
327 problems = errors;
328 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
329 for message_line in message:
330 problems.append(' %s' % message_line)
331
332 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
333 for f in input_api.AffectedFiles(file_filter=file_filter):
334 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49335 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
336 def IsBlacklisted(affected_file, blacklist):
337 local_path = affected_file.LocalPath()
338 for item in blacklist:
339 if input_api.re.match(item, local_path):
340 return True
341 return False
342 if IsBlacklisted(f, excluded_paths):
343 continue
[email protected]127f18ec2012-06-16 05:05:59344 if func_name in line:
345 problems = warnings;
346 if error:
347 problems = errors;
348 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
349 for message_line in message:
350 problems.append(' %s' % message_line)
351
352 result = []
353 if (warnings):
354 result.append(output_api.PresubmitPromptWarning(
355 'Banned functions were used.\n' + '\n'.join(warnings)))
356 if (errors):
357 result.append(output_api.PresubmitError(
358 'Banned functions were used.\n' + '\n'.join(errors)))
359 return result
360
361
[email protected]6c063c62012-07-11 19:11:06362def _CheckNoPragmaOnce(input_api, output_api):
363 """Make sure that banned functions are not used."""
364 files = []
365 pattern = input_api.re.compile(r'^#pragma\s+once',
366 input_api.re.MULTILINE)
367 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
368 if not f.LocalPath().endswith('.h'):
369 continue
370 contents = input_api.ReadFile(f)
371 if pattern.search(contents):
372 files.append(f)
373
374 if files:
375 return [output_api.PresubmitError(
376 'Do not use #pragma once in header files.\n'
377 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
378 files)]
379 return []
380
[email protected]127f18ec2012-06-16 05:05:59381
[email protected]e7479052012-09-19 00:26:12382def _CheckNoTrinaryTrueFalse(input_api, output_api):
383 """Checks to make sure we don't introduce use of foo ? true : false."""
384 problems = []
385 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
386 for f in input_api.AffectedFiles():
387 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
388 continue
389
390 for line_num, line in f.ChangedContents():
391 if pattern.match(line):
392 problems.append(' %s:%d' % (f.LocalPath(), line_num))
393
394 if not problems:
395 return []
396 return [output_api.PresubmitPromptWarning(
397 'Please consider avoiding the "? true : false" pattern if possible.\n' +
398 '\n'.join(problems))]
399
400
[email protected]55f9f382012-07-31 11:02:18401def _CheckUnwantedDependencies(input_api, output_api):
402 """Runs checkdeps on #include statements added in this
403 change. Breaking - rules is an error, breaking ! rules is a
404 warning.
405 """
406 # We need to wait until we have an input_api object and use this
407 # roundabout construct to import checkdeps because this file is
408 # eval-ed and thus doesn't have __file__.
409 original_sys_path = sys.path
410 try:
411 sys.path = sys.path + [input_api.os_path.join(
412 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
413 import checkdeps
414 from cpp_checker import CppChecker
415 from rules import Rule
416 finally:
417 # Restore sys.path to what it was before.
418 sys.path = original_sys_path
419
420 added_includes = []
421 for f in input_api.AffectedFiles():
422 if not CppChecker.IsCppFile(f.LocalPath()):
423 continue
424
425 changed_lines = [line for line_num, line in f.ChangedContents()]
426 added_includes.append([f.LocalPath(), changed_lines])
427
428 deps_checker = checkdeps.DepsChecker()
429
430 error_descriptions = []
431 warning_descriptions = []
432 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
433 added_includes):
434 description_with_path = '%s\n %s' % (path, rule_description)
435 if rule_type == Rule.DISALLOW:
436 error_descriptions.append(description_with_path)
437 else:
438 warning_descriptions.append(description_with_path)
439
440 results = []
441 if error_descriptions:
442 results.append(output_api.PresubmitError(
443 'You added one or more #includes that violate checkdeps rules.',
444 error_descriptions))
445 if warning_descriptions:
[email protected]779caa52012-08-21 17:05:59446 if not input_api.is_committing:
447 warning_factory = output_api.PresubmitPromptWarning
448 else:
449 # We don't want to block use of the CQ when there is a warning
450 # of this kind, so we only show a message when committing.
451 warning_factory = output_api.PresubmitNotifyResult
452 results.append(warning_factory(
[email protected]55f9f382012-07-31 11:02:18453 'You added one or more #includes of files that are temporarily\n'
454 'allowed but being removed. Can you avoid introducing the\n'
455 '#include? See relevant DEPS file(s) for details and contacts.',
456 warning_descriptions))
457 return results
458
459
[email protected]fbcafe5a2012-08-08 15:31:22460def _CheckFilePermissions(input_api, output_api):
461 """Check that all files have their permissions properly set."""
462 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
463 input_api.change.RepositoryRoot()]
464 for f in input_api.AffectedFiles():
465 args += ['--file', f.LocalPath()]
466 errors = []
467 (errors, stderrdata) = subprocess.Popen(args).communicate()
468
469 results = []
470 if errors:
[email protected]c8278b32012-10-30 20:35:49471 results.append(output_api.PresubmitError('checkperms.py failed.',
[email protected]fbcafe5a2012-08-08 15:31:22472 errors))
473 return results
474
475
[email protected]c8278b32012-10-30 20:35:49476def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
477 """Makes sure we don't include ui/aura/window_property.h
478 in header files.
479 """
480 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
481 errors = []
482 for f in input_api.AffectedFiles():
483 if not f.LocalPath().endswith('.h'):
484 continue
485 for line_num, line in f.ChangedContents():
486 if pattern.match(line):
487 errors.append(' %s:%d' % (f.LocalPath(), line_num))
488
489 results = []
490 if errors:
491 results.append(output_api.PresubmitError(
492 'Header files should not include ui/aura/window_property.h', errors))
493 return results
494
495
[email protected]cf9b78f2012-11-14 11:40:28496def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
497 """Checks that the lines in scope occur in the right order.
498
499 1. C system files in alphabetical order
500 2. C++ system files in alphabetical order
501 3. Project's .h files
502 """
503
504 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
505 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
506 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
507
508 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
509
510 state = C_SYSTEM_INCLUDES
511
512 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57513 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28514 problem_linenums = []
515 for line_num, line in scope:
516 if c_system_include_pattern.match(line):
517 if state != C_SYSTEM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57518 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28519 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57520 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28521 elif cpp_system_include_pattern.match(line):
522 if state == C_SYSTEM_INCLUDES:
523 state = CPP_SYSTEM_INCLUDES
524 elif state == CUSTOM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57525 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28526 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57527 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28528 elif custom_include_pattern.match(line):
529 if state != CUSTOM_INCLUDES:
530 state = CUSTOM_INCLUDES
531 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57532 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28533 else:
534 problem_linenums.append(line_num)
535 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57536 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28537
538 warnings = []
[email protected]728b9bb2012-11-14 20:38:57539 for (line_num, previous_line_num) in problem_linenums:
540 if line_num in changed_linenums or previous_line_num in changed_linenums:
[email protected]cf9b78f2012-11-14 11:40:28541 warnings.append(' %s:%d' % (file_path, line_num))
542 return warnings
543
544
[email protected]ac294a12012-12-06 16:38:43545def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28546 """Checks the #include order for the given file f."""
547
[email protected]2299dcf2012-11-15 19:56:24548 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]962f117e2012-11-22 18:11:56549 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
550 # often need to appear in a specific order.
551 excluded_include_pattern = input_api.re.compile(r'\s*#include \<.*/.*')
[email protected]2299dcf2012-11-15 19:56:24552 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]ac294a12012-12-06 16:38:43553 if_pattern = (
554 input_api.re.compile(r'\s*#\s*(if|elif|else|endif|define|undef).*'))
[email protected]cf9b78f2012-11-14 11:40:28555
556 contents = f.NewContents()
557 warnings = []
558 line_num = 0
559
[email protected]ac294a12012-12-06 16:38:43560 # Handle the special first include. If the first include file is
561 # some/path/file.h, the corresponding including file can be some/path/file.cc,
562 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
563 # etc. It's also possible that no special first include exists.
564 for line in contents:
565 line_num += 1
566 if system_include_pattern.match(line):
567 # No special first include -> process the line again along with normal
568 # includes.
569 line_num -= 1
570 break
571 match = custom_include_pattern.match(line)
572 if match:
573 match_dict = match.groupdict()
574 header_basename = input_api.os_path.basename(
575 match_dict['FILE']).replace('.h', '')
576 if header_basename not in input_api.os_path.basename(f.LocalPath()):
[email protected]2299dcf2012-11-15 19:56:24577 # No special first include -> process the line again along with normal
578 # includes.
579 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43580 break
[email protected]cf9b78f2012-11-14 11:40:28581
582 # Split into scopes: Each region between #if and #endif is its own scope.
583 scopes = []
584 current_scope = []
585 for line in contents[line_num:]:
586 line_num += 1
[email protected]2309b0fa02012-11-16 12:18:27587 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28588 scopes.append(current_scope)
589 current_scope = []
[email protected]962f117e2012-11-22 18:11:56590 elif ((system_include_pattern.match(line) or
591 custom_include_pattern.match(line)) and
592 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28593 current_scope.append((line_num, line))
594 scopes.append(current_scope)
595
596 for scope in scopes:
597 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
598 changed_linenums))
599 return warnings
600
601
602def _CheckIncludeOrder(input_api, output_api):
603 """Checks that the #include order is correct.
604
605 1. The corresponding header for source files.
606 2. C system files in alphabetical order
607 3. C++ system files in alphabetical order
608 4. Project's .h files in alphabetical order
609
[email protected]ac294a12012-12-06 16:38:43610 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
611 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28612 """
613
614 warnings = []
615 for f in input_api.AffectedFiles():
[email protected]ac294a12012-12-06 16:38:43616 if f.LocalPath().endswith(('.cc', '.h')):
617 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
618 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28619
620 results = []
621 if warnings:
622 results.append(output_api.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING,
623 warnings))
624 return results
625
626
[email protected]70ca77752012-11-20 03:45:03627def _CheckForVersionControlConflictsInFile(input_api, f):
628 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
629 errors = []
630 for line_num, line in f.ChangedContents():
631 if pattern.match(line):
632 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
633 return errors
634
635
636def _CheckForVersionControlConflicts(input_api, output_api):
637 """Usually this is not intentional and will cause a compile failure."""
638 errors = []
639 for f in input_api.AffectedFiles():
640 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
641
642 results = []
643 if errors:
644 results.append(output_api.PresubmitError(
645 'Version control conflict markers found, please resolve.', errors))
646 return results
647
648
[email protected]22c9bd72011-03-27 16:47:39649def _CommonChecks(input_api, output_api):
650 """Checks common to both upload and commit."""
651 results = []
652 results.extend(input_api.canned_checks.PanProjectChecks(
653 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
[email protected]66daa702011-05-28 14:41:46654 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:19655 results.extend(
656 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:54657 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:18658 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:22659 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:44660 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:59661 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:06662 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:12663 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:18664 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:22665 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:49666 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:27667 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:03668 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:49669 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:24670
671 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
672 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
673 input_api, output_api,
674 input_api.PresubmitLocalPath(),
675 whitelist=[r'.+_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:39676 return results
[email protected]1f7b4172010-01-28 01:17:34677
[email protected]b337cb5b2011-01-23 21:24:05678
679def _CheckSubversionConfig(input_api, output_api):
680 """Verifies the subversion config file is correctly setup.
681
682 Checks that autoprops are enabled, returns an error otherwise.
683 """
684 join = input_api.os_path.join
685 if input_api.platform == 'win32':
686 appdata = input_api.environ.get('APPDATA', '')
687 if not appdata:
688 return [output_api.PresubmitError('%APPDATA% is not configured.')]
689 path = join(appdata, 'Subversion', 'config')
690 else:
691 home = input_api.environ.get('HOME', '')
692 if not home:
693 return [output_api.PresubmitError('$HOME is not configured.')]
694 path = join(home, '.subversion', 'config')
695
696 error_msg = (
697 'Please look at http://dev.chromium.org/developers/coding-style to\n'
698 'configure your subversion configuration file. This enables automatic\n'
[email protected]c6a3c10b2011-01-24 16:14:20699 'properties to simplify the project maintenance.\n'
700 'Pro-tip: just download and install\n'
701 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
[email protected]b337cb5b2011-01-23 21:24:05702
703 try:
704 lines = open(path, 'r').read().splitlines()
705 # Make sure auto-props is enabled and check for 2 Chromium standard
706 # auto-prop.
707 if (not '*.cc = svn:eol-style=LF' in lines or
708 not '*.pdf = svn:mime-type=application/pdf' in lines or
709 not 'enable-auto-props = yes' in lines):
710 return [
[email protected]79ed7e62011-02-21 21:08:53711 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05712 'It looks like you have not configured your subversion config '
[email protected]b5359c02011-02-01 20:29:56713 'file or it is not up-to-date.\n' + error_msg)
[email protected]b337cb5b2011-01-23 21:24:05714 ]
715 except (OSError, IOError):
716 return [
[email protected]79ed7e62011-02-21 21:08:53717 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05718 'Can\'t find your subversion config file.\n' + error_msg)
719 ]
720 return []
721
722
[email protected]66daa702011-05-28 14:41:46723def _CheckAuthorizedAuthor(input_api, output_api):
724 """For non-googler/chromites committers, verify the author's email address is
725 in AUTHORS.
726 """
[email protected]9bb9cb82011-06-13 20:43:01727 # TODO(maruel): Add it to input_api?
728 import fnmatch
729
[email protected]66daa702011-05-28 14:41:46730 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:01731 if not author:
732 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:46733 return []
[email protected]c99663292011-05-31 19:46:08734 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:46735 input_api.PresubmitLocalPath(), 'AUTHORS')
736 valid_authors = (
737 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
738 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:18739 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]9bb9cb82011-06-13 20:43:01740 if input_api.verbose:
741 print 'Valid authors are %s' % ', '.join(valid_authors)
[email protected]d8b50be2011-06-15 14:19:44742 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]66daa702011-05-28 14:41:46743 return [output_api.PresubmitPromptWarning(
744 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
745 '\n'
746 'http://www.chromium.org/developers/contributing-code and read the '
747 '"Legal" section\n'
748 'If you are a chromite, verify the contributor signed the CLA.') %
749 author)]
750 return []
751
752
[email protected]b8079ae4a2012-12-05 19:56:49753def _CheckPatchFiles(input_api, output_api):
754 problems = [f.LocalPath() for f in input_api.AffectedFiles()
755 if f.LocalPath().endswith(('.orig', '.rej'))]
756 if problems:
757 return [output_api.PresubmitError(
758 "Don't commit .rej and .orig files.", problems)]
759 else:
760 return []
761
762
[email protected]1f7b4172010-01-28 01:17:34763def CheckChangeOnUpload(input_api, output_api):
764 results = []
765 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54766 return results
[email protected]ca8d19842009-02-19 16:33:12767
768
769def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:54770 results = []
[email protected]1f7b4172010-01-28 01:17:34771 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:51772 # TODO(thestig) temporarily disabled, doesn't work in third_party/
773 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
774 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:54775 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:27776 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:34777 input_api,
778 output_api,
[email protected]4efa42142010-08-26 01:29:26779 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:27780 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
[email protected]4ddc5df2011-12-12 03:05:04781 output_api, 'http://codereview.chromium.org',
[email protected]c1ba4c52012-03-09 14:23:28782 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
783 '[email protected]'))
[email protected]806e98e2010-03-19 17:49:27784
[email protected]3e4eb112011-01-18 03:29:54785 results.extend(input_api.canned_checks.CheckChangeHasBugField(
786 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:41787 results.extend(input_api.canned_checks.CheckChangeHasDescription(
788 input_api, output_api))
[email protected]b337cb5b2011-01-23 21:24:05789 results.extend(_CheckSubversionConfig(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54790 return results
[email protected]ca8d19842009-02-19 16:33:12791
792
[email protected]5efb2a822011-09-27 23:06:13793def GetPreferredTrySlaves(project, change):
[email protected]4ce995ea2012-06-27 02:13:10794 files = change.LocalPaths()
795
[email protected]3019c902012-06-29 00:09:03796 if not files:
797 return []
798
[email protected]d668899a2012-09-06 18:16:59799 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
[email protected]641f2e3e2012-09-03 11:16:24800 return ['mac_rel', 'mac_asan']
[email protected]d668899a2012-09-06 18:16:59801 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
[email protected]4ce995ea2012-06-27 02:13:10802 return ['win_rel']
[email protected]d668899a2012-09-06 18:16:59803 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
[email protected]3e2f0402012-11-02 16:28:01804 return ['android_dbg', 'android_clang_dbg']
[email protected]356aa542012-09-19 23:31:29805 if all(re.search('^native_client_sdk', f) for f in files):
806 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
[email protected]de142152012-10-03 23:02:45807 if all(re.search('[/_]ios[/_.]', f) for f in files):
808 return ['ios_rel_device', 'ios_dbg_simulator']
[email protected]4ce995ea2012-06-27 02:13:10809
[email protected]3e2f0402012-11-02 16:28:01810 trybots = [
811 'android_clang_dbg',
812 'android_dbg',
813 'ios_dbg_simulator',
814 'ios_rel_device',
815 'linux_asan',
[email protected]95c989162012-11-29 05:58:25816 'linux_aura',
[email protected]3e2f0402012-11-02 16:28:01817 'linux_chromeos',
818 'linux_clang:compile',
819 'linux_rel',
820 'mac_asan',
821 'mac_rel',
[email protected]95c989162012-11-29 05:58:25822 'win_aura',
[email protected]3e2f0402012-11-02 16:28:01823 'win_rel',
824 ]
[email protected]911753b2012-08-02 12:11:54825
826 # Match things like path/aura/file.cc and path/file_aura.cc.
[email protected]95c989162012-11-29 05:58:25827 # Same for chromeos.
828 if any(re.search('[/_](aura|chromeos)', f) for f in files):
[email protected]3e2f0402012-11-02 16:28:01829 trybots += ['linux_chromeos_clang:compile', 'linux_chromeos_asan']
[email protected]4ce995ea2012-06-27 02:13:10830
[email protected]4ce995ea2012-06-27 02:13:10831 return trybots