blob: 777fde19658d58043fd94472b9c37c8ca273ef65 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d1982009-02-19 16:33:1227
jochen9ea8fdbc2014-09-25 13:21:3528# The NetscapePlugIn library is excluded from pan-project as it will soon
29# be deleted together with the rest of the NPAPI and it's not worthwhile to
30# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3831_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3232 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3833)
34
[email protected]06e6d0ff2012-12-11 01:36:4435# Fragment of a regular expression that matches C++ and Objective-C++
36# implementation files.
37_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
38
39# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3244 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4450 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4951 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4752 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4953 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0854 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4955 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4456)
[email protected]ca8d1982009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
nyad2c548b2015-12-09 03:22:32167 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10168 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49169 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22170 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31171 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51172 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
173 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09174 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49175 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
176 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41177 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
178 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48179 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
180 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01181 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54182 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13183 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
184 "gnubby_auth_handler_linux\.cc$",
dnicoara171d8c82015-03-05 20:46:18185 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
rjkroege8471a0a92016-02-04 19:50:29186 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49187 ),
[email protected]23e6cbc2012-06-16 18:51:20188 ),
[email protected]52657f62013-05-20 05:30:31189 (
190 'SkRefPtr',
191 (
192 'The use of SkRefPtr is prohibited. ',
193 'Please use skia::RefPtr instead.'
194 ),
195 True,
196 (),
197 ),
198 (
199 'SkAutoRef',
200 (
201 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
202 'Please use skia::RefPtr instead.'
203 ),
204 True,
205 (),
206 ),
207 (
208 'SkAutoTUnref',
209 (
210 'The use of SkAutoTUnref is dangerous because it implicitly ',
211 'converts to a raw pointer. Please use skia::RefPtr instead.'
212 ),
213 True,
214 (),
215 ),
216 (
217 'SkAutoUnref',
218 (
219 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
220 'because it implicitly converts to a raw pointer. ',
221 'Please use skia::RefPtr instead.'
222 ),
223 True,
224 (),
225 ),
[email protected]d89eec82013-12-03 14:10:59226 (
227 r'/HANDLE_EINTR\(.*close',
228 (
229 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
230 'descriptor will be closed, and it is incorrect to retry the close.',
231 'Either call close directly and ignore its return value, or wrap close',
232 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
233 ),
234 True,
235 (),
236 ),
237 (
238 r'/IGNORE_EINTR\((?!.*close)',
239 (
240 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
241 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
242 ),
243 True,
244 (
245 # Files that #define IGNORE_EINTR.
246 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
247 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
248 ),
249 ),
[email protected]ec5b3f02014-04-04 18:43:43250 (
251 r'/v8::Extension\(',
252 (
253 'Do not introduce new v8::Extensions into the code base, use',
254 'gin::Wrappable instead. See http://crbug.com/334679',
255 ),
256 True,
[email protected]f55c90ee62014-04-12 00:50:03257 (
joaodasilva718f87672014-08-30 09:25:49258 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03259 ),
[email protected]ec5b3f02014-04-04 18:43:43260 ),
skyostilf9469f72015-04-20 10:38:52261 (
sdefresneeaeccc52015-04-22 08:18:32262 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52263 (
264 'MessageLoopProxy is deprecated. ',
265 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
266 ),
267 True,
kinuko59024ce2015-04-21 22:18:30268 (
269 # Internal message_loop related code may still use it.
270 r'^base[\\\/]message_loop[\\\/].*',
271 ),
skyostilf9469f72015-04-20 10:38:52272 ),
[email protected]127f18ec2012-06-16 05:05:59273)
274
mlamouria82272622014-09-16 18:45:04275_IPC_ENUM_TRAITS_DEPRECATED = (
276 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
277 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
278
[email protected]127f18ec2012-06-16 05:05:59279
[email protected]b00342e7f2013-03-26 16:21:54280_VALID_OS_MACROS = (
281 # Please keep sorted.
282 'OS_ANDROID',
283 'OS_BSD',
284 'OS_CAT', # For testing.
285 'OS_CHROMEOS',
286 'OS_FREEBSD',
287 'OS_IOS',
288 'OS_LINUX',
289 'OS_MACOSX',
290 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21291 'OS_NACL_NONSFI',
292 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54293 'OS_OPENBSD',
294 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37295 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54296 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54297 'OS_WIN',
298)
299
300
agrieve4b608422016-03-30 18:50:23301_ANDROID_SPECIFIC_PYDEPS_FILES = [
302 'build/android/test_runner.pydeps',
303]
304
305_GENERIC_PYDEPS_FILES = [
306 'build/secondary/tools/swarming_client/isolate.pydeps',
307]
308
309_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
310
311
[email protected]55459852011-08-10 15:17:19312def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
313 """Attempts to prevent use of functions intended only for testing in
314 non-testing code. For now this is just a best-effort implementation
315 that ignores header files and may have some false positives. A
316 better implementation would probably need a proper C++ parser.
317 """
318 # We only scan .cc files and the like, as the declaration of
319 # for-testing functions in header files are hard to distinguish from
320 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44321 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19322
jochenc0d4808c2015-07-27 09:25:42323 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19324 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09325 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19326 exclusion_pattern = input_api.re.compile(
327 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
328 base_function_pattern, base_function_pattern))
329
330 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44331 black_list = (_EXCLUDED_PATHS +
332 _TEST_CODE_EXCLUDED_PATHS +
333 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19334 return input_api.FilterSourceFile(
335 affected_file,
336 white_list=(file_inclusion_pattern, ),
337 black_list=black_list)
338
339 problems = []
340 for f in input_api.AffectedSourceFiles(FilterFile):
341 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24342 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03343 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46344 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03345 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19346 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03347 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19348
349 if problems:
[email protected]f7051d52013-04-02 18:31:42350 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03351 else:
352 return []
[email protected]55459852011-08-10 15:17:19353
354
[email protected]10689ca2011-09-02 02:31:54355def _CheckNoIOStreamInHeaders(input_api, output_api):
356 """Checks to make sure no .h files include <iostream>."""
357 files = []
358 pattern = input_api.re.compile(r'^#include\s*<iostream>',
359 input_api.re.MULTILINE)
360 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
361 if not f.LocalPath().endswith('.h'):
362 continue
363 contents = input_api.ReadFile(f)
364 if pattern.search(contents):
365 files.append(f)
366
367 if len(files):
368 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06369 'Do not #include <iostream> in header files, since it inserts static '
370 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54371 '#include <ostream>. See http://crbug.com/94794',
372 files) ]
373 return []
374
375
[email protected]72df4e782012-06-21 16:28:18376def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52377 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18378 problems = []
379 for f in input_api.AffectedFiles():
380 if (not f.LocalPath().endswith(('.cc', '.mm'))):
381 continue
382
383 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04384 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18385 problems.append(' %s:%d' % (f.LocalPath(), line_num))
386
387 if not problems:
388 return []
389 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
390 '\n'.join(problems))]
391
392
danakj61c1aa22015-10-26 19:55:52393def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
394 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
395 errors = []
396 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
397 input_api.re.MULTILINE)
398 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
399 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
400 continue
401 for lnum, line in f.ChangedContents():
402 if input_api.re.search(pattern, line):
403 errors.append(output_api.PresubmitError(
404 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
405 'DCHECK_IS_ON()", not forgetting the braces.')
406 % (f.LocalPath(), lnum)))
407 return errors
408
409
mcasasb7440c282015-02-04 14:52:19410def _FindHistogramNameInLine(histogram_name, line):
411 """Tries to find a histogram name or prefix in a line."""
412 if not "affected-histogram" in line:
413 return histogram_name in line
414 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
415 # the histogram_name.
416 if not '"' in line:
417 return False
418 histogram_prefix = line.split('\"')[1]
419 return histogram_prefix in histogram_name
420
421
422def _CheckUmaHistogramChanges(input_api, output_api):
423 """Check that UMA histogram names in touched lines can still be found in other
424 lines of the patch or in histograms.xml. Note that this check would not catch
425 the reverse: changes in histograms.xml not matched in the code itself."""
426 touched_histograms = []
427 histograms_xml_modifications = []
428 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
429 for f in input_api.AffectedFiles():
430 # If histograms.xml itself is modified, keep the modified lines for later.
431 if f.LocalPath().endswith(('histograms.xml')):
432 histograms_xml_modifications = f.ChangedContents()
433 continue
434 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
435 continue
436 for line_num, line in f.ChangedContents():
437 found = pattern.search(line)
438 if found:
439 touched_histograms.append([found.group(1), f, line_num])
440
441 # Search for the touched histogram names in the local modifications to
442 # histograms.xml, and, if not found, on the base histograms.xml file.
443 unmatched_histograms = []
444 for histogram_info in touched_histograms:
445 histogram_name_found = False
446 for line_num, line in histograms_xml_modifications:
447 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
448 if histogram_name_found:
449 break
450 if not histogram_name_found:
451 unmatched_histograms.append(histogram_info)
452
eromanb90c82e7e32015-04-01 15:13:49453 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19454 problems = []
455 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49456 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19457 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45458 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19459 histogram_name_found = False
460 for line in histograms_xml:
461 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
462 if histogram_name_found:
463 break
464 if not histogram_name_found:
465 problems.append(' [%s:%d] %s' %
466 (f.LocalPath(), line_num, histogram_name))
467
468 if not problems:
469 return []
470 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
471 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49472 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19473
474
[email protected]8ea5d4b2011-09-13 21:49:22475def _CheckNoNewWStrings(input_api, output_api):
476 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27477 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22478 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20479 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57480 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
481 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20482 continue
[email protected]8ea5d4b2011-09-13 21:49:22483
[email protected]a11dbe9b2012-08-07 01:32:58484 allowWString = False
[email protected]b5c24292011-11-28 14:38:20485 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58486 if 'presubmit: allow wstring' in line:
487 allowWString = True
488 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27489 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58490 allowWString = False
491 else:
492 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22493
[email protected]55463aa62011-10-12 00:48:27494 if not problems:
495 return []
496 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58497 ' If you are calling a cross-platform API that accepts a wstring, '
498 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27499 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22500
501
[email protected]2a8ac9c2011-10-19 17:20:44502def _CheckNoDEPSGIT(input_api, output_api):
503 """Make sure .DEPS.git is never modified manually."""
504 if any(f.LocalPath().endswith('.DEPS.git') for f in
505 input_api.AffectedFiles()):
506 return [output_api.PresubmitError(
507 'Never commit changes to .DEPS.git. This file is maintained by an\n'
508 'automated system based on what\'s in DEPS and your changes will be\n'
509 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34510 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44511 'for more information')]
512 return []
513
514
tandriief664692014-09-23 14:51:47515def _CheckValidHostsInDEPS(input_api, output_api):
516 """Checks that DEPS file deps are from allowed_hosts."""
517 # Run only if DEPS file has been modified to annoy fewer bystanders.
518 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
519 return []
520 # Outsource work to gclient verify
521 try:
522 input_api.subprocess.check_output(['gclient', 'verify'])
523 return []
524 except input_api.subprocess.CalledProcessError, error:
525 return [output_api.PresubmitError(
526 'DEPS file must have only git dependencies.',
527 long_text=error.output)]
528
529
[email protected]127f18ec2012-06-16 05:05:59530def _CheckNoBannedFunctions(input_api, output_api):
531 """Make sure that banned functions are not used."""
532 warnings = []
533 errors = []
534
535 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
536 for f in input_api.AffectedFiles(file_filter=file_filter):
537 for line_num, line in f.ChangedContents():
538 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26539 matched = False
540 if func_name[0:1] == '/':
541 regex = func_name[1:]
542 if input_api.re.search(regex, line):
543 matched = True
544 elif func_name in line:
545 matched = True
546 if matched:
[email protected]127f18ec2012-06-16 05:05:59547 problems = warnings;
548 if error:
549 problems = errors;
550 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
551 for message_line in message:
552 problems.append(' %s' % message_line)
553
554 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
555 for f in input_api.AffectedFiles(file_filter=file_filter):
556 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49557 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
558 def IsBlacklisted(affected_file, blacklist):
559 local_path = affected_file.LocalPath()
560 for item in blacklist:
561 if input_api.re.match(item, local_path):
562 return True
563 return False
564 if IsBlacklisted(f, excluded_paths):
565 continue
[email protected]d89eec82013-12-03 14:10:59566 matched = False
567 if func_name[0:1] == '/':
568 regex = func_name[1:]
569 if input_api.re.search(regex, line):
570 matched = True
571 elif func_name in line:
572 matched = True
573 if matched:
[email protected]127f18ec2012-06-16 05:05:59574 problems = warnings;
575 if error:
576 problems = errors;
577 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
578 for message_line in message:
579 problems.append(' %s' % message_line)
580
581 result = []
582 if (warnings):
583 result.append(output_api.PresubmitPromptWarning(
584 'Banned functions were used.\n' + '\n'.join(warnings)))
585 if (errors):
586 result.append(output_api.PresubmitError(
587 'Banned functions were used.\n' + '\n'.join(errors)))
588 return result
589
590
[email protected]6c063c62012-07-11 19:11:06591def _CheckNoPragmaOnce(input_api, output_api):
592 """Make sure that banned functions are not used."""
593 files = []
594 pattern = input_api.re.compile(r'^#pragma\s+once',
595 input_api.re.MULTILINE)
596 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
597 if not f.LocalPath().endswith('.h'):
598 continue
599 contents = input_api.ReadFile(f)
600 if pattern.search(contents):
601 files.append(f)
602
603 if files:
604 return [output_api.PresubmitError(
605 'Do not use #pragma once in header files.\n'
606 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
607 files)]
608 return []
609
[email protected]127f18ec2012-06-16 05:05:59610
[email protected]e7479052012-09-19 00:26:12611def _CheckNoTrinaryTrueFalse(input_api, output_api):
612 """Checks to make sure we don't introduce use of foo ? true : false."""
613 problems = []
614 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
615 for f in input_api.AffectedFiles():
616 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
617 continue
618
619 for line_num, line in f.ChangedContents():
620 if pattern.match(line):
621 problems.append(' %s:%d' % (f.LocalPath(), line_num))
622
623 if not problems:
624 return []
625 return [output_api.PresubmitPromptWarning(
626 'Please consider avoiding the "? true : false" pattern if possible.\n' +
627 '\n'.join(problems))]
628
629
[email protected]55f9f382012-07-31 11:02:18630def _CheckUnwantedDependencies(input_api, output_api):
631 """Runs checkdeps on #include statements added in this
632 change. Breaking - rules is an error, breaking ! rules is a
633 warning.
634 """
mohan.reddyf21db962014-10-16 12:26:47635 import sys
[email protected]55f9f382012-07-31 11:02:18636 # We need to wait until we have an input_api object and use this
637 # roundabout construct to import checkdeps because this file is
638 # eval-ed and thus doesn't have __file__.
639 original_sys_path = sys.path
640 try:
641 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47642 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18643 import checkdeps
644 from cpp_checker import CppChecker
645 from rules import Rule
646 finally:
647 # Restore sys.path to what it was before.
648 sys.path = original_sys_path
649
650 added_includes = []
651 for f in input_api.AffectedFiles():
652 if not CppChecker.IsCppFile(f.LocalPath()):
653 continue
654
655 changed_lines = [line for line_num, line in f.ChangedContents()]
656 added_includes.append([f.LocalPath(), changed_lines])
657
[email protected]26385172013-05-09 23:11:35658 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18659
660 error_descriptions = []
661 warning_descriptions = []
662 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
663 added_includes):
664 description_with_path = '%s\n %s' % (path, rule_description)
665 if rule_type == Rule.DISALLOW:
666 error_descriptions.append(description_with_path)
667 else:
668 warning_descriptions.append(description_with_path)
669
670 results = []
671 if error_descriptions:
672 results.append(output_api.PresubmitError(
673 'You added one or more #includes that violate checkdeps rules.',
674 error_descriptions))
675 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42676 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18677 'You added one or more #includes of files that are temporarily\n'
678 'allowed but being removed. Can you avoid introducing the\n'
679 '#include? See relevant DEPS file(s) for details and contacts.',
680 warning_descriptions))
681 return results
682
683
[email protected]fbcafe5a2012-08-08 15:31:22684def _CheckFilePermissions(input_api, output_api):
685 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15686 if input_api.platform == 'win32':
687 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29688 checkperms_tool = input_api.os_path.join(
689 input_api.PresubmitLocalPath(),
690 'tools', 'checkperms', 'checkperms.py')
691 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47692 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22693 for f in input_api.AffectedFiles():
694 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11695 try:
696 input_api.subprocess.check_output(args)
697 return []
698 except input_api.subprocess.CalledProcessError as error:
699 return [output_api.PresubmitError(
700 'checkperms.py failed:',
701 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22702
703
[email protected]c8278b32012-10-30 20:35:49704def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
705 """Makes sure we don't include ui/aura/window_property.h
706 in header files.
707 """
708 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
709 errors = []
710 for f in input_api.AffectedFiles():
711 if not f.LocalPath().endswith('.h'):
712 continue
713 for line_num, line in f.ChangedContents():
714 if pattern.match(line):
715 errors.append(' %s:%d' % (f.LocalPath(), line_num))
716
717 results = []
718 if errors:
719 results.append(output_api.PresubmitError(
720 'Header files should not include ui/aura/window_property.h', errors))
721 return results
722
723
[email protected]cf9b78f2012-11-14 11:40:28724def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
725 """Checks that the lines in scope occur in the right order.
726
727 1. C system files in alphabetical order
728 2. C++ system files in alphabetical order
729 3. Project's .h files
730 """
731
732 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
733 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
734 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
735
736 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
737
738 state = C_SYSTEM_INCLUDES
739
740 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57741 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28742 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55743 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28744 for line_num, line in scope:
745 if c_system_include_pattern.match(line):
746 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55747 problem_linenums.append((line_num, previous_line_num,
748 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28749 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55750 problem_linenums.append((line_num, previous_line_num,
751 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28752 elif cpp_system_include_pattern.match(line):
753 if state == C_SYSTEM_INCLUDES:
754 state = CPP_SYSTEM_INCLUDES
755 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55756 problem_linenums.append((line_num, previous_line_num,
757 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28758 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55759 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28760 elif custom_include_pattern.match(line):
761 if state != CUSTOM_INCLUDES:
762 state = CUSTOM_INCLUDES
763 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55764 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28765 else:
brucedawson70fadb02015-06-30 17:47:55766 problem_linenums.append((line_num, previous_line_num,
767 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28768 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57769 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28770
771 warnings = []
brucedawson70fadb02015-06-30 17:47:55772 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57773 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55774 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28775 return warnings
776
777
[email protected]ac294a12012-12-06 16:38:43778def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28779 """Checks the #include order for the given file f."""
780
[email protected]2299dcf2012-11-15 19:56:24781 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30782 # Exclude the following includes from the check:
783 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
784 # specific order.
785 # 2) <atlbase.h>, "build/build_config.h"
786 excluded_include_pattern = input_api.re.compile(
787 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24788 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33789 # Match the final or penultimate token if it is xxxtest so we can ignore it
790 # when considering the special first include.
791 test_file_tag_pattern = input_api.re.compile(
792 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11793 if_pattern = input_api.re.compile(
794 r'\s*#\s*(if|elif|else|endif|define|undef).*')
795 # Some files need specialized order of includes; exclude such files from this
796 # check.
797 uncheckable_includes_pattern = input_api.re.compile(
798 r'\s*#include '
799 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28800
801 contents = f.NewContents()
802 warnings = []
803 line_num = 0
804
[email protected]ac294a12012-12-06 16:38:43805 # Handle the special first include. If the first include file is
806 # some/path/file.h, the corresponding including file can be some/path/file.cc,
807 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
808 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33809 # If the included file is some/path/file_platform.h the including file could
810 # also be some/path/file_xxxtest_platform.h.
811 including_file_base_name = test_file_tag_pattern.sub(
812 '', input_api.os_path.basename(f.LocalPath()))
813
[email protected]ac294a12012-12-06 16:38:43814 for line in contents:
815 line_num += 1
816 if system_include_pattern.match(line):
817 # No special first include -> process the line again along with normal
818 # includes.
819 line_num -= 1
820 break
821 match = custom_include_pattern.match(line)
822 if match:
823 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33824 header_basename = test_file_tag_pattern.sub(
825 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
826
827 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24828 # No special first include -> process the line again along with normal
829 # includes.
830 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43831 break
[email protected]cf9b78f2012-11-14 11:40:28832
833 # Split into scopes: Each region between #if and #endif is its own scope.
834 scopes = []
835 current_scope = []
836 for line in contents[line_num:]:
837 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11838 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54839 continue
[email protected]2309b0fa02012-11-16 12:18:27840 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28841 scopes.append(current_scope)
842 current_scope = []
[email protected]962f117e2012-11-22 18:11:56843 elif ((system_include_pattern.match(line) or
844 custom_include_pattern.match(line)) and
845 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28846 current_scope.append((line_num, line))
847 scopes.append(current_scope)
848
849 for scope in scopes:
850 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
851 changed_linenums))
852 return warnings
853
854
855def _CheckIncludeOrder(input_api, output_api):
856 """Checks that the #include order is correct.
857
858 1. The corresponding header for source files.
859 2. C system files in alphabetical order
860 3. C++ system files in alphabetical order
861 4. Project's .h files in alphabetical order
862
[email protected]ac294a12012-12-06 16:38:43863 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
864 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28865 """
[email protected]e120b012014-08-15 19:08:35866 def FileFilterIncludeOrder(affected_file):
867 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
868 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28869
870 warnings = []
[email protected]e120b012014-08-15 19:08:35871 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08872 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43873 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
874 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28875
876 results = []
877 if warnings:
[email protected]f7051d52013-04-02 18:31:42878 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53879 warnings))
[email protected]cf9b78f2012-11-14 11:40:28880 return results
881
882
[email protected]70ca77752012-11-20 03:45:03883def _CheckForVersionControlConflictsInFile(input_api, f):
884 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
885 errors = []
886 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23887 if f.LocalPath().endswith('.md'):
888 # First-level headers in markdown look a lot like version control
889 # conflict markers. http://daringfireball.net/projects/markdown/basics
890 continue
[email protected]70ca77752012-11-20 03:45:03891 if pattern.match(line):
892 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
893 return errors
894
895
896def _CheckForVersionControlConflicts(input_api, output_api):
897 """Usually this is not intentional and will cause a compile failure."""
898 errors = []
899 for f in input_api.AffectedFiles():
900 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
901
902 results = []
903 if errors:
904 results.append(output_api.PresubmitError(
905 'Version control conflict markers found, please resolve.', errors))
906 return results
907
908
[email protected]06e6d0ff2012-12-11 01:36:44909def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
910 def FilterFile(affected_file):
911 """Filter function for use with input_api.AffectedSourceFiles,
912 below. This filters out everything except non-test files from
913 top-level directories that generally speaking should not hard-code
914 service URLs (e.g. src/android_webview/, src/content/ and others).
915 """
916 return input_api.FilterSourceFile(
917 affected_file,
[email protected]78bb39d62012-12-11 15:11:56918 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44919 black_list=(_EXCLUDED_PATHS +
920 _TEST_CODE_EXCLUDED_PATHS +
921 input_api.DEFAULT_BLACK_LIST))
922
reillyi38965732015-11-16 18:27:33923 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
924 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46925 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
926 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44927 problems = [] # items are (filename, line_number, line)
928 for f in input_api.AffectedSourceFiles(FilterFile):
929 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46930 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44931 problems.append((f.LocalPath(), line_num, line))
932
933 if problems:
[email protected]f7051d52013-04-02 18:31:42934 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44935 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58936 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44937 [' %s:%d: %s' % (
938 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03939 else:
940 return []
[email protected]06e6d0ff2012-12-11 01:36:44941
942
[email protected]d2530012013-01-25 16:39:27943def _CheckNoAbbreviationInPngFileName(input_api, output_api):
944 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31945 The native_client_sdk directory is excluded because it has auto-generated PNG
946 files for documentation.
[email protected]d2530012013-01-25 16:39:27947 """
[email protected]d2530012013-01-25 16:39:27948 errors = []
binji0dcdf342014-12-12 18:32:31949 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
950 black_list = (r'^native_client_sdk[\\\/]',)
951 file_filter = lambda f: input_api.FilterSourceFile(
952 f, white_list=white_list, black_list=black_list)
953 for f in input_api.AffectedFiles(include_deletes=False,
954 file_filter=file_filter):
955 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27956
957 results = []
958 if errors:
959 results.append(output_api.PresubmitError(
960 'The name of PNG files should not have abbreviations. \n'
961 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
962 'Contact [email protected] if you have questions.', errors))
963 return results
964
965
[email protected]14a6131c2014-01-08 01:15:41966def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08967 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41968 a set of DEPS entries that we should look up.
969
970 For a directory (rather than a specific filename) we fake a path to
971 a specific filename by adding /DEPS. This is chosen as a file that
972 will seldom or never be subject to per-file include_rules.
973 """
[email protected]2b438d62013-11-14 17:54:14974 # We ignore deps entries on auto-generated directories.
975 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08976
977 # This pattern grabs the path without basename in the first
978 # parentheses, and the basename (if present) in the second. It
979 # relies on the simple heuristic that if there is a basename it will
980 # be a header file ending in ".h".
981 pattern = re.compile(
982 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14983 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08984 for changed_line in changed_lines:
985 m = pattern.match(changed_line)
986 if m:
987 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14988 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41989 if m.group(2):
990 results.add('%s%s' % (path, m.group(2)))
991 else:
992 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08993 return results
994
995
[email protected]e871964c2013-05-13 14:14:55996def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
997 """When a dependency prefixed with + is added to a DEPS file, we
998 want to make sure that the change is reviewed by an OWNER of the
999 target file or directory, to avoid layering violations from being
1000 introduced. This check verifies that this happens.
1001 """
1002 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241003
1004 file_filter = lambda f: not input_api.re.match(
1005 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1006 for f in input_api.AffectedFiles(include_deletes=False,
1007 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551008 filename = input_api.os_path.basename(f.LocalPath())
1009 if filename == 'DEPS':
1010 changed_lines |= set(line.strip()
1011 for line_num, line
1012 in f.ChangedContents())
1013 if not changed_lines:
1014 return []
1015
[email protected]14a6131c2014-01-08 01:15:411016 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1017 changed_lines)
[email protected]e871964c2013-05-13 14:14:551018 if not virtual_depended_on_files:
1019 return []
1020
1021 if input_api.is_committing:
1022 if input_api.tbr:
1023 return [output_api.PresubmitNotifyResult(
1024 '--tbr was specified, skipping OWNERS check for DEPS additions')]
1025 if not input_api.change.issue:
1026 return [output_api.PresubmitError(
1027 "DEPS approval by OWNERS check failed: this change has "
1028 "no Rietveld issue number, so we can't check it for approvals.")]
1029 output = output_api.PresubmitError
1030 else:
1031 output = output_api.PresubmitNotifyResult
1032
1033 owners_db = input_api.owners_db
1034 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1035 input_api,
1036 owners_db.email_regexp,
1037 approval_needed=input_api.is_committing)
1038
1039 owner_email = owner_email or input_api.change.author_email
1040
[email protected]de4f7d22013-05-23 14:27:461041 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511042 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461043 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551044 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1045 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411046
1047 # We strip the /DEPS part that was added by
1048 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1049 # directory.
1050 def StripDeps(path):
1051 start_deps = path.rfind('/DEPS')
1052 if start_deps != -1:
1053 return path[:start_deps]
1054 else:
1055 return path
1056 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551057 for path in missing_files]
1058
1059 if unapproved_dependencies:
1060 output_list = [
[email protected]14a6131c2014-01-08 01:15:411061 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551062 '\n '.join(sorted(unapproved_dependencies)))]
1063 if not input_api.is_committing:
1064 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1065 output_list.append(output(
1066 'Suggested missing target path OWNERS:\n %s' %
1067 '\n '.join(suggested_owners or [])))
1068 return output_list
1069
1070 return []
1071
1072
[email protected]85218562013-11-22 07:41:401073def _CheckSpamLogging(input_api, output_api):
1074 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1075 black_list = (_EXCLUDED_PATHS +
1076 _TEST_CODE_EXCLUDED_PATHS +
1077 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501078 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191079 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481080 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461081 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121082 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1083 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581084 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161085 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031086 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151087 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1088 r"^chromecast[\\\/]",
1089 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311090 r"^components[\\\/]html_viewer[\\\/]"
1091 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461092 # TODO(peter): Remove this exception. https://crbug.com/534537
1093 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1094 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251095 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1096 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111097 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151098 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111099 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521100 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501101 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361102 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311103 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131104 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441105 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451106 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021107 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441108 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401109 source_file_filter = lambda x: input_api.FilterSourceFile(
1110 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1111
1112 log_info = []
1113 printf = []
1114
1115 for f in input_api.AffectedSourceFiles(source_file_filter):
1116 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471117 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401118 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471119 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131120 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371121
mohan.reddyf21db962014-10-16 12:26:471122 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371123 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471124 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401125 printf.append(f.LocalPath())
1126
1127 if log_info:
1128 return [output_api.PresubmitError(
1129 'These files spam the console log with LOG(INFO):',
1130 items=log_info)]
1131 if printf:
1132 return [output_api.PresubmitError(
1133 'These files spam the console log with printf/fprintf:',
1134 items=printf)]
1135 return []
1136
1137
[email protected]49aa76a2013-12-04 06:59:161138def _CheckForAnonymousVariables(input_api, output_api):
1139 """These types are all expected to hold locks while in scope and
1140 so should never be anonymous (which causes them to be immediately
1141 destroyed)."""
1142 they_who_must_be_named = [
1143 'base::AutoLock',
1144 'base::AutoReset',
1145 'base::AutoUnlock',
1146 'SkAutoAlphaRestore',
1147 'SkAutoBitmapShaderInstall',
1148 'SkAutoBlitterChoose',
1149 'SkAutoBounderCommit',
1150 'SkAutoCallProc',
1151 'SkAutoCanvasRestore',
1152 'SkAutoCommentBlock',
1153 'SkAutoDescriptor',
1154 'SkAutoDisableDirectionCheck',
1155 'SkAutoDisableOvalCheck',
1156 'SkAutoFree',
1157 'SkAutoGlyphCache',
1158 'SkAutoHDC',
1159 'SkAutoLockColors',
1160 'SkAutoLockPixels',
1161 'SkAutoMalloc',
1162 'SkAutoMaskFreeImage',
1163 'SkAutoMutexAcquire',
1164 'SkAutoPathBoundsUpdate',
1165 'SkAutoPDFRelease',
1166 'SkAutoRasterClipValidate',
1167 'SkAutoRef',
1168 'SkAutoTime',
1169 'SkAutoTrace',
1170 'SkAutoUnref',
1171 ]
1172 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1173 # bad: base::AutoLock(lock.get());
1174 # not bad: base::AutoLock lock(lock.get());
1175 bad_pattern = input_api.re.compile(anonymous)
1176 # good: new base::AutoLock(lock.get())
1177 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1178 errors = []
1179
1180 for f in input_api.AffectedFiles():
1181 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1182 continue
1183 for linenum, line in f.ChangedContents():
1184 if bad_pattern.search(line) and not good_pattern.search(line):
1185 errors.append('%s:%d' % (f.LocalPath(), linenum))
1186
1187 if errors:
1188 return [output_api.PresubmitError(
1189 'These lines create anonymous variables that need to be named:',
1190 items=errors)]
1191 return []
1192
1193
[email protected]5fe0f8742013-11-29 01:04:591194def _CheckCygwinShell(input_api, output_api):
1195 source_file_filter = lambda x: input_api.FilterSourceFile(
1196 x, white_list=(r'.+\.(gyp|gypi)$',))
1197 cygwin_shell = []
1198
1199 for f in input_api.AffectedSourceFiles(source_file_filter):
1200 for linenum, line in f.ChangedContents():
1201 if 'msvs_cygwin_shell' in line:
1202 cygwin_shell.append(f.LocalPath())
1203 break
1204
1205 if cygwin_shell:
1206 return [output_api.PresubmitError(
1207 'These files should not use msvs_cygwin_shell (the default is 0):',
1208 items=cygwin_shell)]
1209 return []
1210
[email protected]85218562013-11-22 07:41:401211
[email protected]999261d2014-03-03 20:08:081212def _CheckUserActionUpdate(input_api, output_api):
1213 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521214 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081215 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521216 # If actions.xml is already included in the changelist, the PRESUBMIT
1217 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081218 return []
1219
[email protected]999261d2014-03-03 20:08:081220 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1221 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521222 current_actions = None
[email protected]999261d2014-03-03 20:08:081223 for f in input_api.AffectedFiles(file_filter=file_filter):
1224 for line_num, line in f.ChangedContents():
1225 match = input_api.re.search(action_re, line)
1226 if match:
[email protected]2f92dec2014-03-07 19:21:521227 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1228 # loaded only once.
1229 if not current_actions:
1230 with open('tools/metrics/actions/actions.xml') as actions_f:
1231 current_actions = actions_f.read()
1232 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081233 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521234 action = 'name="{0}"'.format(action_name)
1235 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081236 return [output_api.PresubmitPromptWarning(
1237 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521238 'tools/metrics/actions/actions.xml. Please run '
1239 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081240 % (f.LocalPath(), line_num, action_name))]
1241 return []
1242
1243
[email protected]99171a92014-06-03 08:44:471244def _GetJSONParseError(input_api, filename, eat_comments=True):
1245 try:
1246 contents = input_api.ReadFile(filename)
1247 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131248 import sys
1249 original_sys_path = sys.path
1250 try:
1251 sys.path = sys.path + [input_api.os_path.join(
1252 input_api.PresubmitLocalPath(),
1253 'tools', 'json_comment_eater')]
1254 import json_comment_eater
1255 finally:
1256 sys.path = original_sys_path
1257 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471258
1259 input_api.json.loads(contents)
1260 except ValueError as e:
1261 return e
1262 return None
1263
1264
1265def _GetIDLParseError(input_api, filename):
1266 try:
1267 contents = input_api.ReadFile(filename)
1268 idl_schema = input_api.os_path.join(
1269 input_api.PresubmitLocalPath(),
1270 'tools', 'json_schema_compiler', 'idl_schema.py')
1271 process = input_api.subprocess.Popen(
1272 [input_api.python_executable, idl_schema],
1273 stdin=input_api.subprocess.PIPE,
1274 stdout=input_api.subprocess.PIPE,
1275 stderr=input_api.subprocess.PIPE,
1276 universal_newlines=True)
1277 (_, error) = process.communicate(input=contents)
1278 return error or None
1279 except ValueError as e:
1280 return e
1281
1282
1283def _CheckParseErrors(input_api, output_api):
1284 """Check that IDL and JSON files do not contain syntax errors."""
1285 actions = {
1286 '.idl': _GetIDLParseError,
1287 '.json': _GetJSONParseError,
1288 }
1289 # These paths contain test data and other known invalid JSON files.
1290 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491291 r'test[\\\/]data[\\\/]',
1292 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471293 ]
1294 # Most JSON files are preprocessed and support comments, but these do not.
1295 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491296 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471297 ]
1298 # Only run IDL checker on files in these directories.
1299 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491300 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1301 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471302 ]
1303
1304 def get_action(affected_file):
1305 filename = affected_file.LocalPath()
1306 return actions.get(input_api.os_path.splitext(filename)[1])
1307
1308 def MatchesFile(patterns, path):
1309 for pattern in patterns:
1310 if input_api.re.search(pattern, path):
1311 return True
1312 return False
1313
1314 def FilterFile(affected_file):
1315 action = get_action(affected_file)
1316 if not action:
1317 return False
1318 path = affected_file.LocalPath()
1319
1320 if MatchesFile(excluded_patterns, path):
1321 return False
1322
1323 if (action == _GetIDLParseError and
1324 not MatchesFile(idl_included_patterns, path)):
1325 return False
1326 return True
1327
1328 results = []
1329 for affected_file in input_api.AffectedFiles(
1330 file_filter=FilterFile, include_deletes=False):
1331 action = get_action(affected_file)
1332 kwargs = {}
1333 if (action == _GetJSONParseError and
1334 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1335 kwargs['eat_comments'] = False
1336 parse_error = action(input_api,
1337 affected_file.AbsoluteLocalPath(),
1338 **kwargs)
1339 if parse_error:
1340 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1341 (affected_file.LocalPath(), parse_error)))
1342 return results
1343
1344
[email protected]760deea2013-12-10 19:33:491345def _CheckJavaStyle(input_api, output_api):
1346 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471347 import sys
[email protected]760deea2013-12-10 19:33:491348 original_sys_path = sys.path
1349 try:
1350 sys.path = sys.path + [input_api.os_path.join(
1351 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1352 import checkstyle
1353 finally:
1354 # Restore sys.path to what it was before.
1355 sys.path = original_sys_path
1356
1357 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091358 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511359 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491360
1361
dskiba88634f4e2015-08-14 23:03:291362def _CheckAndroidToastUsage(input_api, output_api):
1363 """Checks that code uses org.chromium.ui.widget.Toast instead of
1364 android.widget.Toast (Chromium Toast doesn't force hardware
1365 acceleration on low-end devices, saving memory).
1366 """
1367 toast_import_pattern = input_api.re.compile(
1368 r'^import android\.widget\.Toast;$')
1369
1370 errors = []
1371
1372 sources = lambda affected_file: input_api.FilterSourceFile(
1373 affected_file,
1374 black_list=(_EXCLUDED_PATHS +
1375 _TEST_CODE_EXCLUDED_PATHS +
1376 input_api.DEFAULT_BLACK_LIST +
1377 (r'^chromecast[\\\/].*',
1378 r'^remoting[\\\/].*')),
1379 white_list=(r'.*\.java$',))
1380
1381 for f in input_api.AffectedSourceFiles(sources):
1382 for line_num, line in f.ChangedContents():
1383 if toast_import_pattern.search(line):
1384 errors.append("%s:%d" % (f.LocalPath(), line_num))
1385
1386 results = []
1387
1388 if errors:
1389 results.append(output_api.PresubmitError(
1390 'android.widget.Toast usage is detected. Android toasts use hardware'
1391 ' acceleration, and can be\ncostly on low-end devices. Please use'
1392 ' org.chromium.ui.widget.Toast instead.\n'
1393 'Contact [email protected] if you have any questions.',
1394 errors))
1395
1396 return results
1397
1398
dgnaa68d5e2015-06-10 10:08:221399def _CheckAndroidCrLogUsage(input_api, output_api):
1400 """Checks that new logs using org.chromium.base.Log:
1401 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511402 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221403 """
1404 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121405 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1406 class_in_base_pattern = input_api.re.compile(
1407 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1408 has_some_log_import_pattern = input_api.re.compile(
1409 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221410 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121411 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221412 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511413 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221414 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221415
Vincent Scheib16d7b272015-09-15 18:09:071416 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221417 'or contact [email protected] for more info.')
1418 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121419
dgnaa68d5e2015-06-10 10:08:221420 tag_decl_errors = []
1421 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121422 tag_errors = []
dgn38736db2015-09-18 19:20:511423 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121424 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221425
1426 for f in input_api.AffectedSourceFiles(sources):
1427 file_content = input_api.ReadFile(f)
1428 has_modified_logs = False
1429
1430 # Per line checks
dgn87d9fb62015-06-12 09:15:121431 if (cr_log_import_pattern.search(file_content) or
1432 (class_in_base_pattern.search(file_content) and
1433 not has_some_log_import_pattern.search(file_content))):
1434 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221435 for line_num, line in f.ChangedContents():
1436
1437 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121438 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221439 if match:
1440 has_modified_logs = True
1441
1442 # Make sure it uses "TAG"
1443 if not match.group('tag') == 'TAG':
1444 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121445 else:
1446 # Report non cr Log function calls in changed lines
1447 for line_num, line in f.ChangedContents():
1448 if log_call_pattern.search(line):
1449 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221450
1451 # Per file checks
1452 if has_modified_logs:
1453 # Make sure the tag is using the "cr" prefix and is not too long
1454 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511455 tag_name = match.group('name') if match else None
1456 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221457 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511458 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221459 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511460 elif '.' in tag_name:
1461 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221462
1463 results = []
1464 if tag_decl_errors:
1465 results.append(output_api.PresubmitPromptWarning(
1466 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511467 '"private static final String TAG = "<package tag>".\n'
1468 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221469 tag_decl_errors))
1470
1471 if tag_length_errors:
1472 results.append(output_api.PresubmitError(
1473 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511474 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221475 tag_length_errors))
1476
1477 if tag_errors:
1478 results.append(output_api.PresubmitPromptWarning(
1479 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1480 tag_errors))
1481
dgn87d9fb62015-06-12 09:15:121482 if util_log_errors:
dgn4401aa52015-04-29 16:26:171483 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121484 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1485 util_log_errors))
1486
dgn38736db2015-09-18 19:20:511487 if tag_with_dot_errors:
1488 results.append(output_api.PresubmitPromptWarning(
1489 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1490 tag_with_dot_errors))
1491
dgn4401aa52015-04-29 16:26:171492 return results
1493
1494
agrieve7b6479d82015-10-07 14:24:221495def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1496 """Checks if MDPI assets are placed in a correct directory."""
1497 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1498 ('/res/drawable/' in f.LocalPath() or
1499 '/res/drawable-ldrtl/' in f.LocalPath()))
1500 errors = []
1501 for f in input_api.AffectedFiles(include_deletes=False,
1502 file_filter=file_filter):
1503 errors.append(' %s' % f.LocalPath())
1504
1505 results = []
1506 if errors:
1507 results.append(output_api.PresubmitError(
1508 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1509 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1510 '/res/drawable-ldrtl/.\n'
1511 'Contact [email protected] if you have questions.', errors))
1512 return results
1513
1514
agrieve4b608422016-03-30 18:50:231515class PydepsChecker(object):
1516 def __init__(self, input_api, pydeps_files):
1517 self._file_cache = {}
1518 self._input_api = input_api
1519 self._pydeps_files = pydeps_files
1520
1521 def _LoadFile(self, path):
1522 """Returns the list of paths within a .pydeps file relative to //."""
1523 if path not in self._file_cache:
1524 with open(path) as f:
1525 self._file_cache[path] = f.read()
1526 return self._file_cache[path]
1527
1528 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1529 """Returns an interable of paths within the .pydep, relativized to //."""
1530 os_path = self._input_api.os_path
1531 pydeps_dir = os_path.dirname(pydeps_path)
1532 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1533 if not l.startswith('*'))
1534 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1535
1536 def _CreateFilesToPydepsMap(self):
1537 """Returns a map of local_path -> list_of_pydeps."""
1538 ret = {}
1539 for pydep_local_path in self._pydeps_files:
1540 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1541 ret.setdefault(path, []).append(pydep_local_path)
1542 return ret
1543
1544 def ComputeAffectedPydeps(self):
1545 """Returns an iterable of .pydeps files that might need regenerating."""
1546 affected_pydeps = set()
1547 file_to_pydeps_map = None
1548 for f in self._input_api.AffectedFiles(include_deletes=True):
1549 local_path = f.LocalPath()
1550 if local_path == 'DEPS':
1551 return self._pydeps_files
1552 elif local_path.endswith('.pydeps'):
1553 if local_path in self._pydeps_files:
1554 affected_pydeps.add(local_path)
1555 elif local_path.endswith('.py'):
1556 if file_to_pydeps_map is None:
1557 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1558 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1559 return affected_pydeps
1560
1561 def DetermineIfStale(self, pydeps_path):
1562 """Runs print_python_deps.py to see if the files is stale."""
1563 old_pydeps_data = self._LoadFile(pydeps_path)
1564
1565 m = self._input_api.re.search(r'# target: //(.*)', old_pydeps_data)
1566 if not m:
1567 return ['COULD NOT FIND .pydeps TARGET']
1568 target = m.group(1)
1569 m = self._input_api.re.search(r'# root: //(.*)', old_pydeps_data)
1570 if not m:
1571 return ['COULD NOT FIND .pydeps ROOT']
1572 root = m.group(1) or '.'
1573
1574 cmd = ['build/print_python_deps.py', '--root', root, target]
1575 new_pydeps_data = self._input_api.subprocess.check_output(cmd)
1576 if old_pydeps_data != new_pydeps_data:
1577 return cmd[:-1] + ['--output', pydeps_path] + cmd[-1:]
1578
1579
1580def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1581 """Checks if a .pydeps file needs to be regenerated."""
1582 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1583 is_android = input_api.os_path.exists('third_party/android_tools')
1584 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1585 results = []
1586 # First, check for new / deleted .pydeps.
1587 for f in input_api.AffectedFiles(include_deletes=True):
1588 if f.LocalPath().endswith('.pydeps'):
1589 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1590 results.append(output_api.PresubmitError(
1591 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1592 'remove %s' % f.LocalPath()))
1593 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1594 results.append(output_api.PresubmitError(
1595 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1596 'include %s' % f.LocalPath()))
1597
1598 if results:
1599 return results
1600
1601 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1602
1603 for pydep_path in checker.ComputeAffectedPydeps():
1604 try:
1605 cmd = checker.DetermineIfStale(pydep_path)
1606 if cmd:
1607 results.append(output_api.PresubmitError(
1608 'File is stale: %s\nTo regenerate, run:\n%s' % (pydep_path,
1609 ' '.join(cmd))))
1610 except input_api.subprocess.CalledProcessError as error:
1611 return [output_api.PresubmitError('Error running ' + ' '.join(error.cmd),
1612 long_text=error.output)]
1613
1614 return results
1615
1616
mnaganov9b9b1fe82014-12-11 16:30:361617def _CheckForCopyrightedCode(input_api, output_api):
1618 """Verifies that newly added code doesn't contain copyrighted material
1619 and is properly licensed under the standard Chromium license.
1620
1621 As there can be false positives, we maintain a whitelist file. This check
1622 also verifies that the whitelist file is up to date.
1623 """
1624 import sys
1625 original_sys_path = sys.path
1626 try:
1627 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221628 input_api.PresubmitLocalPath(), 'tools')]
1629 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361630 finally:
1631 # Restore sys.path to what it was before.
1632 sys.path = original_sys_path
1633
1634 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1635
1636
glidere61efad2015-02-18 17:39:431637def _CheckSingletonInHeaders(input_api, output_api):
1638 """Checks to make sure no header files have |Singleton<|."""
1639 def FileFilter(affected_file):
1640 # It's ok for base/memory/singleton.h to have |Singleton<|.
1641 black_list = (_EXCLUDED_PATHS +
1642 input_api.DEFAULT_BLACK_LIST +
1643 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1644 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1645
sergeyu34d21222015-09-16 00:11:441646 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431647 files = []
1648 for f in input_api.AffectedSourceFiles(FileFilter):
1649 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1650 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1651 contents = input_api.ReadFile(f)
1652 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241653 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431654 pattern.search(line)):
1655 files.append(f)
1656 break
1657
1658 if files:
1659 return [ output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441660 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431661 'Please move them to an appropriate source file so that the ' +
1662 'template gets instantiated in a single compilation unit.',
1663 files) ]
1664 return []
1665
1666
dbeam37e8e7402016-02-10 22:58:201667def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1668 """Checks for old style compiled_resources.gyp files."""
1669 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1670
1671 added_compiled_resources = filter(is_compiled_resource, [
1672 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1673 ])
1674
1675 if not added_compiled_resources:
1676 return []
1677
1678 return [output_api.PresubmitError(
1679 "Found new compiled_resources.gyp files:\n%s\n\n"
1680 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551681 "please use compiled_resources2.gyp instead:\n"
1682 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1683 %
dbeam37e8e7402016-02-10 22:58:201684 "\n".join(added_compiled_resources))]
1685
1686
[email protected]fd20b902014-05-09 02:14:531687_DEPRECATED_CSS = [
1688 # Values
1689 ( "-webkit-box", "flex" ),
1690 ( "-webkit-inline-box", "inline-flex" ),
1691 ( "-webkit-flex", "flex" ),
1692 ( "-webkit-inline-flex", "inline-flex" ),
1693 ( "-webkit-min-content", "min-content" ),
1694 ( "-webkit-max-content", "max-content" ),
1695
1696 # Properties
1697 ( "-webkit-background-clip", "background-clip" ),
1698 ( "-webkit-background-origin", "background-origin" ),
1699 ( "-webkit-background-size", "background-size" ),
1700 ( "-webkit-box-shadow", "box-shadow" ),
1701
1702 # Functions
1703 ( "-webkit-gradient", "gradient" ),
1704 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1705 ( "-webkit-linear-gradient", "linear-gradient" ),
1706 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1707 ( "-webkit-radial-gradient", "radial-gradient" ),
1708 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1709]
1710
1711def _CheckNoDeprecatedCSS(input_api, output_api):
1712 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251713 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341714 documentation and iOS CSS for dom distiller
1715 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251716 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531717 results = []
dbeam070cfe62014-10-22 06:44:021718 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251719 black_list = (_EXCLUDED_PATHS +
1720 _TEST_CODE_EXCLUDED_PATHS +
1721 input_api.DEFAULT_BLACK_LIST +
1722 (r"^chrome/common/extensions/docs",
1723 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341724 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051725 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441726 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251727 r"^native_client_sdk"))
1728 file_filter = lambda f: input_api.FilterSourceFile(
1729 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531730 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1731 for line_num, line in fpath.ChangedContents():
1732 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021733 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531734 results.append(output_api.PresubmitError(
1735 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1736 (fpath.LocalPath(), line_num, deprecated_value, value)))
1737 return results
1738
mohan.reddyf21db962014-10-16 12:26:471739
dbeam070cfe62014-10-22 06:44:021740_DEPRECATED_JS = [
1741 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1742 ( "__defineGetter__", "Object.defineProperty" ),
1743 ( "__defineSetter__", "Object.defineProperty" ),
1744]
1745
1746def _CheckNoDeprecatedJS(input_api, output_api):
1747 """Make sure that we don't use deprecated JS in Chrome code."""
1748 results = []
1749 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1750 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1751 input_api.DEFAULT_BLACK_LIST)
1752 file_filter = lambda f: input_api.FilterSourceFile(
1753 f, white_list=file_inclusion_pattern, black_list=black_list)
1754 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1755 for lnum, line in fpath.ChangedContents():
1756 for (deprecated, replacement) in _DEPRECATED_JS:
1757 if deprecated in line:
1758 results.append(output_api.PresubmitError(
1759 "%s:%d: Use of deprecated JS %s, use %s instead" %
1760 (fpath.LocalPath(), lnum, deprecated, replacement)))
1761 return results
1762
1763
dgnaa68d5e2015-06-10 10:08:221764def _AndroidSpecificOnUploadChecks(input_api, output_api):
1765 """Groups checks that target android code."""
1766 results = []
dgnaa68d5e2015-06-10 10:08:221767 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221768 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291769 results.extend(_CheckAndroidToastUsage(input_api, output_api))
sergiyb7e573182016-04-01 11:47:121770 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221771 return results
1772
1773
[email protected]22c9bd72011-03-27 16:47:391774def _CommonChecks(input_api, output_api):
1775 """Checks common to both upload and commit."""
1776 results = []
1777 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381778 input_api, output_api,
1779 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461780 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191781 results.extend(
[email protected]760deea2013-12-10 19:33:491782 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541783 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181784 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521785 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221786 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441787 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591788 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061789 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121790 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181791 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221792 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491793 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271794 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031795 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491796 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441797 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271798 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541799 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441800 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461801 # TODO(danakj): Remove this when base/move.h is removed.
dchengcf95c122015-12-18 08:29:161802 results.extend(_CheckForUsingPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551803 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041804 results.extend(
1805 input_api.canned_checks.CheckChangeHasNoTabs(
1806 input_api,
1807 output_api,
1808 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401809 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161810 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591811 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081812 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531813 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021814 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471815 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041816 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361817 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231818 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431819 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201820 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241821
1822 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1823 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1824 input_api, output_api,
1825 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381826 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391827 return results
[email protected]1f7b4172010-01-28 01:17:341828
[email protected]b337cb5b2011-01-23 21:24:051829
[email protected]66daa702011-05-28 14:41:461830def _CheckAuthorizedAuthor(input_api, output_api):
1831 """For non-googler/chromites committers, verify the author's email address is
1832 in AUTHORS.
1833 """
[email protected]9bb9cb82011-06-13 20:43:011834 # TODO(maruel): Add it to input_api?
1835 import fnmatch
1836
[email protected]66daa702011-05-28 14:41:461837 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011838 if not author:
1839 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461840 return []
[email protected]c99663292011-05-31 19:46:081841 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461842 input_api.PresubmitLocalPath(), 'AUTHORS')
1843 valid_authors = (
1844 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1845 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181846 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441847 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231848 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461849 return [output_api.PresubmitPromptWarning(
1850 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1851 '\n'
1852 'http://www.chromium.org/developers/contributing-code and read the '
1853 '"Legal" section\n'
1854 'If you are a chromite, verify the contributor signed the CLA.') %
1855 author)]
1856 return []
1857
1858
[email protected]b8079ae4a2012-12-05 19:56:491859def _CheckPatchFiles(input_api, output_api):
1860 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1861 if f.LocalPath().endswith(('.orig', '.rej'))]
1862 if problems:
1863 return [output_api.PresubmitError(
1864 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031865 else:
1866 return []
[email protected]b8079ae4a2012-12-05 19:56:491867
1868
[email protected]b00342e7f2013-03-26 16:21:541869def _DidYouMeanOSMacro(bad_macro):
1870 try:
1871 return {'A': 'OS_ANDROID',
1872 'B': 'OS_BSD',
1873 'C': 'OS_CHROMEOS',
1874 'F': 'OS_FREEBSD',
1875 'L': 'OS_LINUX',
1876 'M': 'OS_MACOSX',
1877 'N': 'OS_NACL',
1878 'O': 'OS_OPENBSD',
1879 'P': 'OS_POSIX',
1880 'S': 'OS_SOLARIS',
1881 'W': 'OS_WIN'}[bad_macro[3].upper()]
1882 except KeyError:
1883 return ''
1884
1885
1886def _CheckForInvalidOSMacrosInFile(input_api, f):
1887 """Check for sensible looking, totally invalid OS macros."""
1888 preprocessor_statement = input_api.re.compile(r'^\s*#')
1889 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1890 results = []
1891 for lnum, line in f.ChangedContents():
1892 if preprocessor_statement.search(line):
1893 for match in os_macro.finditer(line):
1894 if not match.group(1) in _VALID_OS_MACROS:
1895 good = _DidYouMeanOSMacro(match.group(1))
1896 did_you_mean = ' (did you mean %s?)' % good if good else ''
1897 results.append(' %s:%d %s%s' % (f.LocalPath(),
1898 lnum,
1899 match.group(1),
1900 did_you_mean))
1901 return results
1902
1903
1904def _CheckForInvalidOSMacros(input_api, output_api):
1905 """Check all affected files for invalid OS macros."""
1906 bad_macros = []
1907 for f in input_api.AffectedFiles():
1908 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1909 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1910
1911 if not bad_macros:
1912 return []
1913
1914 return [output_api.PresubmitError(
1915 'Possibly invalid OS macro[s] found. Please fix your code\n'
1916 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1917
lliabraa35bab3932014-10-01 12:16:441918
1919def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1920 """Check all affected files for invalid "if defined" macros."""
1921 ALWAYS_DEFINED_MACROS = (
1922 "TARGET_CPU_PPC",
1923 "TARGET_CPU_PPC64",
1924 "TARGET_CPU_68K",
1925 "TARGET_CPU_X86",
1926 "TARGET_CPU_ARM",
1927 "TARGET_CPU_MIPS",
1928 "TARGET_CPU_SPARC",
1929 "TARGET_CPU_ALPHA",
1930 "TARGET_IPHONE_SIMULATOR",
1931 "TARGET_OS_EMBEDDED",
1932 "TARGET_OS_IPHONE",
1933 "TARGET_OS_MAC",
1934 "TARGET_OS_UNIX",
1935 "TARGET_OS_WIN32",
1936 )
1937 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1938 results = []
1939 for lnum, line in f.ChangedContents():
1940 for match in ifdef_macro.finditer(line):
1941 if match.group(1) in ALWAYS_DEFINED_MACROS:
1942 always_defined = ' %s is always defined. ' % match.group(1)
1943 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1944 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1945 lnum,
1946 always_defined,
1947 did_you_mean))
1948 return results
1949
1950
1951def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1952 """Check all affected files for invalid "if defined" macros."""
1953 bad_macros = []
1954 for f in input_api.AffectedFiles():
1955 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1956 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1957
1958 if not bad_macros:
1959 return []
1960
1961 return [output_api.PresubmitError(
1962 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1963 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1964 bad_macros)]
1965
1966
dchengcf95c122015-12-18 08:29:161967def _CheckForUsingPass(input_api, output_api):
danakj3c84d0c2014-10-06 15:35:461968 """Check all affected files for using side effects of Pass."""
1969 errors = []
1970 for f in input_api.AffectedFiles():
1971 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1972 for lnum, line in f.ChangedContents():
dchengcf95c122015-12-18 08:29:161973 # Warn on any use of foo.Pass().
1974 if input_api.re.search(r'[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461975 errors.append(output_api.PresubmitError(
dchengcf95c122015-12-18 08:29:161976 ('%s:%d uses Pass(); please use std::move() instead. ' +
1977 'See crbug.com/557422.') % (f.LocalPath(), lnum)))
danakj3c84d0c2014-10-06 15:35:461978 return errors
1979
1980
mlamouria82272622014-09-16 18:45:041981def _CheckForIPCRules(input_api, output_api):
1982 """Check for same IPC rules described in
1983 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1984 """
1985 base_pattern = r'IPC_ENUM_TRAITS\('
1986 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1987 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1988
1989 problems = []
1990 for f in input_api.AffectedSourceFiles(None):
1991 local_path = f.LocalPath()
1992 if not local_path.endswith('.h'):
1993 continue
1994 for line_number, line in f.ChangedContents():
1995 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1996 problems.append(
1997 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1998
1999 if problems:
2000 return [output_api.PresubmitPromptWarning(
2001 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2002 else:
2003 return []
2004
[email protected]b00342e7f2013-03-26 16:21:542005
mostynbb639aca52015-01-07 20:31:232006def _CheckForWindowsLineEndings(input_api, output_api):
2007 """Check source code and known ascii text files for Windows style line
2008 endings.
2009 """
earthdok1b5e0ee2015-03-10 15:19:102010 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232011
2012 file_inclusion_pattern = (
2013 known_text_files,
2014 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2015 )
2016
2017 filter = lambda f: input_api.FilterSourceFile(
2018 f, white_list=file_inclusion_pattern, black_list=None)
2019 files = [f.LocalPath() for f in
2020 input_api.AffectedSourceFiles(filter)]
2021
2022 problems = []
2023
2024 for file in files:
2025 fp = open(file, 'r')
2026 for line in fp:
2027 if line.endswith('\r\n'):
2028 problems.append(file)
2029 break
2030 fp.close()
2031
2032 if problems:
2033 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2034 'these files to contain Windows style line endings?\n' +
2035 '\n'.join(problems))]
2036
2037 return []
2038
2039
[email protected]1f7b4172010-01-28 01:17:342040def CheckChangeOnUpload(input_api, output_api):
2041 results = []
2042 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472043 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:172044 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:282045 results.extend(
2046 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192047 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222048 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542049 return results
[email protected]ca8d1982009-02-19 16:33:122050
2051
[email protected]1bfb8322014-04-23 01:02:412052def GetTryServerMasterForBot(bot):
2053 """Returns the Try Server master for the given bot.
2054
[email protected]0bb112362014-07-26 04:38:322055 It tries to guess the master from the bot name, but may still fail
2056 and return None. There is no longer a default master.
2057 """
2058 # Potentially ambiguous bot names are listed explicitly.
2059 master_map = {
[email protected]0bb112362014-07-26 04:38:322060 'chromium_presubmit': 'tryserver.chromium.linux',
2061 'blink_presubmit': 'tryserver.chromium.linux',
2062 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412063 }
[email protected]0bb112362014-07-26 04:38:322064 master = master_map.get(bot)
2065 if not master:
sergiyb37fd293f2015-02-26 06:55:012066 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322067 master = 'tryserver.chromium.linux'
2068 elif 'win' in bot:
2069 master = 'tryserver.chromium.win'
2070 elif 'mac' in bot or 'ios' in bot:
2071 master = 'tryserver.chromium.mac'
2072 return master
[email protected]1bfb8322014-04-23 01:02:412073
2074
Paweł Hajdan, Jr55083782014-12-19 20:32:562075def GetDefaultTryConfigs(bots):
2076 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012077 """
2078
Paweł Hajdan, Jr55083782014-12-19 20:32:562079 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412080
2081 # Build up the mapping from tryserver master to bot/test.
2082 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562083 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412084 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2085 return out
[email protected]38c6a512013-12-18 23:48:012086
2087
[email protected]ca8d1982009-02-19 16:33:122088def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542089 results = []
[email protected]1f7b4172010-01-28 01:17:342090 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542091 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272092 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342093 input_api,
2094 output_api,
[email protected]2fdd1f362013-01-16 03:56:032095 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272096
[email protected]3e4eb112011-01-18 03:29:542097 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2098 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412099 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2100 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542101 return results