Fixes to prep_libc.py to support correct stripping of x64 libcmt on x64 target
[chromium-blink-merge.git] / PRESUBMIT.py
blob751cfb14ebf5850e5a83f639de625f0d5744d82a
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Top-level presubmit script for Chromium.
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8 for more details about the presubmit API built into gcl.
9 """
12 import re
13 import subprocess
14 import sys
17 _EXCLUDED_PATHS = (
18 r"^breakpad[\\\/].*",
19 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
20 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
21 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
22 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
23 r"^skia[\\\/].*",
24 r"^v8[\\\/].*",
25 r".*MakeFile$",
26 r".+_autogen\.h$",
27 r"^cc[\\\/].*",
28 r"^webkit[\\\/]compositor_bindings[\\\/].*",
29 r".+[\\\/]pnacl_shim\.c$",
32 # Fragment of a regular expression that matches file name suffixes
33 # used to indicate different platforms.
34 _PLATFORM_SPECIFIERS = r'(_(android|chromeos|gtk|mac|posix|win))?'
36 # Fragment of a regular expression that matches C++ and Objective-C++
37 # implementation files.
38 _IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
40 # Regular expression that matches code only used for test binaries
41 # (best effort).
42 _TEST_CODE_EXCLUDED_PATHS = (
43 r'.*[/\\](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
44 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
45 r'.+_(api|browser|perf|unit|ui)?test%s%s' % (_PLATFORM_SPECIFIERS,
46 _IMPLEMENTATION_EXTENSIONS),
47 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
48 r'.*[/\\](test|tool(s)?)[/\\].*',
49 # At request of folks maintaining this folder.
50 r'chrome[/\\]browser[/\\]automation[/\\].*',
53 _TEST_ONLY_WARNING = (
54 'You might be calling functions intended only for testing from\n'
55 'production code. It is OK to ignore this warning if you know what\n'
56 'you are doing, as the heuristics used to detect the situation are\n'
57 'not perfect. The commit queue will not block on this warning.\n'
58 'Email joi@chromium.org if you have questions.')
61 _INCLUDE_ORDER_WARNING = (
62 'Your #include order seems to be broken. Send mail to\n'
63 'marja@chromium.org if this is not the case.')
66 _BANNED_OBJC_FUNCTIONS = (
68 'addTrackingRect:',
70 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
71 'prohibited. Please use CrTrackingArea instead.',
72 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
74 False,
77 'NSTrackingArea',
79 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
80 'instead.',
81 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
83 False,
86 'convertPointFromBase:',
88 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
89 'Please use |convertPoint:(point) fromView:nil| instead.',
90 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
92 True,
95 'convertPointToBase:',
97 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
98 'Please use |convertPoint:(point) toView:nil| instead.',
99 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 True,
104 'convertRectFromBase:',
106 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
107 'Please use |convertRect:(point) fromView:nil| instead.',
108 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 True,
113 'convertRectToBase:',
115 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
116 'Please use |convertRect:(point) toView:nil| instead.',
117 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 True,
122 'convertSizeFromBase:',
124 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
125 'Please use |convertSize:(point) fromView:nil| instead.',
126 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 True,
131 'convertSizeToBase:',
133 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
134 'Please use |convertSize:(point) toView:nil| instead.',
135 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 True,
142 _BANNED_CPP_FUNCTIONS = (
143 # Make sure that gtest's FRIEND_TEST() macro is not used; the
144 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
145 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
147 'FRIEND_TEST(',
149 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
150 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
152 False,
156 'ScopedAllowIO',
158 'New code should not use ScopedAllowIO. Post a task to the blocking',
159 'pool or the FILE thread instead.',
161 True,
163 r"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
169 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
170 """Attempts to prevent use of functions intended only for testing in
171 non-testing code. For now this is just a best-effort implementation
172 that ignores header files and may have some false positives. A
173 better implementation would probably need a proper C++ parser.
175 # We only scan .cc files and the like, as the declaration of
176 # for-testing functions in header files are hard to distinguish from
177 # calls to such functions without a proper C++ parser.
178 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
180 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
181 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
182 exclusion_pattern = input_api.re.compile(
183 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
184 base_function_pattern, base_function_pattern))
186 def FilterFile(affected_file):
187 black_list = (_EXCLUDED_PATHS +
188 _TEST_CODE_EXCLUDED_PATHS +
189 input_api.DEFAULT_BLACK_LIST)
190 return input_api.FilterSourceFile(
191 affected_file,
192 white_list=(file_inclusion_pattern, ),
193 black_list=black_list)
195 problems = []
196 for f in input_api.AffectedSourceFiles(FilterFile):
197 local_path = f.LocalPath()
198 lines = input_api.ReadFile(f).splitlines()
199 line_number = 0
200 for line in lines:
201 if (inclusion_pattern.search(line) and
202 not exclusion_pattern.search(line)):
203 problems.append(
204 '%s:%d\n %s' % (local_path, line_number, line.strip()))
205 line_number += 1
207 if problems:
208 if not input_api.is_committing:
209 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
210 else:
211 # We don't warn on commit, to avoid stopping commits going through CQ.
212 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
213 else:
214 return []
217 def _CheckNoIOStreamInHeaders(input_api, output_api):
218 """Checks to make sure no .h files include <iostream>."""
219 files = []
220 pattern = input_api.re.compile(r'^#include\s*<iostream>',
221 input_api.re.MULTILINE)
222 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
223 if not f.LocalPath().endswith('.h'):
224 continue
225 contents = input_api.ReadFile(f)
226 if pattern.search(contents):
227 files.append(f)
229 if len(files):
230 return [ output_api.PresubmitError(
231 'Do not #include <iostream> in header files, since it inserts static '
232 'initialization into every file including the header. Instead, '
233 '#include <ostream>. See http://crbug.com/94794',
234 files) ]
235 return []
238 def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
239 """Checks to make sure no source files use UNIT_TEST"""
240 problems = []
241 for f in input_api.AffectedFiles():
242 if (not f.LocalPath().endswith(('.cc', '.mm'))):
243 continue
245 for line_num, line in f.ChangedContents():
246 if 'UNIT_TEST' in line:
247 problems.append(' %s:%d' % (f.LocalPath(), line_num))
249 if not problems:
250 return []
251 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
252 '\n'.join(problems))]
255 def _CheckNoNewWStrings(input_api, output_api):
256 """Checks to make sure we don't introduce use of wstrings."""
257 problems = []
258 for f in input_api.AffectedFiles():
259 if (not f.LocalPath().endswith(('.cc', '.h')) or
260 f.LocalPath().endswith('test.cc')):
261 continue
263 allowWString = False
264 for line_num, line in f.ChangedContents():
265 if 'presubmit: allow wstring' in line:
266 allowWString = True
267 elif not allowWString and 'wstring' in line:
268 problems.append(' %s:%d' % (f.LocalPath(), line_num))
269 allowWString = False
270 else:
271 allowWString = False
273 if not problems:
274 return []
275 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
276 ' If you are calling a cross-platform API that accepts a wstring, '
277 'fix the API.\n' +
278 '\n'.join(problems))]
281 def _CheckNoDEPSGIT(input_api, output_api):
282 """Make sure .DEPS.git is never modified manually."""
283 if any(f.LocalPath().endswith('.DEPS.git') for f in
284 input_api.AffectedFiles()):
285 return [output_api.PresubmitError(
286 'Never commit changes to .DEPS.git. This file is maintained by an\n'
287 'automated system based on what\'s in DEPS and your changes will be\n'
288 'overwritten.\n'
289 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
290 'for more information')]
291 return []
294 def _CheckNoBannedFunctions(input_api, output_api):
295 """Make sure that banned functions are not used."""
296 warnings = []
297 errors = []
299 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
300 for f in input_api.AffectedFiles(file_filter=file_filter):
301 for line_num, line in f.ChangedContents():
302 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
303 if func_name in line:
304 problems = warnings;
305 if error:
306 problems = errors;
307 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
308 for message_line in message:
309 problems.append(' %s' % message_line)
311 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
312 for f in input_api.AffectedFiles(file_filter=file_filter):
313 for line_num, line in f.ChangedContents():
314 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
315 def IsBlacklisted(affected_file, blacklist):
316 local_path = affected_file.LocalPath()
317 for item in blacklist:
318 if input_api.re.match(item, local_path):
319 return True
320 return False
321 if IsBlacklisted(f, excluded_paths):
322 continue
323 if func_name in line:
324 problems = warnings;
325 if error:
326 problems = errors;
327 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
328 for message_line in message:
329 problems.append(' %s' % message_line)
331 result = []
332 if (warnings):
333 result.append(output_api.PresubmitPromptWarning(
334 'Banned functions were used.\n' + '\n'.join(warnings)))
335 if (errors):
336 result.append(output_api.PresubmitError(
337 'Banned functions were used.\n' + '\n'.join(errors)))
338 return result
341 def _CheckNoPragmaOnce(input_api, output_api):
342 """Make sure that banned functions are not used."""
343 files = []
344 pattern = input_api.re.compile(r'^#pragma\s+once',
345 input_api.re.MULTILINE)
346 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
347 if not f.LocalPath().endswith('.h'):
348 continue
349 contents = input_api.ReadFile(f)
350 if pattern.search(contents):
351 files.append(f)
353 if files:
354 return [output_api.PresubmitError(
355 'Do not use #pragma once in header files.\n'
356 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
357 files)]
358 return []
361 def _CheckNoTrinaryTrueFalse(input_api, output_api):
362 """Checks to make sure we don't introduce use of foo ? true : false."""
363 problems = []
364 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
365 for f in input_api.AffectedFiles():
366 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
367 continue
369 for line_num, line in f.ChangedContents():
370 if pattern.match(line):
371 problems.append(' %s:%d' % (f.LocalPath(), line_num))
373 if not problems:
374 return []
375 return [output_api.PresubmitPromptWarning(
376 'Please consider avoiding the "? true : false" pattern if possible.\n' +
377 '\n'.join(problems))]
380 def _CheckUnwantedDependencies(input_api, output_api):
381 """Runs checkdeps on #include statements added in this
382 change. Breaking - rules is an error, breaking ! rules is a
383 warning.
385 # We need to wait until we have an input_api object and use this
386 # roundabout construct to import checkdeps because this file is
387 # eval-ed and thus doesn't have __file__.
388 original_sys_path = sys.path
389 try:
390 sys.path = sys.path + [input_api.os_path.join(
391 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
392 import checkdeps
393 from cpp_checker import CppChecker
394 from rules import Rule
395 finally:
396 # Restore sys.path to what it was before.
397 sys.path = original_sys_path
399 added_includes = []
400 for f in input_api.AffectedFiles():
401 if not CppChecker.IsCppFile(f.LocalPath()):
402 continue
404 changed_lines = [line for line_num, line in f.ChangedContents()]
405 added_includes.append([f.LocalPath(), changed_lines])
407 deps_checker = checkdeps.DepsChecker()
409 error_descriptions = []
410 warning_descriptions = []
411 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
412 added_includes):
413 description_with_path = '%s\n %s' % (path, rule_description)
414 if rule_type == Rule.DISALLOW:
415 error_descriptions.append(description_with_path)
416 else:
417 warning_descriptions.append(description_with_path)
419 results = []
420 if error_descriptions:
421 results.append(output_api.PresubmitError(
422 'You added one or more #includes that violate checkdeps rules.',
423 error_descriptions))
424 if warning_descriptions:
425 if not input_api.is_committing:
426 warning_factory = output_api.PresubmitPromptWarning
427 else:
428 # We don't want to block use of the CQ when there is a warning
429 # of this kind, so we only show a message when committing.
430 warning_factory = output_api.PresubmitNotifyResult
431 results.append(warning_factory(
432 'You added one or more #includes of files that are temporarily\n'
433 'allowed but being removed. Can you avoid introducing the\n'
434 '#include? See relevant DEPS file(s) for details and contacts.',
435 warning_descriptions))
436 return results
439 def _CheckFilePermissions(input_api, output_api):
440 """Check that all files have their permissions properly set."""
441 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
442 input_api.change.RepositoryRoot()]
443 for f in input_api.AffectedFiles():
444 args += ['--file', f.LocalPath()]
445 errors = []
446 (errors, stderrdata) = subprocess.Popen(args).communicate()
448 results = []
449 if errors:
450 results.append(output_api.PresubmitError('checkperms.py failed.',
451 errors))
452 return results
455 def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
456 """Makes sure we don't include ui/aura/window_property.h
457 in header files.
459 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
460 errors = []
461 for f in input_api.AffectedFiles():
462 if not f.LocalPath().endswith('.h'):
463 continue
464 for line_num, line in f.ChangedContents():
465 if pattern.match(line):
466 errors.append(' %s:%d' % (f.LocalPath(), line_num))
468 results = []
469 if errors:
470 results.append(output_api.PresubmitError(
471 'Header files should not include ui/aura/window_property.h', errors))
472 return results
475 def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
476 """Checks that the lines in scope occur in the right order.
478 1. C system files in alphabetical order
479 2. C++ system files in alphabetical order
480 3. Project's .h files
483 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
484 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
485 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
487 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
489 state = C_SYSTEM_INCLUDES
491 previous_line = ''
492 previous_line_num = 0
493 problem_linenums = []
494 for line_num, line in scope:
495 if c_system_include_pattern.match(line):
496 if state != C_SYSTEM_INCLUDES:
497 problem_linenums.append((line_num, previous_line_num))
498 elif previous_line and previous_line > line:
499 problem_linenums.append((line_num, previous_line_num))
500 elif cpp_system_include_pattern.match(line):
501 if state == C_SYSTEM_INCLUDES:
502 state = CPP_SYSTEM_INCLUDES
503 elif state == CUSTOM_INCLUDES:
504 problem_linenums.append((line_num, previous_line_num))
505 elif previous_line and previous_line > line:
506 problem_linenums.append((line_num, previous_line_num))
507 elif custom_include_pattern.match(line):
508 if state != CUSTOM_INCLUDES:
509 state = CUSTOM_INCLUDES
510 elif previous_line and previous_line > line:
511 problem_linenums.append((line_num, previous_line_num))
512 else:
513 problem_linenums.append(line_num)
514 previous_line = line
515 previous_line_num = line_num
517 warnings = []
518 for (line_num, previous_line_num) in problem_linenums:
519 if line_num in changed_linenums or previous_line_num in changed_linenums:
520 warnings.append(' %s:%d' % (file_path, line_num))
521 return warnings
524 def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
525 """Checks the #include order for the given file f."""
527 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
528 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
529 # often need to appear in a specific order.
530 excluded_include_pattern = input_api.re.compile(r'\s*#include \<.*/.*')
531 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
532 if_pattern = input_api.re.compile(
533 r'\s*#\s*(if|elif|else|endif|define|undef).*')
534 # Some files need specialized order of includes; exclude such files from this
535 # check.
536 uncheckable_includes_pattern = input_api.re.compile(
537 r'\s*#include '
538 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
540 contents = f.NewContents()
541 warnings = []
542 line_num = 0
544 # Handle the special first include. If the first include file is
545 # some/path/file.h, the corresponding including file can be some/path/file.cc,
546 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
547 # etc. It's also possible that no special first include exists.
548 for line in contents:
549 line_num += 1
550 if system_include_pattern.match(line):
551 # No special first include -> process the line again along with normal
552 # includes.
553 line_num -= 1
554 break
555 match = custom_include_pattern.match(line)
556 if match:
557 match_dict = match.groupdict()
558 header_basename = input_api.os_path.basename(
559 match_dict['FILE']).replace('.h', '')
560 if header_basename not in input_api.os_path.basename(f.LocalPath()):
561 # No special first include -> process the line again along with normal
562 # includes.
563 line_num -= 1
564 break
566 # Split into scopes: Each region between #if and #endif is its own scope.
567 scopes = []
568 current_scope = []
569 for line in contents[line_num:]:
570 line_num += 1
571 if uncheckable_includes_pattern.match(line):
572 return []
573 if if_pattern.match(line):
574 scopes.append(current_scope)
575 current_scope = []
576 elif ((system_include_pattern.match(line) or
577 custom_include_pattern.match(line)) and
578 not excluded_include_pattern.match(line)):
579 current_scope.append((line_num, line))
580 scopes.append(current_scope)
582 for scope in scopes:
583 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
584 changed_linenums))
585 return warnings
588 def _CheckIncludeOrder(input_api, output_api):
589 """Checks that the #include order is correct.
591 1. The corresponding header for source files.
592 2. C system files in alphabetical order
593 3. C++ system files in alphabetical order
594 4. Project's .h files in alphabetical order
596 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
597 these rules separately.
600 warnings = []
601 for f in input_api.AffectedFiles():
602 if f.LocalPath().endswith(('.cc', '.h')):
603 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
604 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
606 results = []
607 if warnings:
608 if not input_api.is_committing:
609 results.append(output_api.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING,
610 warnings))
611 else:
612 # We don't warn on commit, to avoid stopping commits going through CQ.
613 results.append(output_api.PresubmitNotifyResult(_INCLUDE_ORDER_WARNING,
614 warnings))
615 return results
618 def _CheckForVersionControlConflictsInFile(input_api, f):
619 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
620 errors = []
621 for line_num, line in f.ChangedContents():
622 if pattern.match(line):
623 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
624 return errors
627 def _CheckForVersionControlConflicts(input_api, output_api):
628 """Usually this is not intentional and will cause a compile failure."""
629 errors = []
630 for f in input_api.AffectedFiles():
631 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
633 results = []
634 if errors:
635 results.append(output_api.PresubmitError(
636 'Version control conflict markers found, please resolve.', errors))
637 return results
640 def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
641 def FilterFile(affected_file):
642 """Filter function for use with input_api.AffectedSourceFiles,
643 below. This filters out everything except non-test files from
644 top-level directories that generally speaking should not hard-code
645 service URLs (e.g. src/android_webview/, src/content/ and others).
647 return input_api.FilterSourceFile(
648 affected_file,
649 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
650 black_list=(_EXCLUDED_PATHS +
651 _TEST_CODE_EXCLUDED_PATHS +
652 input_api.DEFAULT_BLACK_LIST))
654 pattern = input_api.re.compile('"[^"]*google\.com[^"]*"')
655 problems = [] # items are (filename, line_number, line)
656 for f in input_api.AffectedSourceFiles(FilterFile):
657 for line_num, line in f.ChangedContents():
658 if pattern.search(line):
659 problems.append((f.LocalPath(), line_num, line))
661 if problems:
662 if not input_api.is_committing:
663 warning_factory = output_api.PresubmitPromptWarning
664 else:
665 # We don't want to block use of the CQ when there is a warning
666 # of this kind, so we only show a message when committing.
667 warning_factory = output_api.PresubmitNotifyResult
668 return [warning_factory(
669 'Most layers below src/chrome/ should not hardcode service URLs.\n'
670 'Are you sure this is correct? (Contact: joi@chromium.org)',
671 [' %s:%d: %s' % (
672 problem[0], problem[1], problem[2]) for problem in problems])]
673 else:
674 return []
677 def _CheckNoAbbreviationInPngFileName(input_api, output_api):
678 """Makes sure there are no abbreviations in the name of PNG files.
680 pattern = input_api.re.compile(r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$')
681 errors = []
682 for f in input_api.AffectedFiles(include_deletes=False):
683 if pattern.match(f.LocalPath()):
684 errors.append(' %s' % f.LocalPath())
686 results = []
687 if errors:
688 results.append(output_api.PresubmitError(
689 'The name of PNG files should not have abbreviations. \n'
690 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
691 'Contact oshima@chromium.org if you have questions.', errors))
692 return results
695 def _CommonChecks(input_api, output_api):
696 """Checks common to both upload and commit."""
697 results = []
698 results.extend(input_api.canned_checks.PanProjectChecks(
699 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
700 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
701 results.extend(
702 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
703 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
704 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
705 results.extend(_CheckNoNewWStrings(input_api, output_api))
706 results.extend(_CheckNoDEPSGIT(input_api, output_api))
707 results.extend(_CheckNoBannedFunctions(input_api, output_api))
708 results.extend(_CheckNoPragmaOnce(input_api, output_api))
709 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
710 results.extend(_CheckUnwantedDependencies(input_api, output_api))
711 results.extend(_CheckFilePermissions(input_api, output_api))
712 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
713 results.extend(_CheckIncludeOrder(input_api, output_api))
714 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
715 results.extend(_CheckPatchFiles(input_api, output_api))
716 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
717 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
719 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
720 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
721 input_api, output_api,
722 input_api.PresubmitLocalPath(),
723 whitelist=[r'^PRESUBMIT_test\.py$']))
724 return results
727 def _CheckSubversionConfig(input_api, output_api):
728 """Verifies the subversion config file is correctly setup.
730 Checks that autoprops are enabled, returns an error otherwise.
732 join = input_api.os_path.join
733 if input_api.platform == 'win32':
734 appdata = input_api.environ.get('APPDATA', '')
735 if not appdata:
736 return [output_api.PresubmitError('%APPDATA% is not configured.')]
737 path = join(appdata, 'Subversion', 'config')
738 else:
739 home = input_api.environ.get('HOME', '')
740 if not home:
741 return [output_api.PresubmitError('$HOME is not configured.')]
742 path = join(home, '.subversion', 'config')
744 error_msg = (
745 'Please look at http://dev.chromium.org/developers/coding-style to\n'
746 'configure your subversion configuration file. This enables automatic\n'
747 'properties to simplify the project maintenance.\n'
748 'Pro-tip: just download and install\n'
749 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
751 try:
752 lines = open(path, 'r').read().splitlines()
753 # Make sure auto-props is enabled and check for 2 Chromium standard
754 # auto-prop.
755 if (not '*.cc = svn:eol-style=LF' in lines or
756 not '*.pdf = svn:mime-type=application/pdf' in lines or
757 not 'enable-auto-props = yes' in lines):
758 return [
759 output_api.PresubmitNotifyResult(
760 'It looks like you have not configured your subversion config '
761 'file or it is not up-to-date.\n' + error_msg)
763 except (OSError, IOError):
764 return [
765 output_api.PresubmitNotifyResult(
766 'Can\'t find your subversion config file.\n' + error_msg)
768 return []
771 def _CheckAuthorizedAuthor(input_api, output_api):
772 """For non-googler/chromites committers, verify the author's email address is
773 in AUTHORS.
775 # TODO(maruel): Add it to input_api?
776 import fnmatch
778 author = input_api.change.author_email
779 if not author:
780 input_api.logging.info('No author, skipping AUTHOR check')
781 return []
782 authors_path = input_api.os_path.join(
783 input_api.PresubmitLocalPath(), 'AUTHORS')
784 valid_authors = (
785 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
786 for line in open(authors_path))
787 valid_authors = [item.group(1).lower() for item in valid_authors if item]
788 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
789 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
790 return [output_api.PresubmitPromptWarning(
791 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
792 '\n'
793 'http://www.chromium.org/developers/contributing-code and read the '
794 '"Legal" section\n'
795 'If you are a chromite, verify the contributor signed the CLA.') %
796 author)]
797 return []
800 def _CheckPatchFiles(input_api, output_api):
801 problems = [f.LocalPath() for f in input_api.AffectedFiles()
802 if f.LocalPath().endswith(('.orig', '.rej'))]
803 if problems:
804 return [output_api.PresubmitError(
805 "Don't commit .rej and .orig files.", problems)]
806 else:
807 return []
810 def CheckChangeOnUpload(input_api, output_api):
811 results = []
812 results.extend(_CommonChecks(input_api, output_api))
813 return results
816 def CheckChangeOnCommit(input_api, output_api):
817 results = []
818 results.extend(_CommonChecks(input_api, output_api))
819 # TODO(thestig) temporarily disabled, doesn't work in third_party/
820 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
821 # input_api, output_api, sources))
822 # Make sure the tree is 'open'.
823 results.extend(input_api.canned_checks.CheckTreeIsOpen(
824 input_api,
825 output_api,
826 json_url='http://chromium-status.appspot.com/current?format=json'))
827 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
828 output_api, 'http://codereview.chromium.org',
829 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
830 'tryserver@chromium.org'))
832 results.extend(input_api.canned_checks.CheckChangeHasBugField(
833 input_api, output_api))
834 results.extend(input_api.canned_checks.CheckChangeHasDescription(
835 input_api, output_api))
836 results.extend(_CheckSubversionConfig(input_api, output_api))
837 return results
840 def GetPreferredTrySlaves(project, change):
841 files = change.LocalPaths()
843 if not files or all(re.search(r'[\\/]OWNERS$', f) for f in files):
844 return []
846 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
847 return ['mac_rel', 'mac_asan']
848 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
849 return ['win_rel']
850 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
851 return ['android_dbg', 'android_clang_dbg']
852 if all(re.search('^native_client_sdk', f) for f in files):
853 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
854 if all(re.search('[/_]ios[/_.]', f) for f in files):
855 return ['ios_rel_device', 'ios_dbg_simulator']
857 trybots = [
858 'android_clang_dbg',
859 'android_dbg',
860 'ios_dbg_simulator',
861 'ios_rel_device',
862 'linux_asan',
863 'linux_aura',
864 'linux_chromeos',
865 'linux_clang:compile',
866 'linux_rel',
867 'mac_asan',
868 'mac_rel',
869 'win7_aura',
870 'win_rel',
873 # Match things like path/aura/file.cc and path/file_aura.cc.
874 # Same for chromeos.
875 if any(re.search('[/_](aura|chromeos)', f) for f in files):
876 trybots += ['linux_chromeos_clang:compile', 'linux_chromeos_asan']
878 return trybots