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.
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[\\\/].*",
28 r
".+[\\\/]pnacl_shim\.c$",
31 # Fragment of a regular expression that matches file name suffixes
32 # used to indicate different platforms.
33 _PLATFORM_SPECIFIERS
= r
'(_(android|chromeos|gtk|mac|posix|win))?'
35 # Fragment of a regular expression that matches C++ and Objective-C++
36 # implementation files.
37 _IMPLEMENTATION_EXTENSIONS
= r
'\.(cc|cpp|cxx|mm)$'
39 # Regular expression that matches code only used for test binaries
41 _TEST_CODE_EXCLUDED_PATHS
= (
42 r
'.*[/\\](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS
,
43 r
'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS
,
44 r
'.+_(api|browser|perf|unit|ui)?test%s%s' % (_PLATFORM_SPECIFIERS
,
45 _IMPLEMENTATION_EXTENSIONS
),
46 r
'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS
,
47 r
'.*[/\\](test|tool(s)?)[/\\].*',
48 # At request of folks maintaining this folder.
49 r
'chrome[/\\]browser[/\\]automation[/\\].*',
52 _TEST_ONLY_WARNING
= (
53 'You might be calling functions intended only for testing from\n'
54 'production code. It is OK to ignore this warning if you know what\n'
55 'you are doing, as the heuristics used to detect the situation are\n'
56 'not perfect. The commit queue will not block on this warning.\n'
57 'Email joi@chromium.org if you have questions.')
60 _INCLUDE_ORDER_WARNING
= (
61 'Your #include order seems to be broken. Send mail to\n'
62 'marja@chromium.org if this is not the case.')
65 _BANNED_OBJC_FUNCTIONS
= (
69 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
70 'prohibited. Please use CrTrackingArea instead.',
71 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
78 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
80 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
85 'convertPointFromBase:',
87 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
88 'Please use |convertPoint:(point) fromView:nil| instead.',
89 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
94 'convertPointToBase:',
96 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
97 'Please use |convertPoint:(point) toView:nil| instead.',
98 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
103 'convertRectFromBase:',
105 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
106 'Please use |convertRect:(point) fromView:nil| instead.',
107 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
112 'convertRectToBase:',
114 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
115 'Please use |convertRect:(point) toView:nil| instead.',
116 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
121 'convertSizeFromBase:',
123 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
124 'Please use |convertSize:(point) fromView:nil| instead.',
125 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
130 'convertSizeToBase:',
132 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
133 'Please use |convertSize:(point) toView:nil| instead.',
134 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 _BANNED_CPP_FUNCTIONS
= (
142 # Make sure that gtest's FRIEND_TEST() macro is not used; the
143 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
144 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
148 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
149 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
157 'New code should not use ScopedAllowIO. Post a task to the blocking',
158 'pool or the FILE thread instead.',
162 r
"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
169 # Please keep sorted.
172 'OS_CAT', # For testing.
182 'OS_SUN', # Not in build/build_config.h but in skia.
187 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api
, output_api
):
188 """Attempts to prevent use of functions intended only for testing in
189 non-testing code. For now this is just a best-effort implementation
190 that ignores header files and may have some false positives. A
191 better implementation would probably need a proper C++ parser.
193 # We only scan .cc files and the like, as the declaration of
194 # for-testing functions in header files are hard to distinguish from
195 # calls to such functions without a proper C++ parser.
196 file_inclusion_pattern
= r
'.+%s' % _IMPLEMENTATION_EXTENSIONS
198 base_function_pattern
= r
'ForTest(ing)?|for_test(ing)?'
199 inclusion_pattern
= input_api
.re
.compile(r
'(%s)\s*\(' % base_function_pattern
)
200 exclusion_pattern
= input_api
.re
.compile(
201 r
'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
202 base_function_pattern
, base_function_pattern
))
204 def FilterFile(affected_file
):
205 black_list
= (_EXCLUDED_PATHS
+
206 _TEST_CODE_EXCLUDED_PATHS
+
207 input_api
.DEFAULT_BLACK_LIST
)
208 return input_api
.FilterSourceFile(
210 white_list
=(file_inclusion_pattern
, ),
211 black_list
=black_list
)
214 for f
in input_api
.AffectedSourceFiles(FilterFile
):
215 local_path
= f
.LocalPath()
216 lines
= input_api
.ReadFile(f
).splitlines()
219 if (inclusion_pattern
.search(line
) and
220 not exclusion_pattern
.search(line
)):
222 '%s:%d\n %s' % (local_path
, line_number
, line
.strip()))
226 if not input_api
.is_committing
:
227 return [output_api
.PresubmitPromptWarning(_TEST_ONLY_WARNING
, problems
)]
229 # We don't warn on commit, to avoid stopping commits going through CQ.
230 return [output_api
.PresubmitNotifyResult(_TEST_ONLY_WARNING
, problems
)]
235 def _CheckNoIOStreamInHeaders(input_api
, output_api
):
236 """Checks to make sure no .h files include <iostream>."""
238 pattern
= input_api
.re
.compile(r
'^#include\s*<iostream>',
239 input_api
.re
.MULTILINE
)
240 for f
in input_api
.AffectedSourceFiles(input_api
.FilterSourceFile
):
241 if not f
.LocalPath().endswith('.h'):
243 contents
= input_api
.ReadFile(f
)
244 if pattern
.search(contents
):
248 return [ output_api
.PresubmitError(
249 'Do not #include <iostream> in header files, since it inserts static '
250 'initialization into every file including the header. Instead, '
251 '#include <ostream>. See http://crbug.com/94794',
256 def _CheckNoUNIT_TESTInSourceFiles(input_api
, output_api
):
257 """Checks to make sure no source files use UNIT_TEST"""
259 for f
in input_api
.AffectedFiles():
260 if (not f
.LocalPath().endswith(('.cc', '.mm'))):
263 for line_num
, line
in f
.ChangedContents():
264 if 'UNIT_TEST' in line
:
265 problems
.append(' %s:%d' % (f
.LocalPath(), line_num
))
269 return [output_api
.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
270 '\n'.join(problems
))]
273 def _CheckNoNewWStrings(input_api
, output_api
):
274 """Checks to make sure we don't introduce use of wstrings."""
276 for f
in input_api
.AffectedFiles():
277 if (not f
.LocalPath().endswith(('.cc', '.h')) or
278 f
.LocalPath().endswith('test.cc')):
282 for line_num
, line
in f
.ChangedContents():
283 if 'presubmit: allow wstring' in line
:
285 elif not allowWString
and 'wstring' in line
:
286 problems
.append(' %s:%d' % (f
.LocalPath(), line_num
))
293 return [output_api
.PresubmitPromptWarning('New code should not use wstrings.'
294 ' If you are calling a cross-platform API that accepts a wstring, '
296 '\n'.join(problems
))]
299 def _CheckNoDEPSGIT(input_api
, output_api
):
300 """Make sure .DEPS.git is never modified manually."""
301 if any(f
.LocalPath().endswith('.DEPS.git') for f
in
302 input_api
.AffectedFiles()):
303 return [output_api
.PresubmitError(
304 'Never commit changes to .DEPS.git. This file is maintained by an\n'
305 'automated system based on what\'s in DEPS and your changes will be\n'
307 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
308 'for more information')]
312 def _CheckNoBannedFunctions(input_api
, output_api
):
313 """Make sure that banned functions are not used."""
317 file_filter
= lambda f
: f
.LocalPath().endswith(('.mm', '.m', '.h'))
318 for f
in input_api
.AffectedFiles(file_filter
=file_filter
):
319 for line_num
, line
in f
.ChangedContents():
320 for func_name
, message
, error
in _BANNED_OBJC_FUNCTIONS
:
321 if func_name
in line
:
325 problems
.append(' %s:%d:' % (f
.LocalPath(), line_num
))
326 for message_line
in message
:
327 problems
.append(' %s' % message_line
)
329 file_filter
= lambda f
: f
.LocalPath().endswith(('.cc', '.mm', '.h'))
330 for f
in input_api
.AffectedFiles(file_filter
=file_filter
):
331 for line_num
, line
in f
.ChangedContents():
332 for func_name
, message
, error
, excluded_paths
in _BANNED_CPP_FUNCTIONS
:
333 def IsBlacklisted(affected_file
, blacklist
):
334 local_path
= affected_file
.LocalPath()
335 for item
in blacklist
:
336 if input_api
.re
.match(item
, local_path
):
339 if IsBlacklisted(f
, excluded_paths
):
341 if func_name
in line
:
345 problems
.append(' %s:%d:' % (f
.LocalPath(), line_num
))
346 for message_line
in message
:
347 problems
.append(' %s' % message_line
)
351 result
.append(output_api
.PresubmitPromptWarning(
352 'Banned functions were used.\n' + '\n'.join(warnings
)))
354 result
.append(output_api
.PresubmitError(
355 'Banned functions were used.\n' + '\n'.join(errors
)))
359 def _CheckNoPragmaOnce(input_api
, output_api
):
360 """Make sure that banned functions are not used."""
362 pattern
= input_api
.re
.compile(r
'^#pragma\s+once',
363 input_api
.re
.MULTILINE
)
364 for f
in input_api
.AffectedSourceFiles(input_api
.FilterSourceFile
):
365 if not f
.LocalPath().endswith('.h'):
367 contents
= input_api
.ReadFile(f
)
368 if pattern
.search(contents
):
372 return [output_api
.PresubmitError(
373 'Do not use #pragma once in header files.\n'
374 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
379 def _CheckNoTrinaryTrueFalse(input_api
, output_api
):
380 """Checks to make sure we don't introduce use of foo ? true : false."""
382 pattern
= input_api
.re
.compile(r
'\?\s*(true|false)\s*:\s*(true|false)')
383 for f
in input_api
.AffectedFiles():
384 if not f
.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
387 for line_num
, line
in f
.ChangedContents():
388 if pattern
.match(line
):
389 problems
.append(' %s:%d' % (f
.LocalPath(), line_num
))
393 return [output_api
.PresubmitPromptWarning(
394 'Please consider avoiding the "? true : false" pattern if possible.\n' +
395 '\n'.join(problems
))]
398 def _CheckUnwantedDependencies(input_api
, output_api
):
399 """Runs checkdeps on #include statements added in this
400 change. Breaking - rules is an error, breaking ! rules is a
403 # We need to wait until we have an input_api object and use this
404 # roundabout construct to import checkdeps because this file is
405 # eval-ed and thus doesn't have __file__.
406 original_sys_path
= sys
.path
408 sys
.path
= sys
.path
+ [input_api
.os_path
.join(
409 input_api
.PresubmitLocalPath(), 'tools', 'checkdeps')]
411 from cpp_checker
import CppChecker
412 from rules
import Rule
414 # Restore sys.path to what it was before.
415 sys
.path
= original_sys_path
418 for f
in input_api
.AffectedFiles():
419 if not CppChecker
.IsCppFile(f
.LocalPath()):
422 changed_lines
= [line
for line_num
, line
in f
.ChangedContents()]
423 added_includes
.append([f
.LocalPath(), changed_lines
])
425 deps_checker
= checkdeps
.DepsChecker()
427 error_descriptions
= []
428 warning_descriptions
= []
429 for path
, rule_type
, rule_description
in deps_checker
.CheckAddedCppIncludes(
431 description_with_path
= '%s\n %s' % (path
, rule_description
)
432 if rule_type
== Rule
.DISALLOW
:
433 error_descriptions
.append(description_with_path
)
435 warning_descriptions
.append(description_with_path
)
438 if error_descriptions
:
439 results
.append(output_api
.PresubmitError(
440 'You added one or more #includes that violate checkdeps rules.',
442 if warning_descriptions
:
443 if not input_api
.is_committing
:
444 warning_factory
= output_api
.PresubmitPromptWarning
446 # We don't want to block use of the CQ when there is a warning
447 # of this kind, so we only show a message when committing.
448 warning_factory
= output_api
.PresubmitNotifyResult
449 results
.append(warning_factory(
450 'You added one or more #includes of files that are temporarily\n'
451 'allowed but being removed. Can you avoid introducing the\n'
452 '#include? See relevant DEPS file(s) for details and contacts.',
453 warning_descriptions
))
457 def _CheckFilePermissions(input_api
, output_api
):
458 """Check that all files have their permissions properly set."""
459 args
= [sys
.executable
, 'tools/checkperms/checkperms.py', '--root',
460 input_api
.change
.RepositoryRoot()]
461 for f
in input_api
.AffectedFiles():
462 args
+= ['--file', f
.LocalPath()]
464 (errors
, stderrdata
) = subprocess
.Popen(args
).communicate()
468 results
.append(output_api
.PresubmitError('checkperms.py failed.',
473 def _CheckNoAuraWindowPropertyHInHeaders(input_api
, output_api
):
474 """Makes sure we don't include ui/aura/window_property.h
477 pattern
= input_api
.re
.compile(r
'^#include\s*"ui/aura/window_property.h"')
479 for f
in input_api
.AffectedFiles():
480 if not f
.LocalPath().endswith('.h'):
482 for line_num
, line
in f
.ChangedContents():
483 if pattern
.match(line
):
484 errors
.append(' %s:%d' % (f
.LocalPath(), line_num
))
488 results
.append(output_api
.PresubmitError(
489 'Header files should not include ui/aura/window_property.h', errors
))
493 def _CheckIncludeOrderForScope(scope
, input_api
, file_path
, changed_linenums
):
494 """Checks that the lines in scope occur in the right order.
496 1. C system files in alphabetical order
497 2. C++ system files in alphabetical order
498 3. Project's .h files
501 c_system_include_pattern
= input_api
.re
.compile(r
'\s*#include <.*\.h>')
502 cpp_system_include_pattern
= input_api
.re
.compile(r
'\s*#include <.*>')
503 custom_include_pattern
= input_api
.re
.compile(r
'\s*#include ".*')
505 C_SYSTEM_INCLUDES
, CPP_SYSTEM_INCLUDES
, CUSTOM_INCLUDES
= range(3)
507 state
= C_SYSTEM_INCLUDES
510 previous_line_num
= 0
511 problem_linenums
= []
512 for line_num
, line
in scope
:
513 if c_system_include_pattern
.match(line
):
514 if state
!= C_SYSTEM_INCLUDES
:
515 problem_linenums
.append((line_num
, previous_line_num
))
516 elif previous_line
and previous_line
> line
:
517 problem_linenums
.append((line_num
, previous_line_num
))
518 elif cpp_system_include_pattern
.match(line
):
519 if state
== C_SYSTEM_INCLUDES
:
520 state
= CPP_SYSTEM_INCLUDES
521 elif state
== CUSTOM_INCLUDES
:
522 problem_linenums
.append((line_num
, previous_line_num
))
523 elif previous_line
and previous_line
> line
:
524 problem_linenums
.append((line_num
, previous_line_num
))
525 elif custom_include_pattern
.match(line
):
526 if state
!= CUSTOM_INCLUDES
:
527 state
= CUSTOM_INCLUDES
528 elif previous_line
and previous_line
> line
:
529 problem_linenums
.append((line_num
, previous_line_num
))
531 problem_linenums
.append(line_num
)
533 previous_line_num
= line_num
536 for (line_num
, previous_line_num
) in problem_linenums
:
537 if line_num
in changed_linenums
or previous_line_num
in changed_linenums
:
538 warnings
.append(' %s:%d' % (file_path
, line_num
))
542 def _CheckIncludeOrderInFile(input_api
, f
, changed_linenums
):
543 """Checks the #include order for the given file f."""
545 system_include_pattern
= input_api
.re
.compile(r
'\s*#include \<.*')
546 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
547 # often need to appear in a specific order.
548 excluded_include_pattern
= input_api
.re
.compile(r
'\s*#include \<.*/.*')
549 custom_include_pattern
= input_api
.re
.compile(r
'\s*#include "(?P<FILE>.*)"')
550 if_pattern
= input_api
.re
.compile(
551 r
'\s*#\s*(if|elif|else|endif|define|undef).*')
552 # Some files need specialized order of includes; exclude such files from this
554 uncheckable_includes_pattern
= input_api
.re
.compile(
556 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
558 contents
= f
.NewContents()
562 # Handle the special first include. If the first include file is
563 # some/path/file.h, the corresponding including file can be some/path/file.cc,
564 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
565 # etc. It's also possible that no special first include exists.
566 for line
in contents
:
568 if system_include_pattern
.match(line
):
569 # No special first include -> process the line again along with normal
573 match
= custom_include_pattern
.match(line
)
575 match_dict
= match
.groupdict()
576 header_basename
= input_api
.os_path
.basename(
577 match_dict
['FILE']).replace('.h', '')
578 if header_basename
not in input_api
.os_path
.basename(f
.LocalPath()):
579 # No special first include -> process the line again along with normal
584 # Split into scopes: Each region between #if and #endif is its own scope.
587 for line
in contents
[line_num
:]:
589 if uncheckable_includes_pattern
.match(line
):
591 if if_pattern
.match(line
):
592 scopes
.append(current_scope
)
594 elif ((system_include_pattern
.match(line
) or
595 custom_include_pattern
.match(line
)) and
596 not excluded_include_pattern
.match(line
)):
597 current_scope
.append((line_num
, line
))
598 scopes
.append(current_scope
)
601 warnings
.extend(_CheckIncludeOrderForScope(scope
, input_api
, f
.LocalPath(),
606 def _CheckIncludeOrder(input_api
, output_api
):
607 """Checks that the #include order is correct.
609 1. The corresponding header for source files.
610 2. C system files in alphabetical order
611 3. C++ system files in alphabetical order
612 4. Project's .h files in alphabetical order
614 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
615 these rules separately.
619 for f
in input_api
.AffectedFiles():
620 if f
.LocalPath().endswith(('.cc', '.h')):
621 changed_linenums
= set(line_num
for line_num
, _
in f
.ChangedContents())
622 warnings
.extend(_CheckIncludeOrderInFile(input_api
, f
, changed_linenums
))
626 if not input_api
.is_committing
:
627 results
.append(output_api
.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING
,
630 # We don't warn on commit, to avoid stopping commits going through CQ.
631 results
.append(output_api
.PresubmitNotifyResult(_INCLUDE_ORDER_WARNING
,
636 def _CheckForVersionControlConflictsInFile(input_api
, f
):
637 pattern
= input_api
.re
.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
639 for line_num
, line
in f
.ChangedContents():
640 if pattern
.match(line
):
641 errors
.append(' %s:%d %s' % (f
.LocalPath(), line_num
, line
))
645 def _CheckForVersionControlConflicts(input_api
, output_api
):
646 """Usually this is not intentional and will cause a compile failure."""
648 for f
in input_api
.AffectedFiles():
649 errors
.extend(_CheckForVersionControlConflictsInFile(input_api
, f
))
653 results
.append(output_api
.PresubmitError(
654 'Version control conflict markers found, please resolve.', errors
))
658 def _CheckHardcodedGoogleHostsInLowerLayers(input_api
, output_api
):
659 def FilterFile(affected_file
):
660 """Filter function for use with input_api.AffectedSourceFiles,
661 below. This filters out everything except non-test files from
662 top-level directories that generally speaking should not hard-code
663 service URLs (e.g. src/android_webview/, src/content/ and others).
665 return input_api
.FilterSourceFile(
667 white_list
=(r
'^(android_webview|base|content|net)[\\\/].*', ),
668 black_list
=(_EXCLUDED_PATHS
+
669 _TEST_CODE_EXCLUDED_PATHS
+
670 input_api
.DEFAULT_BLACK_LIST
))
672 pattern
= input_api
.re
.compile('"[^"]*google\.com[^"]*"')
673 problems
= [] # items are (filename, line_number, line)
674 for f
in input_api
.AffectedSourceFiles(FilterFile
):
675 for line_num
, line
in f
.ChangedContents():
676 if pattern
.search(line
):
677 problems
.append((f
.LocalPath(), line_num
, line
))
680 if not input_api
.is_committing
:
681 warning_factory
= output_api
.PresubmitPromptWarning
683 # We don't want to block use of the CQ when there is a warning
684 # of this kind, so we only show a message when committing.
685 warning_factory
= output_api
.PresubmitNotifyResult
686 return [warning_factory(
687 'Most layers below src/chrome/ should not hardcode service URLs.\n'
688 'Are you sure this is correct? (Contact: joi@chromium.org)',
690 problem
[0], problem
[1], problem
[2]) for problem
in problems
])]
695 def _CheckNoAbbreviationInPngFileName(input_api
, output_api
):
696 """Makes sure there are no abbreviations in the name of PNG files.
698 pattern
= input_api
.re
.compile(r
'.*_[a-z]_.*\.png$|.*_[a-z]\.png$')
700 for f
in input_api
.AffectedFiles(include_deletes
=False):
701 if pattern
.match(f
.LocalPath()):
702 errors
.append(' %s' % f
.LocalPath())
706 results
.append(output_api
.PresubmitError(
707 'The name of PNG files should not have abbreviations. \n'
708 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
709 'Contact oshima@chromium.org if you have questions.', errors
))
713 def _CommonChecks(input_api
, output_api
):
714 """Checks common to both upload and commit."""
716 results
.extend(input_api
.canned_checks
.PanProjectChecks(
717 input_api
, output_api
, excluded_paths
=_EXCLUDED_PATHS
))
718 results
.extend(_CheckAuthorizedAuthor(input_api
, output_api
))
720 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api
, output_api
))
721 results
.extend(_CheckNoIOStreamInHeaders(input_api
, output_api
))
722 results
.extend(_CheckNoUNIT_TESTInSourceFiles(input_api
, output_api
))
723 results
.extend(_CheckNoNewWStrings(input_api
, output_api
))
724 results
.extend(_CheckNoDEPSGIT(input_api
, output_api
))
725 results
.extend(_CheckNoBannedFunctions(input_api
, output_api
))
726 results
.extend(_CheckNoPragmaOnce(input_api
, output_api
))
727 results
.extend(_CheckNoTrinaryTrueFalse(input_api
, output_api
))
728 results
.extend(_CheckUnwantedDependencies(input_api
, output_api
))
729 results
.extend(_CheckFilePermissions(input_api
, output_api
))
730 results
.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api
, output_api
))
731 results
.extend(_CheckIncludeOrder(input_api
, output_api
))
732 results
.extend(_CheckForVersionControlConflicts(input_api
, output_api
))
733 results
.extend(_CheckPatchFiles(input_api
, output_api
))
734 results
.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api
, output_api
))
735 results
.extend(_CheckNoAbbreviationInPngFileName(input_api
, output_api
))
736 results
.extend(_CheckForInvalidOSMacros(input_api
, output_api
))
738 if any('PRESUBMIT.py' == f
.LocalPath() for f
in input_api
.AffectedFiles()):
739 results
.extend(input_api
.canned_checks
.RunUnitTestsInDirectory(
740 input_api
, output_api
,
741 input_api
.PresubmitLocalPath(),
742 whitelist
=[r
'^PRESUBMIT_test\.py$']))
746 def _CheckSubversionConfig(input_api
, output_api
):
747 """Verifies the subversion config file is correctly setup.
749 Checks that autoprops are enabled, returns an error otherwise.
751 join
= input_api
.os_path
.join
752 if input_api
.platform
== 'win32':
753 appdata
= input_api
.environ
.get('APPDATA', '')
755 return [output_api
.PresubmitError('%APPDATA% is not configured.')]
756 path
= join(appdata
, 'Subversion', 'config')
758 home
= input_api
.environ
.get('HOME', '')
760 return [output_api
.PresubmitError('$HOME is not configured.')]
761 path
= join(home
, '.subversion', 'config')
764 'Please look at http://dev.chromium.org/developers/coding-style to\n'
765 'configure your subversion configuration file. This enables automatic\n'
766 'properties to simplify the project maintenance.\n'
767 'Pro-tip: just download and install\n'
768 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
771 lines
= open(path
, 'r').read().splitlines()
772 # Make sure auto-props is enabled and check for 2 Chromium standard
774 if (not '*.cc = svn:eol-style=LF' in lines
or
775 not '*.pdf = svn:mime-type=application/pdf' in lines
or
776 not 'enable-auto-props = yes' in lines
):
778 output_api
.PresubmitNotifyResult(
779 'It looks like you have not configured your subversion config '
780 'file or it is not up-to-date.\n' + error_msg
)
782 except (OSError, IOError):
784 output_api
.PresubmitNotifyResult(
785 'Can\'t find your subversion config file.\n' + error_msg
)
790 def _CheckAuthorizedAuthor(input_api
, output_api
):
791 """For non-googler/chromites committers, verify the author's email address is
794 # TODO(maruel): Add it to input_api?
797 author
= input_api
.change
.author_email
799 input_api
.logging
.info('No author, skipping AUTHOR check')
801 authors_path
= input_api
.os_path
.join(
802 input_api
.PresubmitLocalPath(), 'AUTHORS')
804 input_api
.re
.match(r
'[^#]+\s+\<(.+?)\>\s*$', line
)
805 for line
in open(authors_path
))
806 valid_authors
= [item
.group(1).lower() for item
in valid_authors
if item
]
807 if not any(fnmatch
.fnmatch(author
.lower(), valid
) for valid
in valid_authors
):
808 input_api
.logging
.info('Valid authors are %s', ', '.join(valid_authors
))
809 return [output_api
.PresubmitPromptWarning(
810 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
812 'http://www.chromium.org/developers/contributing-code and read the '
814 'If you are a chromite, verify the contributor signed the CLA.') %
819 def _CheckPatchFiles(input_api
, output_api
):
820 problems
= [f
.LocalPath() for f
in input_api
.AffectedFiles()
821 if f
.LocalPath().endswith(('.orig', '.rej'))]
823 return [output_api
.PresubmitError(
824 "Don't commit .rej and .orig files.", problems
)]
829 def _DidYouMeanOSMacro(bad_macro
):
831 return {'A': 'OS_ANDROID',
841 'W': 'OS_WIN'}[bad_macro
[3].upper()]
846 def _CheckForInvalidOSMacrosInFile(input_api
, f
):
847 """Check for sensible looking, totally invalid OS macros."""
848 preprocessor_statement
= input_api
.re
.compile(r
'^\s*#')
849 os_macro
= input_api
.re
.compile(r
'defined\((OS_[^)]+)\)')
851 for lnum
, line
in f
.ChangedContents():
852 if preprocessor_statement
.search(line
):
853 for match
in os_macro
.finditer(line
):
854 if not match
.group(1) in _VALID_OS_MACROS
:
855 good
= _DidYouMeanOSMacro(match
.group(1))
856 did_you_mean
= ' (did you mean %s?)' % good
if good
else ''
857 results
.append(' %s:%d %s%s' % (f
.LocalPath(),
864 def _CheckForInvalidOSMacros(input_api
, output_api
):
865 """Check all affected files for invalid OS macros."""
867 for f
in input_api
.AffectedFiles():
868 if not f
.LocalPath().endswith(('.py', '.js', '.html', '.css')):
869 bad_macros
.extend(_CheckForInvalidOSMacrosInFile(input_api
, f
))
874 return [output_api
.PresubmitError(
875 'Possibly invalid OS macro[s] found. Please fix your code\n'
876 'or add your macro to src/PRESUBMIT.py.', bad_macros
)]
879 def CheckChangeOnUpload(input_api
, output_api
):
881 results
.extend(_CommonChecks(input_api
, output_api
))
885 def CheckChangeOnCommit(input_api
, output_api
):
887 results
.extend(_CommonChecks(input_api
, output_api
))
888 # TODO(thestig) temporarily disabled, doesn't work in third_party/
889 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
890 # input_api, output_api, sources))
891 # Make sure the tree is 'open'.
892 results
.extend(input_api
.canned_checks
.CheckTreeIsOpen(
895 json_url
='http://chromium-status.appspot.com/current?format=json'))
896 results
.extend(input_api
.canned_checks
.CheckRietveldTryJobExecution(input_api
,
897 output_api
, 'http://codereview.chromium.org',
898 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
899 'tryserver@chromium.org'))
901 results
.extend(input_api
.canned_checks
.CheckChangeHasBugField(
902 input_api
, output_api
))
903 results
.extend(input_api
.canned_checks
.CheckChangeHasDescription(
904 input_api
, output_api
))
905 results
.extend(_CheckSubversionConfig(input_api
, output_api
))
909 def GetPreferredTrySlaves(project
, change
):
910 files
= change
.LocalPaths()
912 if not files
or all(re
.search(r
'[\\/]OWNERS$', f
) for f
in files
):
915 if all(re
.search('\.(m|mm)$|(^|[/_])mac[/_.]', f
) for f
in files
):
916 return ['mac_rel', 'mac_asan', 'mac:compile']
917 if all(re
.search('(^|[/_])win[/_.]', f
) for f
in files
):
918 return ['win_rel', 'win7_aura', 'win:compile']
919 if all(re
.search('(^|[/_])android[/_.]', f
) for f
in files
):
920 return ['android_dbg', 'android_clang_dbg']
921 if all(re
.search('^native_client_sdk', f
) for f
in files
):
922 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
923 if all(re
.search('[/_]ios[/_.]', f
) for f
in files
):
924 return ['ios_rel_device', 'ios_dbg_simulator']
934 'linux_clang:compile',
944 # Match things like path/aura/file.cc and path/file_aura.cc.
946 if any(re
.search('[/_](aura|chromeos)', f
) for f
in files
):
947 trybots
+= ['linux_chromeos_clang:compile', 'linux_chromeos_asan']