1 # Copyright (c) 2011 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.
13 r
"^net/tools/spdyshark/[\\\/].*",
20 def _CheckNoInterfacesInBase(input_api
, output_api
):
21 """Checks to make sure no files in libbase.a have |@interface|."""
22 pattern
= input_api
.re
.compile(r
'^\s*@interface', input_api
.re
.MULTILINE
)
24 for f
in input_api
.AffectedSourceFiles(input_api
.FilterSourceFile
):
25 if (f
.LocalPath().startswith('base/') and
26 not f
.LocalPath().endswith('_unittest.mm')):
27 contents
= input_api
.ReadFile(f
)
28 if pattern
.search(contents
):
32 return [ output_api
.PresubmitError(
33 'Objective-C interfaces or categories are forbidden in libbase. ' +
34 'See http://groups.google.com/a/chromium.org/group/chromium-dev/' +
35 'browse_thread/thread/efb28c10435987fd',
40 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api
, output_api
):
41 """Attempts to prevent use of functions intended only for testing in
42 non-testing code. For now this is just a best-effort implementation
43 that ignores header files and may have some false positives. A
44 better implementation would probably need a proper C++ parser.
46 # We only scan .cc files and the like, as the declaration of
47 # for-testing functions in header files are hard to distinguish from
48 # calls to such functions without a proper C++ parser.
49 source_extensions
= r
'\.(cc|cpp|cxx|mm)$'
50 file_inclusion_pattern
= r
'.+%s' % source_extensions
51 file_exclusion_pattern
= (
52 r
'.+(_test_support|profile_sync_service_harness|'
53 r
'_(api|browser|perf|unit|ui)?test)%s' % source_extensions
)
54 path_exclusion_pattern
= r
'.*[/\\](test|tool(s)?)[/\\].*'
56 base_function_pattern
= r
'ForTest(ing)?|for_test(ing)?'
57 inclusion_pattern
= input_api
.re
.compile(r
'(%s)\s*\(' % base_function_pattern
)
58 exclusion_pattern
= input_api
.re
.compile(
59 r
'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
60 base_function_pattern
, base_function_pattern
))
62 def FilterFile(affected_file
):
63 black_list
= ((file_exclusion_pattern
, path_exclusion_pattern
, ) +
64 _EXCLUDED_PATHS
+ input_api
.DEFAULT_BLACK_LIST
)
65 return input_api
.FilterSourceFile(
67 white_list
=(file_inclusion_pattern
, ),
68 black_list
=black_list
)
71 for f
in input_api
.AffectedSourceFiles(FilterFile
):
72 local_path
= f
.LocalPath()
73 lines
= input_api
.ReadFile(f
).splitlines()
76 if (inclusion_pattern
.search(line
) and
77 not exclusion_pattern
.search(line
)):
79 '%s:%d\n %s' % (local_path
, line_number
, line
.strip()))
83 return [output_api
.PresubmitPromptWarning(
84 'You might be calling functions intended only for testing from\n'
85 'production code. Please verify that the following usages are OK,\n'
86 'and email joi@chromium.org if you are seeing false positives:',
92 def _CheckNoIOStreamInHeaders(input_api
, output_api
):
93 """Checks to make sure no .h files include <iostream>."""
95 pattern
= input_api
.re
.compile(r
'^#include\s*<iostream>',
96 input_api
.re
.MULTILINE
)
97 for f
in input_api
.AffectedSourceFiles(input_api
.FilterSourceFile
):
98 if not f
.LocalPath().endswith('.h'):
100 contents
= input_api
.ReadFile(f
)
101 if pattern
.search(contents
):
105 return [ output_api
.PresubmitError(
106 'Do not #include <iostream> in header files, since it inserts static ' +
107 'initialization into every file including the header. Instead, ' +
108 '#include <ostream>. See http://crbug.com/94794',
113 def _CheckNoNewWStrings(input_api
, output_api
):
114 """Checks to make sure we don't introduce use of wstrings."""
116 for f
in input_api
.AffectedFiles():
117 for line_num
, line
in f
.ChangedContents():
118 if (not f
.LocalPath().endswith(('.cc', '.h')) or
119 f
.LocalPath().endswith('test.cc')):
122 if 'wstring' in line
:
123 errors
.append(output_api
.PresubmitError(
124 '%s, line %d: new code should not use wstrings. If you are '
125 'calling an API that accepts a wstring, fix the API.'
126 % (f
.LocalPath(), line_num
)))
131 def _CommonChecks(input_api
, output_api
):
132 """Checks common to both upload and commit."""
134 results
.extend(input_api
.canned_checks
.PanProjectChecks(
135 input_api
, output_api
, excluded_paths
=_EXCLUDED_PATHS
))
136 results
.extend(_CheckNoInterfacesInBase(input_api
, output_api
))
137 results
.extend(_CheckAuthorizedAuthor(input_api
, output_api
))
139 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api
, output_api
))
140 results
.extend(_CheckNoIOStreamInHeaders(input_api
, output_api
))
141 results
.extend(_CheckNoNewWStrings(input_api
, output_api
))
145 def _CheckSubversionConfig(input_api
, output_api
):
146 """Verifies the subversion config file is correctly setup.
148 Checks that autoprops are enabled, returns an error otherwise.
150 join
= input_api
.os_path
.join
151 if input_api
.platform
== 'win32':
152 appdata
= input_api
.environ
.get('APPDATA', '')
154 return [output_api
.PresubmitError('%APPDATA% is not configured.')]
155 path
= join(appdata
, 'Subversion', 'config')
157 home
= input_api
.environ
.get('HOME', '')
159 return [output_api
.PresubmitError('$HOME is not configured.')]
160 path
= join(home
, '.subversion', 'config')
163 'Please look at http://dev.chromium.org/developers/coding-style to\n'
164 'configure your subversion configuration file. This enables automatic\n'
165 'properties to simplify the project maintenance.\n'
166 'Pro-tip: just download and install\n'
167 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
170 lines
= open(path
, 'r').read().splitlines()
171 # Make sure auto-props is enabled and check for 2 Chromium standard
173 if (not '*.cc = svn:eol-style=LF' in lines
or
174 not '*.pdf = svn:mime-type=application/pdf' in lines
or
175 not 'enable-auto-props = yes' in lines
):
177 output_api
.PresubmitNotifyResult(
178 'It looks like you have not configured your subversion config '
179 'file or it is not up-to-date.\n' + error_msg
)
181 except (OSError, IOError):
183 output_api
.PresubmitNotifyResult(
184 'Can\'t find your subversion config file.\n' + error_msg
)
189 def _CheckAuthorizedAuthor(input_api
, output_api
):
190 """For non-googler/chromites committers, verify the author's email address is
193 # TODO(maruel): Add it to input_api?
196 author
= input_api
.change
.author_email
198 input_api
.logging
.info('No author, skipping AUTHOR check')
200 authors_path
= input_api
.os_path
.join(
201 input_api
.PresubmitLocalPath(), 'AUTHORS')
203 input_api
.re
.match(r
'[^#]+\s+\<(.+?)\>\s*$', line
)
204 for line
in open(authors_path
))
205 valid_authors
= [item
.group(1).lower() for item
in valid_authors
if item
]
206 if input_api
.verbose
:
207 print 'Valid authors are %s' % ', '.join(valid_authors
)
208 if not any(fnmatch
.fnmatch(author
.lower(), valid
) for valid
in valid_authors
):
209 return [output_api
.PresubmitPromptWarning(
210 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
212 'http://www.chromium.org/developers/contributing-code and read the '
214 'If you are a chromite, verify the contributor signed the CLA.') %
219 def CheckChangeOnUpload(input_api
, output_api
):
221 results
.extend(_CommonChecks(input_api
, output_api
))
225 def CheckChangeOnCommit(input_api
, output_api
):
227 results
.extend(_CommonChecks(input_api
, output_api
))
228 # TODO(thestig) temporarily disabled, doesn't work in third_party/
229 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
230 # input_api, output_api, sources))
231 # Make sure the tree is 'open'.
232 results
.extend(input_api
.canned_checks
.CheckTreeIsOpen(
235 json_url
='http://chromium-status.appspot.com/current?format=json'))
236 results
.extend(input_api
.canned_checks
.CheckRietveldTryJobExecution(input_api
,
237 output_api
, 'http://codereview.chromium.org', ('win', 'linux', 'mac'),
238 'tryserver@chromium.org'))
240 results
.extend(input_api
.canned_checks
.CheckChangeHasBugField(
241 input_api
, output_api
))
242 results
.extend(input_api
.canned_checks
.CheckChangeHasTestField(
243 input_api
, output_api
))
244 results
.extend(_CheckSubversionConfig(input_api
, output_api
))
248 def GetPreferredTrySlaves(project
, change
):
249 only_objc_files
= all(
250 f
.LocalPath().endswith(('.mm', '.m')) for f
in change
.AffectedFiles())
253 return ['win', 'linux', 'mac']