blob: e1e866133cafa8eed25d68c28d397c130cf1b49f [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]db9d45a5f2012-11-27 16:24:46155 'chrome::FindLastActiveWithProfile',
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',
159 'id. Talk to robertshield@ for more information.',
160 ),
161 True,
[email protected]282c30d2012-11-27 16:47:12162 (),
[email protected]db9d45a5f2012-11-27 16:24:46163 ),
164 (
[email protected]e3c945502012-06-26 20:01:49165 'browser::FindAnyBrowser',
166 (
167 'This function is deprecated and we\'re working on removing it. Pass',
168 'more context to get a Browser*, like a WebContents, window, or session',
[email protected]1099dbd2012-11-01 19:56:02169 'id. Talk to robertshield@ for more information.',
[email protected]e3c945502012-06-26 20:01:49170 ),
171 True,
[email protected]7345da02012-11-27 14:31:49172 (),
[email protected]e3c945502012-06-26 20:01:49173 ),
174 (
175 'browser::FindOrCreateTabbedBrowser',
176 (
177 'This function is deprecated and we\'re working on removing it. Pass',
178 'more context to get a Browser*, like a WebContents, window, or session',
[email protected]1099dbd2012-11-01 19:56:02179 'id. Talk to robertshield@ for more information.',
[email protected]e3c945502012-06-26 20:01:49180 ),
181 True,
[email protected]7345da02012-11-27 14:31:49182 (),
[email protected]e3c945502012-06-26 20:01:49183 ),
184 (
[email protected]1099dbd2012-11-01 19:56:02185 'browser::FindTabbedBrowserDeprecated',
[email protected]e3c945502012-06-26 20:01:49186 (
187 'This function is deprecated and we\'re working on removing it. Pass',
188 'more context to get a Browser*, like a WebContents, window, or session',
[email protected]1099dbd2012-11-01 19:56:02189 'id. Talk to robertshield@ for more information.',
[email protected]e3c945502012-06-26 20:01:49190 ),
191 True,
[email protected]7345da02012-11-27 14:31:49192 (),
[email protected]e3c945502012-06-26 20:01:49193 ),
[email protected]bb5eff1cc2012-11-01 20:46:29194 (
195 'RunAllPending()',
196 (
197 'This function is deprecated and we\'re working on removing it. Rename',
198 'to RunUntilIdle',
199 ),
200 True,
[email protected]7345da02012-11-27 14:31:49201 (),
[email protected]bb5eff1cc2012-11-01 20:46:29202 ),
[email protected]127f18ec2012-06-16 05:05:59203)
204
205
[email protected]eea609a2011-11-18 13:10:12206
[email protected]55459852011-08-10 15:17:19207def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
208 """Attempts to prevent use of functions intended only for testing in
209 non-testing code. For now this is just a best-effort implementation
210 that ignores header files and may have some false positives. A
211 better implementation would probably need a proper C++ parser.
212 """
213 # We only scan .cc files and the like, as the declaration of
214 # for-testing functions in header files are hard to distinguish from
215 # calls to such functions without a proper C++ parser.
[email protected]403bfbc92012-06-11 23:30:09216 platform_specifiers = r'(_(android|chromeos|gtk|mac|posix|win))?'
[email protected]55459852011-08-10 15:17:19217 source_extensions = r'\.(cc|cpp|cxx|mm)$'
218 file_inclusion_pattern = r'.+%s' % source_extensions
[email protected]19e77fd2011-10-20 05:24:05219 file_exclusion_patterns = (
[email protected]44e376e2012-10-26 19:40:21220 r'.*[/\\](fake_|test_|mock_).+%s' % source_extensions,
[email protected]c762d252012-02-28 02:07:24221 r'.+_test_(base|support|util)%s' % source_extensions,
[email protected]403bfbc92012-06-11 23:30:09222 r'.+_(api|browser|perf|unit|ui)?test%s%s' % (platform_specifiers,
223 source_extensions),
[email protected]19e77fd2011-10-20 05:24:05224 r'.+profile_sync_service_harness%s' % source_extensions,
225 )
226 path_exclusion_patterns = (
227 r'.*[/\\](test|tool(s)?)[/\\].*',
228 # At request of folks maintaining this folder.
229 r'chrome[/\\]browser[/\\]automation[/\\].*',
230 )
[email protected]55459852011-08-10 15:17:19231
232 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
233 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
234 exclusion_pattern = input_api.re.compile(
235 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
236 base_function_pattern, base_function_pattern))
237
238 def FilterFile(affected_file):
[email protected]19e77fd2011-10-20 05:24:05239 black_list = (file_exclusion_patterns + path_exclusion_patterns +
[email protected]3afb12a42011-08-15 13:48:33240 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19241 return input_api.FilterSourceFile(
242 affected_file,
243 white_list=(file_inclusion_pattern, ),
244 black_list=black_list)
245
246 problems = []
247 for f in input_api.AffectedSourceFiles(FilterFile):
248 local_path = f.LocalPath()
249 lines = input_api.ReadFile(f).splitlines()
250 line_number = 0
251 for line in lines:
252 if (inclusion_pattern.search(line) and
253 not exclusion_pattern.search(line)):
254 problems.append(
255 '%s:%d\n %s' % (local_path, line_number, line.strip()))
256 line_number += 1
257
258 if problems:
[email protected]eea609a2011-11-18 13:10:12259 if not input_api.is_committing:
260 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
261 else:
262 # We don't warn on commit, to avoid stopping commits going through CQ.
263 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
[email protected]55459852011-08-10 15:17:19264 else:
265 return []
266
267
[email protected]10689ca2011-09-02 02:31:54268def _CheckNoIOStreamInHeaders(input_api, output_api):
269 """Checks to make sure no .h files include <iostream>."""
270 files = []
271 pattern = input_api.re.compile(r'^#include\s*<iostream>',
272 input_api.re.MULTILINE)
273 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
274 if not f.LocalPath().endswith('.h'):
275 continue
276 contents = input_api.ReadFile(f)
277 if pattern.search(contents):
278 files.append(f)
279
280 if len(files):
281 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06282 'Do not #include <iostream> in header files, since it inserts static '
283 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54284 '#include <ostream>. See http://crbug.com/94794',
285 files) ]
286 return []
287
288
[email protected]72df4e782012-06-21 16:28:18289def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
290 """Checks to make sure no source files use UNIT_TEST"""
291 problems = []
292 for f in input_api.AffectedFiles():
293 if (not f.LocalPath().endswith(('.cc', '.mm'))):
294 continue
295
296 for line_num, line in f.ChangedContents():
297 if 'UNIT_TEST' in line:
298 problems.append(' %s:%d' % (f.LocalPath(), line_num))
299
300 if not problems:
301 return []
302 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
303 '\n'.join(problems))]
304
305
[email protected]8ea5d4b2011-09-13 21:49:22306def _CheckNoNewWStrings(input_api, output_api):
307 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27308 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22309 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20310 if (not f.LocalPath().endswith(('.cc', '.h')) or
311 f.LocalPath().endswith('test.cc')):
312 continue
[email protected]8ea5d4b2011-09-13 21:49:22313
[email protected]a11dbe9b2012-08-07 01:32:58314 allowWString = False
[email protected]b5c24292011-11-28 14:38:20315 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58316 if 'presubmit: allow wstring' in line:
317 allowWString = True
318 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27319 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58320 allowWString = False
321 else:
322 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22323
[email protected]55463aa62011-10-12 00:48:27324 if not problems:
325 return []
326 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58327 ' If you are calling a cross-platform API that accepts a wstring, '
328 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27329 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22330
331
[email protected]2a8ac9c2011-10-19 17:20:44332def _CheckNoDEPSGIT(input_api, output_api):
333 """Make sure .DEPS.git is never modified manually."""
334 if any(f.LocalPath().endswith('.DEPS.git') for f in
335 input_api.AffectedFiles()):
336 return [output_api.PresubmitError(
337 'Never commit changes to .DEPS.git. This file is maintained by an\n'
338 'automated system based on what\'s in DEPS and your changes will be\n'
339 'overwritten.\n'
340 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
341 'for more information')]
342 return []
343
344
[email protected]127f18ec2012-06-16 05:05:59345def _CheckNoBannedFunctions(input_api, output_api):
346 """Make sure that banned functions are not used."""
347 warnings = []
348 errors = []
349
350 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
351 for f in input_api.AffectedFiles(file_filter=file_filter):
352 for line_num, line in f.ChangedContents():
353 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
354 if func_name in line:
355 problems = warnings;
356 if error:
357 problems = errors;
358 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
359 for message_line in message:
360 problems.append(' %s' % message_line)
361
362 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
363 for f in input_api.AffectedFiles(file_filter=file_filter):
364 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49365 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
366 def IsBlacklisted(affected_file, blacklist):
367 local_path = affected_file.LocalPath()
368 for item in blacklist:
369 if input_api.re.match(item, local_path):
370 return True
371 return False
372 if IsBlacklisted(f, excluded_paths):
373 continue
[email protected]127f18ec2012-06-16 05:05:59374 if func_name in line:
375 problems = warnings;
376 if error:
377 problems = errors;
378 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
379 for message_line in message:
380 problems.append(' %s' % message_line)
381
382 result = []
383 if (warnings):
384 result.append(output_api.PresubmitPromptWarning(
385 'Banned functions were used.\n' + '\n'.join(warnings)))
386 if (errors):
387 result.append(output_api.PresubmitError(
388 'Banned functions were used.\n' + '\n'.join(errors)))
389 return result
390
391
[email protected]6c063c62012-07-11 19:11:06392def _CheckNoPragmaOnce(input_api, output_api):
393 """Make sure that banned functions are not used."""
394 files = []
395 pattern = input_api.re.compile(r'^#pragma\s+once',
396 input_api.re.MULTILINE)
397 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
398 if not f.LocalPath().endswith('.h'):
399 continue
400 contents = input_api.ReadFile(f)
401 if pattern.search(contents):
402 files.append(f)
403
404 if files:
405 return [output_api.PresubmitError(
406 'Do not use #pragma once in header files.\n'
407 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
408 files)]
409 return []
410
[email protected]127f18ec2012-06-16 05:05:59411
[email protected]e7479052012-09-19 00:26:12412def _CheckNoTrinaryTrueFalse(input_api, output_api):
413 """Checks to make sure we don't introduce use of foo ? true : false."""
414 problems = []
415 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
416 for f in input_api.AffectedFiles():
417 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
418 continue
419
420 for line_num, line in f.ChangedContents():
421 if pattern.match(line):
422 problems.append(' %s:%d' % (f.LocalPath(), line_num))
423
424 if not problems:
425 return []
426 return [output_api.PresubmitPromptWarning(
427 'Please consider avoiding the "? true : false" pattern if possible.\n' +
428 '\n'.join(problems))]
429
430
[email protected]55f9f382012-07-31 11:02:18431def _CheckUnwantedDependencies(input_api, output_api):
432 """Runs checkdeps on #include statements added in this
433 change. Breaking - rules is an error, breaking ! rules is a
434 warning.
435 """
436 # We need to wait until we have an input_api object and use this
437 # roundabout construct to import checkdeps because this file is
438 # eval-ed and thus doesn't have __file__.
439 original_sys_path = sys.path
440 try:
441 sys.path = sys.path + [input_api.os_path.join(
442 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
443 import checkdeps
444 from cpp_checker import CppChecker
445 from rules import Rule
446 finally:
447 # Restore sys.path to what it was before.
448 sys.path = original_sys_path
449
450 added_includes = []
451 for f in input_api.AffectedFiles():
452 if not CppChecker.IsCppFile(f.LocalPath()):
453 continue
454
455 changed_lines = [line for line_num, line in f.ChangedContents()]
456 added_includes.append([f.LocalPath(), changed_lines])
457
458 deps_checker = checkdeps.DepsChecker()
459
460 error_descriptions = []
461 warning_descriptions = []
462 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
463 added_includes):
464 description_with_path = '%s\n %s' % (path, rule_description)
465 if rule_type == Rule.DISALLOW:
466 error_descriptions.append(description_with_path)
467 else:
468 warning_descriptions.append(description_with_path)
469
470 results = []
471 if error_descriptions:
472 results.append(output_api.PresubmitError(
473 'You added one or more #includes that violate checkdeps rules.',
474 error_descriptions))
475 if warning_descriptions:
[email protected]779caa52012-08-21 17:05:59476 if not input_api.is_committing:
477 warning_factory = output_api.PresubmitPromptWarning
478 else:
479 # We don't want to block use of the CQ when there is a warning
480 # of this kind, so we only show a message when committing.
481 warning_factory = output_api.PresubmitNotifyResult
482 results.append(warning_factory(
[email protected]55f9f382012-07-31 11:02:18483 'You added one or more #includes of files that are temporarily\n'
484 'allowed but being removed. Can you avoid introducing the\n'
485 '#include? See relevant DEPS file(s) for details and contacts.',
486 warning_descriptions))
487 return results
488
489
[email protected]fbcafe5a2012-08-08 15:31:22490def _CheckFilePermissions(input_api, output_api):
491 """Check that all files have their permissions properly set."""
492 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
493 input_api.change.RepositoryRoot()]
494 for f in input_api.AffectedFiles():
495 args += ['--file', f.LocalPath()]
496 errors = []
497 (errors, stderrdata) = subprocess.Popen(args).communicate()
498
499 results = []
500 if errors:
[email protected]c8278b32012-10-30 20:35:49501 results.append(output_api.PresubmitError('checkperms.py failed.',
[email protected]fbcafe5a2012-08-08 15:31:22502 errors))
503 return results
504
505
[email protected]c8278b32012-10-30 20:35:49506def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
507 """Makes sure we don't include ui/aura/window_property.h
508 in header files.
509 """
510 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
511 errors = []
512 for f in input_api.AffectedFiles():
513 if not f.LocalPath().endswith('.h'):
514 continue
515 for line_num, line in f.ChangedContents():
516 if pattern.match(line):
517 errors.append(' %s:%d' % (f.LocalPath(), line_num))
518
519 results = []
520 if errors:
521 results.append(output_api.PresubmitError(
522 'Header files should not include ui/aura/window_property.h', errors))
523 return results
524
525
[email protected]cf9b78f2012-11-14 11:40:28526def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
527 """Checks that the lines in scope occur in the right order.
528
529 1. C system files in alphabetical order
530 2. C++ system files in alphabetical order
531 3. Project's .h files
532 """
533
534 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
535 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
536 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
537
538 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
539
540 state = C_SYSTEM_INCLUDES
541
542 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57543 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28544 problem_linenums = []
545 for line_num, line in scope:
546 if c_system_include_pattern.match(line):
547 if state != C_SYSTEM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57548 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28549 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57550 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28551 elif cpp_system_include_pattern.match(line):
552 if state == C_SYSTEM_INCLUDES:
553 state = CPP_SYSTEM_INCLUDES
554 elif state == CUSTOM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57555 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28556 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57557 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28558 elif custom_include_pattern.match(line):
559 if state != CUSTOM_INCLUDES:
560 state = CUSTOM_INCLUDES
561 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57562 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28563 else:
564 problem_linenums.append(line_num)
565 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57566 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28567
568 warnings = []
[email protected]728b9bb2012-11-14 20:38:57569 for (line_num, previous_line_num) in problem_linenums:
570 if line_num in changed_linenums or previous_line_num in changed_linenums:
[email protected]cf9b78f2012-11-14 11:40:28571 warnings.append(' %s:%d' % (file_path, line_num))
572 return warnings
573
574
[email protected]2299dcf2012-11-15 19:56:24575def _CheckIncludeOrderInFile(input_api, f, is_source, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28576 """Checks the #include order for the given file f."""
577
[email protected]2299dcf2012-11-15 19:56:24578 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]962f117e2012-11-22 18:11:56579 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
580 # often need to appear in a specific order.
581 excluded_include_pattern = input_api.re.compile(r'\s*#include \<.*/.*')
[email protected]2299dcf2012-11-15 19:56:24582 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]2309b0fa02012-11-16 12:18:27583 if_pattern = input_api.re.compile(r'\s*#\s*(if|elif|else|endif).*')
[email protected]cf9b78f2012-11-14 11:40:28584
585 contents = f.NewContents()
586 warnings = []
587 line_num = 0
588
[email protected]2299dcf2012-11-15 19:56:24589 # Handle the special first include for source files. If the header file is
590 # some/path/file.h, the corresponding source file can be some/path/file.cc,
591 # some/other/path/file.cc, some/path/file_platform.cc etc. It's also possible
592 # that no special first include exists.
[email protected]cf9b78f2012-11-14 11:40:28593 if is_source:
594 for line in contents:
595 line_num += 1
[email protected]2299dcf2012-11-15 19:56:24596 if system_include_pattern.match(line):
597 # No special first include -> process the line again along with normal
598 # includes.
599 line_num -= 1
600 break
601 match = custom_include_pattern.match(line)
602 if match:
603 match_dict = match.groupdict()
604 header_basename = input_api.os_path.basename(
605 match_dict['FILE']).replace('.h', '')
606 if header_basename not in input_api.os_path.basename(f.LocalPath()):
607 # No special first include -> process the line again along with normal
608 # includes.
[email protected]cf9b78f2012-11-14 11:40:28609 line_num -= 1
610 break
611
612 # Split into scopes: Each region between #if and #endif is its own scope.
613 scopes = []
614 current_scope = []
615 for line in contents[line_num:]:
616 line_num += 1
[email protected]2309b0fa02012-11-16 12:18:27617 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28618 scopes.append(current_scope)
619 current_scope = []
[email protected]962f117e2012-11-22 18:11:56620 elif ((system_include_pattern.match(line) or
621 custom_include_pattern.match(line)) and
622 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28623 current_scope.append((line_num, line))
624 scopes.append(current_scope)
625
626 for scope in scopes:
627 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
628 changed_linenums))
629 return warnings
630
631
632def _CheckIncludeOrder(input_api, output_api):
633 """Checks that the #include order is correct.
634
635 1. The corresponding header for source files.
636 2. C system files in alphabetical order
637 3. C++ system files in alphabetical order
638 4. Project's .h files in alphabetical order
639
640 Each region between #if and #endif follows these rules separately.
641 """
642
643 warnings = []
644 for f in input_api.AffectedFiles():
645 changed_linenums = set([line_num for line_num, _ in f.ChangedContents()])
646 if f.LocalPath().endswith('.cc'):
[email protected]2299dcf2012-11-15 19:56:24647 warnings.extend(_CheckIncludeOrderInFile(input_api, f, True,
648 changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28649 elif f.LocalPath().endswith('.h'):
[email protected]2299dcf2012-11-15 19:56:24650 warnings.extend(_CheckIncludeOrderInFile(input_api, f, False,
651 changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28652
653 results = []
654 if warnings:
655 results.append(output_api.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING,
656 warnings))
657 return results
658
659
[email protected]70ca77752012-11-20 03:45:03660def _CheckForVersionControlConflictsInFile(input_api, f):
661 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
662 errors = []
663 for line_num, line in f.ChangedContents():
664 if pattern.match(line):
665 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
666 return errors
667
668
669def _CheckForVersionControlConflicts(input_api, output_api):
670 """Usually this is not intentional and will cause a compile failure."""
671 errors = []
672 for f in input_api.AffectedFiles():
673 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
674
675 results = []
676 if errors:
677 results.append(output_api.PresubmitError(
678 'Version control conflict markers found, please resolve.', errors))
679 return results
680
681
[email protected]22c9bd72011-03-27 16:47:39682def _CommonChecks(input_api, output_api):
683 """Checks common to both upload and commit."""
684 results = []
685 results.extend(input_api.canned_checks.PanProjectChecks(
686 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
[email protected]66daa702011-05-28 14:41:46687 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:19688 results.extend(
689 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:54690 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:18691 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:22692 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:44693 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:59694 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:06695 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:12696 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:18697 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:22698 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:49699 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:27700 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:03701 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:24702
703 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
704 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
705 input_api, output_api,
706 input_api.PresubmitLocalPath(),
707 whitelist=[r'.+_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:39708 return results
[email protected]1f7b4172010-01-28 01:17:34709
[email protected]b337cb5b2011-01-23 21:24:05710
711def _CheckSubversionConfig(input_api, output_api):
712 """Verifies the subversion config file is correctly setup.
713
714 Checks that autoprops are enabled, returns an error otherwise.
715 """
716 join = input_api.os_path.join
717 if input_api.platform == 'win32':
718 appdata = input_api.environ.get('APPDATA', '')
719 if not appdata:
720 return [output_api.PresubmitError('%APPDATA% is not configured.')]
721 path = join(appdata, 'Subversion', 'config')
722 else:
723 home = input_api.environ.get('HOME', '')
724 if not home:
725 return [output_api.PresubmitError('$HOME is not configured.')]
726 path = join(home, '.subversion', 'config')
727
728 error_msg = (
729 'Please look at http://dev.chromium.org/developers/coding-style to\n'
730 'configure your subversion configuration file. This enables automatic\n'
[email protected]c6a3c10b2011-01-24 16:14:20731 'properties to simplify the project maintenance.\n'
732 'Pro-tip: just download and install\n'
733 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
[email protected]b337cb5b2011-01-23 21:24:05734
735 try:
736 lines = open(path, 'r').read().splitlines()
737 # Make sure auto-props is enabled and check for 2 Chromium standard
738 # auto-prop.
739 if (not '*.cc = svn:eol-style=LF' in lines or
740 not '*.pdf = svn:mime-type=application/pdf' in lines or
741 not 'enable-auto-props = yes' in lines):
742 return [
[email protected]79ed7e62011-02-21 21:08:53743 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05744 'It looks like you have not configured your subversion config '
[email protected]b5359c02011-02-01 20:29:56745 'file or it is not up-to-date.\n' + error_msg)
[email protected]b337cb5b2011-01-23 21:24:05746 ]
747 except (OSError, IOError):
748 return [
[email protected]79ed7e62011-02-21 21:08:53749 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05750 'Can\'t find your subversion config file.\n' + error_msg)
751 ]
752 return []
753
754
[email protected]66daa702011-05-28 14:41:46755def _CheckAuthorizedAuthor(input_api, output_api):
756 """For non-googler/chromites committers, verify the author's email address is
757 in AUTHORS.
758 """
[email protected]9bb9cb82011-06-13 20:43:01759 # TODO(maruel): Add it to input_api?
760 import fnmatch
761
[email protected]66daa702011-05-28 14:41:46762 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:01763 if not author:
764 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:46765 return []
[email protected]c99663292011-05-31 19:46:08766 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:46767 input_api.PresubmitLocalPath(), 'AUTHORS')
768 valid_authors = (
769 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
770 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:18771 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]9bb9cb82011-06-13 20:43:01772 if input_api.verbose:
773 print 'Valid authors are %s' % ', '.join(valid_authors)
[email protected]d8b50be2011-06-15 14:19:44774 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]66daa702011-05-28 14:41:46775 return [output_api.PresubmitPromptWarning(
776 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
777 '\n'
778 'http://www.chromium.org/developers/contributing-code and read the '
779 '"Legal" section\n'
780 'If you are a chromite, verify the contributor signed the CLA.') %
781 author)]
782 return []
783
784
[email protected]1f7b4172010-01-28 01:17:34785def CheckChangeOnUpload(input_api, output_api):
786 results = []
787 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54788 return results
[email protected]ca8d19842009-02-19 16:33:12789
790
791def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:54792 results = []
[email protected]1f7b4172010-01-28 01:17:34793 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:51794 # TODO(thestig) temporarily disabled, doesn't work in third_party/
795 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
796 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:54797 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:27798 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:34799 input_api,
800 output_api,
[email protected]4efa42142010-08-26 01:29:26801 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:27802 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
[email protected]4ddc5df2011-12-12 03:05:04803 output_api, 'http://codereview.chromium.org',
[email protected]c1ba4c52012-03-09 14:23:28804 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
805 '[email protected]'))
[email protected]806e98e2010-03-19 17:49:27806
[email protected]3e4eb112011-01-18 03:29:54807 results.extend(input_api.canned_checks.CheckChangeHasBugField(
808 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:41809 results.extend(input_api.canned_checks.CheckChangeHasDescription(
810 input_api, output_api))
[email protected]b337cb5b2011-01-23 21:24:05811 results.extend(_CheckSubversionConfig(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54812 return results
[email protected]ca8d19842009-02-19 16:33:12813
814
[email protected]5efb2a822011-09-27 23:06:13815def GetPreferredTrySlaves(project, change):
[email protected]4ce995ea2012-06-27 02:13:10816 files = change.LocalPaths()
817
[email protected]3019c902012-06-29 00:09:03818 if not files:
819 return []
820
[email protected]d668899a2012-09-06 18:16:59821 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
[email protected]641f2e3e2012-09-03 11:16:24822 return ['mac_rel', 'mac_asan']
[email protected]d668899a2012-09-06 18:16:59823 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
[email protected]4ce995ea2012-06-27 02:13:10824 return ['win_rel']
[email protected]d668899a2012-09-06 18:16:59825 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
[email protected]3e2f0402012-11-02 16:28:01826 return ['android_dbg', 'android_clang_dbg']
[email protected]356aa542012-09-19 23:31:29827 if all(re.search('^native_client_sdk', f) for f in files):
828 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
[email protected]de142152012-10-03 23:02:45829 if all(re.search('[/_]ios[/_.]', f) for f in files):
830 return ['ios_rel_device', 'ios_dbg_simulator']
[email protected]4ce995ea2012-06-27 02:13:10831
[email protected]3e2f0402012-11-02 16:28:01832 trybots = [
833 'android_clang_dbg',
834 'android_dbg',
835 'ios_dbg_simulator',
836 'ios_rel_device',
837 'linux_asan',
[email protected]95c989162012-11-29 05:58:25838 'linux_aura',
[email protected]3e2f0402012-11-02 16:28:01839 'linux_chromeos',
840 'linux_clang:compile',
841 'linux_rel',
842 'mac_asan',
843 'mac_rel',
[email protected]95c989162012-11-29 05:58:25844 'win_aura',
[email protected]3e2f0402012-11-02 16:28:01845 'win_rel',
846 ]
[email protected]911753b2012-08-02 12:11:54847
848 # Match things like path/aura/file.cc and path/file_aura.cc.
[email protected]95c989162012-11-29 05:58:25849 # Same for chromeos.
850 if any(re.search('[/_](aura|chromeos)', f) for f in files):
[email protected]3e2f0402012-11-02 16:28:01851 trybots += ['linux_chromeos_clang:compile', 'linux_chromeos_asan']
[email protected]4ce995ea2012-06-27 02:13:10852
[email protected]4ce995ea2012-06-27 02:13:10853 return trybots