blob: 9331c0eb6a87900ec65f3533627f9de31e4661e7 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-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]ca8d1982009-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]8886ffcb2013-02-12 04:56:2821 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0822 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r"^skia[\\\/].*",
24 r"^v8[\\\/].*",
25 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5326 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3427 r".+[\\\/]pnacl_shim\.c$",
[email protected]4306417642009-06-11 00:33:4028)
[email protected]ca8d1982009-02-19 16:33:1229
[email protected]06e6d0ff2012-12-11 01:36:4430# Fragment of a regular expression that matches C++ and Objective-C++
31# implementation files.
32_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
33
34# Regular expression that matches code only used for test binaries
35# (best effort).
36_TEST_CODE_EXCLUDED_PATHS = (
37 r'.*[/\\](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
38 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]11e06082013-04-26 19:09:0339 r'.+_(api|browser|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1240 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4441 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
42 r'.*[/\\](test|tool(s)?)[/\\].*',
43 # At request of folks maintaining this folder.
44 r'chrome[/\\]browser[/\\]automation[/\\].*',
45)
[email protected]ca8d1982009-02-19 16:33:1246
[email protected]eea609a2011-11-18 13:10:1247_TEST_ONLY_WARNING = (
48 'You might be calling functions intended only for testing from\n'
49 'production code. It is OK to ignore this warning if you know what\n'
50 'you are doing, as the heuristics used to detect the situation are\n'
51 'not perfect. The commit queue will not block on this warning.\n'
52 'Email [email protected] if you have questions.')
53
54
[email protected]cf9b78f2012-11-14 11:40:2855_INCLUDE_ORDER_WARNING = (
56 'Your #include order seems to be broken. Send mail to\n'
57 '[email protected] if this is not the case.')
58
59
[email protected]127f18ec2012-06-16 05:05:5960_BANNED_OBJC_FUNCTIONS = (
61 (
62 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2063 (
64 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5965 'prohibited. Please use CrTrackingArea instead.',
66 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
67 ),
68 False,
69 ),
70 (
71 'NSTrackingArea',
[email protected]23e6cbc2012-06-16 18:51:2072 (
73 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5974 'instead.',
75 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
76 ),
77 False,
78 ),
79 (
80 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2081 (
82 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5983 'Please use |convertPoint:(point) fromView:nil| instead.',
84 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
85 ),
86 True,
87 ),
88 (
89 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2090 (
91 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5992 'Please use |convertPoint:(point) toView:nil| instead.',
93 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
94 ),
95 True,
96 ),
97 (
98 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2099 (
100 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59101 'Please use |convertRect:(point) fromView:nil| instead.',
102 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
103 ),
104 True,
105 ),
106 (
107 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20108 (
109 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59110 'Please use |convertRect:(point) toView:nil| instead.',
111 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
112 ),
113 True,
114 ),
115 (
116 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20117 (
118 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59119 'Please use |convertSize:(point) fromView:nil| instead.',
120 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
121 ),
122 True,
123 ),
124 (
125 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20126 (
127 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59128 'Please use |convertSize:(point) toView:nil| instead.',
129 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
130 ),
131 True,
132 ),
133)
134
135
136_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20137 # Make sure that gtest's FRIEND_TEST() macro is not used; the
138 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30139 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20140 (
141 'FRIEND_TEST(',
142 (
[email protected]e3c945502012-06-26 20:01:49143 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20144 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
145 ),
146 False,
[email protected]7345da02012-11-27 14:31:49147 (),
[email protected]23e6cbc2012-06-16 18:51:20148 ),
149 (
150 'ScopedAllowIO',
151 (
[email protected]e3c945502012-06-26 20:01:49152 'New code should not use ScopedAllowIO. Post a task to the blocking',
153 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20154 ),
[email protected]e3c945502012-06-26 20:01:49155 True,
[email protected]7345da02012-11-27 14:31:49156 (
157 r"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
[email protected]398ad132013-04-02 15:11:01158 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]7345da02012-11-27 14:31:49159 ),
[email protected]23e6cbc2012-06-16 18:51:20160 ),
[email protected]127f18ec2012-06-16 05:05:59161)
162
163
[email protected]b00342e7f2013-03-26 16:21:54164_VALID_OS_MACROS = (
165 # Please keep sorted.
166 'OS_ANDROID',
167 'OS_BSD',
168 'OS_CAT', # For testing.
169 'OS_CHROMEOS',
170 'OS_FREEBSD',
171 'OS_IOS',
172 'OS_LINUX',
173 'OS_MACOSX',
174 'OS_NACL',
175 'OS_OPENBSD',
176 'OS_POSIX',
177 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54178 'OS_WIN',
179)
180
181
[email protected]55459852011-08-10 15:17:19182def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
183 """Attempts to prevent use of functions intended only for testing in
184 non-testing code. For now this is just a best-effort implementation
185 that ignores header files and may have some false positives. A
186 better implementation would probably need a proper C++ parser.
187 """
188 # We only scan .cc files and the like, as the declaration of
189 # for-testing functions in header files are hard to distinguish from
190 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44191 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19192
193 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
194 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
195 exclusion_pattern = input_api.re.compile(
196 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
197 base_function_pattern, base_function_pattern))
198
199 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44200 black_list = (_EXCLUDED_PATHS +
201 _TEST_CODE_EXCLUDED_PATHS +
202 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19203 return input_api.FilterSourceFile(
204 affected_file,
205 white_list=(file_inclusion_pattern, ),
206 black_list=black_list)
207
208 problems = []
209 for f in input_api.AffectedSourceFiles(FilterFile):
210 local_path = f.LocalPath()
[email protected]2fdd1f362013-01-16 03:56:03211 lines = input_api.ReadFile(f).splitlines()
212 line_number = 0
213 for line in lines:
214 if (inclusion_pattern.search(line) and
215 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19216 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03217 '%s:%d\n %s' % (local_path, line_number, line.strip()))
218 line_number += 1
[email protected]55459852011-08-10 15:17:19219
220 if problems:
[email protected]f7051d52013-04-02 18:31:42221 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03222 else:
223 return []
[email protected]55459852011-08-10 15:17:19224
225
[email protected]10689ca2011-09-02 02:31:54226def _CheckNoIOStreamInHeaders(input_api, output_api):
227 """Checks to make sure no .h files include <iostream>."""
228 files = []
229 pattern = input_api.re.compile(r'^#include\s*<iostream>',
230 input_api.re.MULTILINE)
231 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
232 if not f.LocalPath().endswith('.h'):
233 continue
234 contents = input_api.ReadFile(f)
235 if pattern.search(contents):
236 files.append(f)
237
238 if len(files):
239 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06240 'Do not #include <iostream> in header files, since it inserts static '
241 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54242 '#include <ostream>. See http://crbug.com/94794',
243 files) ]
244 return []
245
246
[email protected]72df4e782012-06-21 16:28:18247def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
248 """Checks to make sure no source files use UNIT_TEST"""
249 problems = []
250 for f in input_api.AffectedFiles():
251 if (not f.LocalPath().endswith(('.cc', '.mm'))):
252 continue
253
254 for line_num, line in f.ChangedContents():
255 if 'UNIT_TEST' in line:
256 problems.append(' %s:%d' % (f.LocalPath(), line_num))
257
258 if not problems:
259 return []
260 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
261 '\n'.join(problems))]
262
263
[email protected]8ea5d4b2011-09-13 21:49:22264def _CheckNoNewWStrings(input_api, output_api):
265 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27266 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22267 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20268 if (not f.LocalPath().endswith(('.cc', '.h')) or
269 f.LocalPath().endswith('test.cc')):
270 continue
[email protected]8ea5d4b2011-09-13 21:49:22271
[email protected]a11dbe9b2012-08-07 01:32:58272 allowWString = False
[email protected]b5c24292011-11-28 14:38:20273 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58274 if 'presubmit: allow wstring' in line:
275 allowWString = True
276 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27277 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58278 allowWString = False
279 else:
280 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22281
[email protected]55463aa62011-10-12 00:48:27282 if not problems:
283 return []
284 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58285 ' If you are calling a cross-platform API that accepts a wstring, '
286 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27287 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22288
289
[email protected]2a8ac9c2011-10-19 17:20:44290def _CheckNoDEPSGIT(input_api, output_api):
291 """Make sure .DEPS.git is never modified manually."""
292 if any(f.LocalPath().endswith('.DEPS.git') for f in
293 input_api.AffectedFiles()):
294 return [output_api.PresubmitError(
295 'Never commit changes to .DEPS.git. This file is maintained by an\n'
296 'automated system based on what\'s in DEPS and your changes will be\n'
297 'overwritten.\n'
298 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
299 'for more information')]
300 return []
301
302
[email protected]127f18ec2012-06-16 05:05:59303def _CheckNoBannedFunctions(input_api, output_api):
304 """Make sure that banned functions are not used."""
305 warnings = []
306 errors = []
307
308 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
309 for f in input_api.AffectedFiles(file_filter=file_filter):
310 for line_num, line in f.ChangedContents():
311 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
312 if func_name in line:
313 problems = warnings;
314 if error:
315 problems = errors;
316 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
317 for message_line in message:
318 problems.append(' %s' % message_line)
319
320 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
321 for f in input_api.AffectedFiles(file_filter=file_filter):
322 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49323 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
324 def IsBlacklisted(affected_file, blacklist):
325 local_path = affected_file.LocalPath()
326 for item in blacklist:
327 if input_api.re.match(item, local_path):
328 return True
329 return False
330 if IsBlacklisted(f, excluded_paths):
331 continue
[email protected]127f18ec2012-06-16 05:05:59332 if func_name in line:
333 problems = warnings;
334 if error:
335 problems = errors;
336 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
337 for message_line in message:
338 problems.append(' %s' % message_line)
339
340 result = []
341 if (warnings):
342 result.append(output_api.PresubmitPromptWarning(
343 'Banned functions were used.\n' + '\n'.join(warnings)))
344 if (errors):
345 result.append(output_api.PresubmitError(
346 'Banned functions were used.\n' + '\n'.join(errors)))
347 return result
348
349
[email protected]6c063c62012-07-11 19:11:06350def _CheckNoPragmaOnce(input_api, output_api):
351 """Make sure that banned functions are not used."""
352 files = []
353 pattern = input_api.re.compile(r'^#pragma\s+once',
354 input_api.re.MULTILINE)
355 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
356 if not f.LocalPath().endswith('.h'):
357 continue
358 contents = input_api.ReadFile(f)
359 if pattern.search(contents):
360 files.append(f)
361
362 if files:
363 return [output_api.PresubmitError(
364 'Do not use #pragma once in header files.\n'
365 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
366 files)]
367 return []
368
[email protected]127f18ec2012-06-16 05:05:59369
[email protected]e7479052012-09-19 00:26:12370def _CheckNoTrinaryTrueFalse(input_api, output_api):
371 """Checks to make sure we don't introduce use of foo ? true : false."""
372 problems = []
373 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
374 for f in input_api.AffectedFiles():
375 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
376 continue
377
378 for line_num, line in f.ChangedContents():
379 if pattern.match(line):
380 problems.append(' %s:%d' % (f.LocalPath(), line_num))
381
382 if not problems:
383 return []
384 return [output_api.PresubmitPromptWarning(
385 'Please consider avoiding the "? true : false" pattern if possible.\n' +
386 '\n'.join(problems))]
387
388
[email protected]55f9f382012-07-31 11:02:18389def _CheckUnwantedDependencies(input_api, output_api):
390 """Runs checkdeps on #include statements added in this
391 change. Breaking - rules is an error, breaking ! rules is a
392 warning.
393 """
394 # We need to wait until we have an input_api object and use this
395 # roundabout construct to import checkdeps because this file is
396 # eval-ed and thus doesn't have __file__.
397 original_sys_path = sys.path
398 try:
399 sys.path = sys.path + [input_api.os_path.join(
400 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
401 import checkdeps
402 from cpp_checker import CppChecker
403 from rules import Rule
404 finally:
405 # Restore sys.path to what it was before.
406 sys.path = original_sys_path
407
408 added_includes = []
409 for f in input_api.AffectedFiles():
410 if not CppChecker.IsCppFile(f.LocalPath()):
411 continue
412
413 changed_lines = [line for line_num, line in f.ChangedContents()]
414 added_includes.append([f.LocalPath(), changed_lines])
415
416 deps_checker = checkdeps.DepsChecker()
417
418 error_descriptions = []
419 warning_descriptions = []
420 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
421 added_includes):
422 description_with_path = '%s\n %s' % (path, rule_description)
423 if rule_type == Rule.DISALLOW:
424 error_descriptions.append(description_with_path)
425 else:
426 warning_descriptions.append(description_with_path)
427
428 results = []
429 if error_descriptions:
430 results.append(output_api.PresubmitError(
431 'You added one or more #includes that violate checkdeps rules.',
432 error_descriptions))
433 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42434 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18435 'You added one or more #includes of files that are temporarily\n'
436 'allowed but being removed. Can you avoid introducing the\n'
437 '#include? See relevant DEPS file(s) for details and contacts.',
438 warning_descriptions))
439 return results
440
441
[email protected]fbcafe5a2012-08-08 15:31:22442def _CheckFilePermissions(input_api, output_api):
443 """Check that all files have their permissions properly set."""
444 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
445 input_api.change.RepositoryRoot()]
446 for f in input_api.AffectedFiles():
447 args += ['--file', f.LocalPath()]
448 errors = []
449 (errors, stderrdata) = subprocess.Popen(args).communicate()
450
451 results = []
452 if errors:
[email protected]c8278b32012-10-30 20:35:49453 results.append(output_api.PresubmitError('checkperms.py failed.',
[email protected]fbcafe5a2012-08-08 15:31:22454 errors))
455 return results
456
457
[email protected]c8278b32012-10-30 20:35:49458def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
459 """Makes sure we don't include ui/aura/window_property.h
460 in header files.
461 """
462 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
463 errors = []
464 for f in input_api.AffectedFiles():
465 if not f.LocalPath().endswith('.h'):
466 continue
467 for line_num, line in f.ChangedContents():
468 if pattern.match(line):
469 errors.append(' %s:%d' % (f.LocalPath(), line_num))
470
471 results = []
472 if errors:
473 results.append(output_api.PresubmitError(
474 'Header files should not include ui/aura/window_property.h', errors))
475 return results
476
477
[email protected]cf9b78f2012-11-14 11:40:28478def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
479 """Checks that the lines in scope occur in the right order.
480
481 1. C system files in alphabetical order
482 2. C++ system files in alphabetical order
483 3. Project's .h files
484 """
485
486 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
487 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
488 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
489
490 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
491
492 state = C_SYSTEM_INCLUDES
493
494 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57495 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28496 problem_linenums = []
497 for line_num, line in scope:
498 if c_system_include_pattern.match(line):
499 if state != C_SYSTEM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57500 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28501 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57502 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28503 elif cpp_system_include_pattern.match(line):
504 if state == C_SYSTEM_INCLUDES:
505 state = CPP_SYSTEM_INCLUDES
506 elif state == CUSTOM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57507 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28508 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57509 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28510 elif custom_include_pattern.match(line):
511 if state != CUSTOM_INCLUDES:
512 state = CUSTOM_INCLUDES
513 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57514 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28515 else:
516 problem_linenums.append(line_num)
517 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57518 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28519
520 warnings = []
[email protected]728b9bb2012-11-14 20:38:57521 for (line_num, previous_line_num) in problem_linenums:
522 if line_num in changed_linenums or previous_line_num in changed_linenums:
[email protected]cf9b78f2012-11-14 11:40:28523 warnings.append(' %s:%d' % (file_path, line_num))
524 return warnings
525
526
[email protected]ac294a12012-12-06 16:38:43527def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28528 """Checks the #include order for the given file f."""
529
[email protected]2299dcf2012-11-15 19:56:24530 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]962f117e2012-11-22 18:11:56531 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
532 # often need to appear in a specific order.
533 excluded_include_pattern = input_api.re.compile(r'\s*#include \<.*/.*')
[email protected]2299dcf2012-11-15 19:56:24534 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]0e5c1852012-12-18 20:17:11535 if_pattern = input_api.re.compile(
536 r'\s*#\s*(if|elif|else|endif|define|undef).*')
537 # Some files need specialized order of includes; exclude such files from this
538 # check.
539 uncheckable_includes_pattern = input_api.re.compile(
540 r'\s*#include '
541 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28542
543 contents = f.NewContents()
544 warnings = []
545 line_num = 0
546
[email protected]ac294a12012-12-06 16:38:43547 # Handle the special first include. If the first include file is
548 # some/path/file.h, the corresponding including file can be some/path/file.cc,
549 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
550 # etc. It's also possible that no special first include exists.
551 for line in contents:
552 line_num += 1
553 if system_include_pattern.match(line):
554 # No special first include -> process the line again along with normal
555 # includes.
556 line_num -= 1
557 break
558 match = custom_include_pattern.match(line)
559 if match:
560 match_dict = match.groupdict()
561 header_basename = input_api.os_path.basename(
562 match_dict['FILE']).replace('.h', '')
563 if header_basename not in input_api.os_path.basename(f.LocalPath()):
[email protected]2299dcf2012-11-15 19:56:24564 # No special first include -> process the line again along with normal
565 # includes.
566 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43567 break
[email protected]cf9b78f2012-11-14 11:40:28568
569 # Split into scopes: Each region between #if and #endif is its own scope.
570 scopes = []
571 current_scope = []
572 for line in contents[line_num:]:
573 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11574 if uncheckable_includes_pattern.match(line):
575 return []
[email protected]2309b0fa02012-11-16 12:18:27576 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28577 scopes.append(current_scope)
578 current_scope = []
[email protected]962f117e2012-11-22 18:11:56579 elif ((system_include_pattern.match(line) or
580 custom_include_pattern.match(line)) and
581 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28582 current_scope.append((line_num, line))
583 scopes.append(current_scope)
584
585 for scope in scopes:
586 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
587 changed_linenums))
588 return warnings
589
590
591def _CheckIncludeOrder(input_api, output_api):
592 """Checks that the #include order is correct.
593
594 1. The corresponding header for source files.
595 2. C system files in alphabetical order
596 3. C++ system files in alphabetical order
597 4. Project's .h files in alphabetical order
598
[email protected]ac294a12012-12-06 16:38:43599 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
600 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28601 """
602
603 warnings = []
604 for f in input_api.AffectedFiles():
[email protected]ac294a12012-12-06 16:38:43605 if f.LocalPath().endswith(('.cc', '.h')):
606 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
607 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28608
609 results = []
610 if warnings:
[email protected]f7051d52013-04-02 18:31:42611 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53612 warnings))
[email protected]cf9b78f2012-11-14 11:40:28613 return results
614
615
[email protected]70ca77752012-11-20 03:45:03616def _CheckForVersionControlConflictsInFile(input_api, f):
617 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
618 errors = []
619 for line_num, line in f.ChangedContents():
620 if pattern.match(line):
621 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
622 return errors
623
624
625def _CheckForVersionControlConflicts(input_api, output_api):
626 """Usually this is not intentional and will cause a compile failure."""
627 errors = []
628 for f in input_api.AffectedFiles():
629 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
630
631 results = []
632 if errors:
633 results.append(output_api.PresubmitError(
634 'Version control conflict markers found, please resolve.', errors))
635 return results
636
637
[email protected]06e6d0ff2012-12-11 01:36:44638def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
639 def FilterFile(affected_file):
640 """Filter function for use with input_api.AffectedSourceFiles,
641 below. This filters out everything except non-test files from
642 top-level directories that generally speaking should not hard-code
643 service URLs (e.g. src/android_webview/, src/content/ and others).
644 """
645 return input_api.FilterSourceFile(
646 affected_file,
[email protected]78bb39d62012-12-11 15:11:56647 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44648 black_list=(_EXCLUDED_PATHS +
649 _TEST_CODE_EXCLUDED_PATHS +
650 input_api.DEFAULT_BLACK_LIST))
651
652 pattern = input_api.re.compile('"[^"]*google\.com[^"]*"')
653 problems = [] # items are (filename, line_number, line)
654 for f in input_api.AffectedSourceFiles(FilterFile):
655 for line_num, line in f.ChangedContents():
656 if pattern.search(line):
657 problems.append((f.LocalPath(), line_num, line))
658
659 if problems:
[email protected]f7051d52013-04-02 18:31:42660 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44661 'Most layers below src/chrome/ should not hardcode service URLs.\n'
662 'Are you sure this is correct? (Contact: [email protected])',
663 [' %s:%d: %s' % (
664 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03665 else:
666 return []
[email protected]06e6d0ff2012-12-11 01:36:44667
668
[email protected]d2530012013-01-25 16:39:27669def _CheckNoAbbreviationInPngFileName(input_api, output_api):
670 """Makes sure there are no abbreviations in the name of PNG files.
671 """
[email protected]4053a48e2013-01-25 21:43:04672 pattern = input_api.re.compile(r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$')
[email protected]d2530012013-01-25 16:39:27673 errors = []
674 for f in input_api.AffectedFiles(include_deletes=False):
675 if pattern.match(f.LocalPath()):
676 errors.append(' %s' % f.LocalPath())
677
678 results = []
679 if errors:
680 results.append(output_api.PresubmitError(
681 'The name of PNG files should not have abbreviations. \n'
682 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
683 'Contact [email protected] if you have questions.', errors))
684 return results
685
686
[email protected]22c9bd72011-03-27 16:47:39687def _CommonChecks(input_api, output_api):
688 """Checks common to both upload and commit."""
689 results = []
690 results.extend(input_api.canned_checks.PanProjectChecks(
691 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
[email protected]66daa702011-05-28 14:41:46692 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:19693 results.extend(
694 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:54695 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:18696 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:22697 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:44698 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:59699 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:06700 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:12701 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:18702 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:22703 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:49704 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:27705 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:03706 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:49707 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:44708 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:27709 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:54710 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:24711
712 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
713 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
714 input_api, output_api,
715 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:38716 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:39717 return results
[email protected]1f7b4172010-01-28 01:17:34718
[email protected]b337cb5b2011-01-23 21:24:05719
720def _CheckSubversionConfig(input_api, output_api):
721 """Verifies the subversion config file is correctly setup.
722
723 Checks that autoprops are enabled, returns an error otherwise.
724 """
725 join = input_api.os_path.join
726 if input_api.platform == 'win32':
727 appdata = input_api.environ.get('APPDATA', '')
728 if not appdata:
729 return [output_api.PresubmitError('%APPDATA% is not configured.')]
730 path = join(appdata, 'Subversion', 'config')
731 else:
732 home = input_api.environ.get('HOME', '')
733 if not home:
734 return [output_api.PresubmitError('$HOME is not configured.')]
735 path = join(home, '.subversion', 'config')
736
737 error_msg = (
738 'Please look at http://dev.chromium.org/developers/coding-style to\n'
739 'configure your subversion configuration file. This enables automatic\n'
[email protected]c6a3c10b2011-01-24 16:14:20740 'properties to simplify the project maintenance.\n'
741 'Pro-tip: just download and install\n'
742 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
[email protected]b337cb5b2011-01-23 21:24:05743
744 try:
745 lines = open(path, 'r').read().splitlines()
746 # Make sure auto-props is enabled and check for 2 Chromium standard
747 # auto-prop.
748 if (not '*.cc = svn:eol-style=LF' in lines or
749 not '*.pdf = svn:mime-type=application/pdf' in lines or
750 not 'enable-auto-props = yes' in lines):
751 return [
[email protected]79ed7e62011-02-21 21:08:53752 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05753 'It looks like you have not configured your subversion config '
[email protected]b5359c02011-02-01 20:29:56754 'file or it is not up-to-date.\n' + error_msg)
[email protected]b337cb5b2011-01-23 21:24:05755 ]
756 except (OSError, IOError):
757 return [
[email protected]79ed7e62011-02-21 21:08:53758 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05759 'Can\'t find your subversion config file.\n' + error_msg)
760 ]
761 return []
762
763
[email protected]66daa702011-05-28 14:41:46764def _CheckAuthorizedAuthor(input_api, output_api):
765 """For non-googler/chromites committers, verify the author's email address is
766 in AUTHORS.
767 """
[email protected]9bb9cb82011-06-13 20:43:01768 # TODO(maruel): Add it to input_api?
769 import fnmatch
770
[email protected]66daa702011-05-28 14:41:46771 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:01772 if not author:
773 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:46774 return []
[email protected]c99663292011-05-31 19:46:08775 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:46776 input_api.PresubmitLocalPath(), 'AUTHORS')
777 valid_authors = (
778 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
779 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:18780 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:44781 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:23782 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:46783 return [output_api.PresubmitPromptWarning(
784 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
785 '\n'
786 'http://www.chromium.org/developers/contributing-code and read the '
787 '"Legal" section\n'
788 'If you are a chromite, verify the contributor signed the CLA.') %
789 author)]
790 return []
791
792
[email protected]b8079ae4a2012-12-05 19:56:49793def _CheckPatchFiles(input_api, output_api):
794 problems = [f.LocalPath() for f in input_api.AffectedFiles()
795 if f.LocalPath().endswith(('.orig', '.rej'))]
796 if problems:
797 return [output_api.PresubmitError(
798 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:03799 else:
800 return []
[email protected]b8079ae4a2012-12-05 19:56:49801
802
[email protected]b00342e7f2013-03-26 16:21:54803def _DidYouMeanOSMacro(bad_macro):
804 try:
805 return {'A': 'OS_ANDROID',
806 'B': 'OS_BSD',
807 'C': 'OS_CHROMEOS',
808 'F': 'OS_FREEBSD',
809 'L': 'OS_LINUX',
810 'M': 'OS_MACOSX',
811 'N': 'OS_NACL',
812 'O': 'OS_OPENBSD',
813 'P': 'OS_POSIX',
814 'S': 'OS_SOLARIS',
815 'W': 'OS_WIN'}[bad_macro[3].upper()]
816 except KeyError:
817 return ''
818
819
820def _CheckForInvalidOSMacrosInFile(input_api, f):
821 """Check for sensible looking, totally invalid OS macros."""
822 preprocessor_statement = input_api.re.compile(r'^\s*#')
823 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
824 results = []
825 for lnum, line in f.ChangedContents():
826 if preprocessor_statement.search(line):
827 for match in os_macro.finditer(line):
828 if not match.group(1) in _VALID_OS_MACROS:
829 good = _DidYouMeanOSMacro(match.group(1))
830 did_you_mean = ' (did you mean %s?)' % good if good else ''
831 results.append(' %s:%d %s%s' % (f.LocalPath(),
832 lnum,
833 match.group(1),
834 did_you_mean))
835 return results
836
837
838def _CheckForInvalidOSMacros(input_api, output_api):
839 """Check all affected files for invalid OS macros."""
840 bad_macros = []
841 for f in input_api.AffectedFiles():
842 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
843 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
844
845 if not bad_macros:
846 return []
847
848 return [output_api.PresubmitError(
849 'Possibly invalid OS macro[s] found. Please fix your code\n'
850 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
851
852
[email protected]1f7b4172010-01-28 01:17:34853def CheckChangeOnUpload(input_api, output_api):
854 results = []
855 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54856 return results
[email protected]ca8d1982009-02-19 16:33:12857
858
859def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:54860 results = []
[email protected]1f7b4172010-01-28 01:17:34861 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:51862 # TODO(thestig) temporarily disabled, doesn't work in third_party/
863 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
864 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:54865 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:27866 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:34867 input_api,
868 output_api,
[email protected]2fdd1f362013-01-16 03:56:03869 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:27870 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
[email protected]2fdd1f362013-01-16 03:56:03871 output_api, 'http://codereview.chromium.org',
[email protected]c1ba4c52012-03-09 14:23:28872 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
873 '[email protected]'))
[email protected]806e98e2010-03-19 17:49:27874
[email protected]3e4eb112011-01-18 03:29:54875 results.extend(input_api.canned_checks.CheckChangeHasBugField(
876 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:41877 results.extend(input_api.canned_checks.CheckChangeHasDescription(
878 input_api, output_api))
[email protected]b337cb5b2011-01-23 21:24:05879 results.extend(_CheckSubversionConfig(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54880 return results
[email protected]ca8d1982009-02-19 16:33:12881
882
[email protected]5efb2a822011-09-27 23:06:13883def GetPreferredTrySlaves(project, change):
[email protected]4ce995ea2012-06-27 02:13:10884 files = change.LocalPaths()
885
[email protected]751b05f2013-01-10 23:12:17886 if not files or all(re.search(r'[\\/]OWNERS$', f) for f in files):
[email protected]3019c902012-06-29 00:09:03887 return []
888
[email protected]d668899a2012-09-06 18:16:59889 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
[email protected]7fab6202013-02-21 17:54:35890 return ['mac_rel', 'mac_asan', 'mac:compile']
[email protected]d668899a2012-09-06 18:16:59891 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
[email protected]7fab6202013-02-21 17:54:35892 return ['win_rel', 'win7_aura', 'win:compile']
[email protected]d668899a2012-09-06 18:16:59893 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
[email protected]3e2f0402012-11-02 16:28:01894 return ['android_dbg', 'android_clang_dbg']
[email protected]356aa542012-09-19 23:31:29895 if all(re.search('^native_client_sdk', f) for f in files):
896 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
[email protected]de142152012-10-03 23:02:45897 if all(re.search('[/_]ios[/_.]', f) for f in files):
898 return ['ios_rel_device', 'ios_dbg_simulator']
[email protected]4ce995ea2012-06-27 02:13:10899
[email protected]3e2f0402012-11-02 16:28:01900 trybots = [
901 'android_clang_dbg',
902 'android_dbg',
903 'ios_dbg_simulator',
904 'ios_rel_device',
905 'linux_asan',
[email protected]95c989162012-11-29 05:58:25906 'linux_aura',
[email protected]3e2f0402012-11-02 16:28:01907 'linux_chromeos',
908 'linux_clang:compile',
909 'linux_rel',
910 'mac_asan',
911 'mac_rel',
[email protected]7fab6202013-02-21 17:54:35912 'mac:compile',
[email protected]aa85c8b2013-01-11 04:20:28913 'win7_aura',
[email protected]3e2f0402012-11-02 16:28:01914 'win_rel',
[email protected]7fab6202013-02-21 17:54:35915 'win:compile',
[email protected]3e2f0402012-11-02 16:28:01916 ]
[email protected]911753b2012-08-02 12:11:54917
918 # Match things like path/aura/file.cc and path/file_aura.cc.
[email protected]95c989162012-11-29 05:58:25919 # Same for chromeos.
920 if any(re.search('[/_](aura|chromeos)', f) for f in files):
[email protected]3e2f0402012-11-02 16:28:01921 trybots += ['linux_chromeos_clang:compile', 'linux_chromeos_asan']
[email protected]4ce995ea2012-06-27 02:13:10922
[email protected]4ce995ea2012-06-27 02:13:10923 return trybots