blob: c777fb800552bdeb4bf54c5bd121d5684b1e6e19 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-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[\\\/].*",
19 r"^v8[\\\/].*",
20 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5321 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3422 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4223 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
[email protected]d2600602014-02-19 00:09:1924 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js"
[email protected]4306417642009-06-11 00:33:4025)
[email protected]ca8d19842009-02-19 16:33:1226
jochen9ea8fdbc2014-09-25 13:21:3527# The NetscapePlugIn library is excluded from pan-project as it will soon
28# be deleted together with the rest of the NPAPI and it's not worthwhile to
29# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3830_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3231 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3832)
33
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
38# Regular expression that matches code only used for test binaries
39# (best effort).
40_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4941 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4442 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3243 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1244 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4445 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4946 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0547 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4948 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4449 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4950 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4751 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4952 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0853 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4954 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4455)
[email protected]ca8d19842009-02-19 16:33:1256
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
brucedawson70fadb02015-06-30 17:47:5566 'collation (LC_COLLATE=C) and check\nhttps://google-styleguide.googlecode'
marjaa017dc482015-03-09 17:13:4067 '.com/svn/trunk/cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
[email protected]127f18ec2012-06-16 05:05:5969_BANNED_OBJC_FUNCTIONS = (
70 (
71 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2072 (
73 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5974 'prohibited. Please use CrTrackingArea instead.',
75 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
76 ),
77 False,
78 ),
79 (
[email protected]eaae1972014-04-16 04:17:2680 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2081 (
82 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5983 'instead.',
84 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
85 ),
86 False,
87 ),
88 (
89 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2090 (
91 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5992 'Please use |convertPoint:(point) fromView:nil| instead.',
93 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
94 ),
95 True,
96 ),
97 (
98 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2099 (
100 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59101 'Please use |convertPoint:(point) toView:nil| instead.',
102 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
103 ),
104 True,
105 ),
106 (
107 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20108 (
109 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59110 'Please use |convertRect:(point) fromView:nil| instead.',
111 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
112 ),
113 True,
114 ),
115 (
116 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20117 (
118 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59119 'Please use |convertRect:(point) toView:nil| instead.',
120 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
121 ),
122 True,
123 ),
124 (
125 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20126 (
127 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59128 'Please use |convertSize:(point) fromView:nil| instead.',
129 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
130 ),
131 True,
132 ),
133 (
134 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20135 (
136 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59137 'Please use |convertSize:(point) toView:nil| instead.',
138 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
139 ),
140 True,
141 ),
142)
143
144
145_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20146 # Make sure that gtest's FRIEND_TEST() macro is not used; the
147 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30148 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20149 (
150 'FRIEND_TEST(',
151 (
[email protected]e3c945502012-06-26 20:01:49152 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20153 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
154 ),
155 False,
[email protected]7345da02012-11-27 14:31:49156 (),
[email protected]23e6cbc2012-06-16 18:51:20157 ),
158 (
159 'ScopedAllowIO',
160 (
[email protected]e3c945502012-06-26 20:01:49161 'New code should not use ScopedAllowIO. Post a task to the blocking',
162 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20163 ),
[email protected]e3c945502012-06-26 20:01:49164 True,
[email protected]7345da02012-11-27 14:31:49165 (
thestig75844fdb2014-09-09 19:47:10166 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22167 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
alematee4016bb2014-11-12 17:38:51168 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
169 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09170 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
[email protected]de7d61ff2013-08-20 11:30:41171 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
172 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48173 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
174 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01175 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54176 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu34d21222015-09-16 00:11:44177 r"^remoting[\\\/]host[\\\/]gnubby_auth_handler_posix\.cc$",
dnicoara171d8c82015-03-05 20:46:18178 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
dnicoarab29d0512015-05-07 19:29:23179 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49180 ),
[email protected]23e6cbc2012-06-16 18:51:20181 ),
[email protected]52657f62013-05-20 05:30:31182 (
183 'SkRefPtr',
184 (
185 'The use of SkRefPtr is prohibited. ',
186 'Please use skia::RefPtr instead.'
187 ),
188 True,
189 (),
190 ),
191 (
192 'SkAutoRef',
193 (
194 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
195 'Please use skia::RefPtr instead.'
196 ),
197 True,
198 (),
199 ),
200 (
201 'SkAutoTUnref',
202 (
203 'The use of SkAutoTUnref is dangerous because it implicitly ',
204 'converts to a raw pointer. Please use skia::RefPtr instead.'
205 ),
206 True,
207 (),
208 ),
209 (
210 'SkAutoUnref',
211 (
212 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
213 'because it implicitly converts to a raw pointer. ',
214 'Please use skia::RefPtr instead.'
215 ),
216 True,
217 (),
218 ),
[email protected]d89eec82013-12-03 14:10:59219 (
220 r'/HANDLE_EINTR\(.*close',
221 (
222 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
223 'descriptor will be closed, and it is incorrect to retry the close.',
224 'Either call close directly and ignore its return value, or wrap close',
225 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
226 ),
227 True,
228 (),
229 ),
230 (
231 r'/IGNORE_EINTR\((?!.*close)',
232 (
233 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
234 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
235 ),
236 True,
237 (
238 # Files that #define IGNORE_EINTR.
239 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
240 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
241 ),
242 ),
[email protected]ec5b3f02014-04-04 18:43:43243 (
244 r'/v8::Extension\(',
245 (
246 'Do not introduce new v8::Extensions into the code base, use',
247 'gin::Wrappable instead. See http://crbug.com/334679',
248 ),
249 True,
[email protected]f55c90ee62014-04-12 00:50:03250 (
joaodasilva718f87672014-08-30 09:25:49251 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03252 ),
[email protected]ec5b3f02014-04-04 18:43:43253 ),
skyostilf9469f72015-04-20 10:38:52254 (
sdefresneeaeccc52015-04-22 08:18:32255 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52256 (
257 'MessageLoopProxy is deprecated. ',
258 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
259 ),
260 True,
kinuko59024ce2015-04-21 22:18:30261 (
262 # Internal message_loop related code may still use it.
263 r'^base[\\\/]message_loop[\\\/].*',
264 ),
skyostilf9469f72015-04-20 10:38:52265 ),
[email protected]127f18ec2012-06-16 05:05:59266)
267
mlamouria82272622014-09-16 18:45:04268_IPC_ENUM_TRAITS_DEPRECATED = (
269 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
270 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
271
[email protected]127f18ec2012-06-16 05:05:59272
[email protected]b00342e7f2013-03-26 16:21:54273_VALID_OS_MACROS = (
274 # Please keep sorted.
275 'OS_ANDROID',
[email protected]f4440b42014-03-19 05:47:01276 'OS_ANDROID_HOST',
[email protected]b00342e7f2013-03-26 16:21:54277 'OS_BSD',
278 'OS_CAT', # For testing.
279 'OS_CHROMEOS',
280 'OS_FREEBSD',
281 'OS_IOS',
282 'OS_LINUX',
283 'OS_MACOSX',
284 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21285 'OS_NACL_NONSFI',
286 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54287 'OS_OPENBSD',
288 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37289 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54290 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54291 'OS_WIN',
292)
293
294
[email protected]55459852011-08-10 15:17:19295def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
296 """Attempts to prevent use of functions intended only for testing in
297 non-testing code. For now this is just a best-effort implementation
298 that ignores header files and may have some false positives. A
299 better implementation would probably need a proper C++ parser.
300 """
301 # We only scan .cc files and the like, as the declaration of
302 # for-testing functions in header files are hard to distinguish from
303 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44304 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19305
jochenc0d4808c2015-07-27 09:25:42306 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19307 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09308 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19309 exclusion_pattern = input_api.re.compile(
310 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
311 base_function_pattern, base_function_pattern))
312
313 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44314 black_list = (_EXCLUDED_PATHS +
315 _TEST_CODE_EXCLUDED_PATHS +
316 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19317 return input_api.FilterSourceFile(
318 affected_file,
319 white_list=(file_inclusion_pattern, ),
320 black_list=black_list)
321
322 problems = []
323 for f in input_api.AffectedSourceFiles(FilterFile):
324 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24325 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03326 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46327 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03328 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19329 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03330 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19331
332 if problems:
[email protected]f7051d52013-04-02 18:31:42333 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03334 else:
335 return []
[email protected]55459852011-08-10 15:17:19336
337
[email protected]10689ca2011-09-02 02:31:54338def _CheckNoIOStreamInHeaders(input_api, output_api):
339 """Checks to make sure no .h files include <iostream>."""
340 files = []
341 pattern = input_api.re.compile(r'^#include\s*<iostream>',
342 input_api.re.MULTILINE)
343 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
344 if not f.LocalPath().endswith('.h'):
345 continue
346 contents = input_api.ReadFile(f)
347 if pattern.search(contents):
348 files.append(f)
349
350 if len(files):
351 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06352 'Do not #include <iostream> in header files, since it inserts static '
353 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54354 '#include <ostream>. See http://crbug.com/94794',
355 files) ]
356 return []
357
358
[email protected]72df4e782012-06-21 16:28:18359def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
360 """Checks to make sure no source files use UNIT_TEST"""
361 problems = []
362 for f in input_api.AffectedFiles():
363 if (not f.LocalPath().endswith(('.cc', '.mm'))):
364 continue
365
366 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04367 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18368 problems.append(' %s:%d' % (f.LocalPath(), line_num))
369
370 if not problems:
371 return []
372 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
373 '\n'.join(problems))]
374
375
mcasasb7440c282015-02-04 14:52:19376def _FindHistogramNameInLine(histogram_name, line):
377 """Tries to find a histogram name or prefix in a line."""
378 if not "affected-histogram" in line:
379 return histogram_name in line
380 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
381 # the histogram_name.
382 if not '"' in line:
383 return False
384 histogram_prefix = line.split('\"')[1]
385 return histogram_prefix in histogram_name
386
387
388def _CheckUmaHistogramChanges(input_api, output_api):
389 """Check that UMA histogram names in touched lines can still be found in other
390 lines of the patch or in histograms.xml. Note that this check would not catch
391 the reverse: changes in histograms.xml not matched in the code itself."""
392 touched_histograms = []
393 histograms_xml_modifications = []
394 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
395 for f in input_api.AffectedFiles():
396 # If histograms.xml itself is modified, keep the modified lines for later.
397 if f.LocalPath().endswith(('histograms.xml')):
398 histograms_xml_modifications = f.ChangedContents()
399 continue
400 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
401 continue
402 for line_num, line in f.ChangedContents():
403 found = pattern.search(line)
404 if found:
405 touched_histograms.append([found.group(1), f, line_num])
406
407 # Search for the touched histogram names in the local modifications to
408 # histograms.xml, and, if not found, on the base histograms.xml file.
409 unmatched_histograms = []
410 for histogram_info in touched_histograms:
411 histogram_name_found = False
412 for line_num, line in histograms_xml_modifications:
413 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
414 if histogram_name_found:
415 break
416 if not histogram_name_found:
417 unmatched_histograms.append(histogram_info)
418
eromanb90c82e7e32015-04-01 15:13:49419 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19420 problems = []
421 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49422 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19423 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45424 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19425 histogram_name_found = False
426 for line in histograms_xml:
427 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
428 if histogram_name_found:
429 break
430 if not histogram_name_found:
431 problems.append(' [%s:%d] %s' %
432 (f.LocalPath(), line_num, histogram_name))
433
434 if not problems:
435 return []
436 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
437 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49438 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19439
440
[email protected]8ea5d4b2011-09-13 21:49:22441def _CheckNoNewWStrings(input_api, output_api):
442 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27443 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22444 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20445 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57446 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
447 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20448 continue
[email protected]8ea5d4b2011-09-13 21:49:22449
[email protected]a11dbe9b2012-08-07 01:32:58450 allowWString = False
[email protected]b5c24292011-11-28 14:38:20451 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58452 if 'presubmit: allow wstring' in line:
453 allowWString = True
454 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27455 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58456 allowWString = False
457 else:
458 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22459
[email protected]55463aa62011-10-12 00:48:27460 if not problems:
461 return []
462 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58463 ' If you are calling a cross-platform API that accepts a wstring, '
464 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27465 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22466
467
[email protected]2a8ac9c2011-10-19 17:20:44468def _CheckNoDEPSGIT(input_api, output_api):
469 """Make sure .DEPS.git is never modified manually."""
470 if any(f.LocalPath().endswith('.DEPS.git') for f in
471 input_api.AffectedFiles()):
472 return [output_api.PresubmitError(
473 'Never commit changes to .DEPS.git. This file is maintained by an\n'
474 'automated system based on what\'s in DEPS and your changes will be\n'
475 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34476 '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:44477 'for more information')]
478 return []
479
480
tandriief664692014-09-23 14:51:47481def _CheckValidHostsInDEPS(input_api, output_api):
482 """Checks that DEPS file deps are from allowed_hosts."""
483 # Run only if DEPS file has been modified to annoy fewer bystanders.
484 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
485 return []
486 # Outsource work to gclient verify
487 try:
488 input_api.subprocess.check_output(['gclient', 'verify'])
489 return []
490 except input_api.subprocess.CalledProcessError, error:
491 return [output_api.PresubmitError(
492 'DEPS file must have only git dependencies.',
493 long_text=error.output)]
494
495
[email protected]127f18ec2012-06-16 05:05:59496def _CheckNoBannedFunctions(input_api, output_api):
497 """Make sure that banned functions are not used."""
498 warnings = []
499 errors = []
500
501 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
502 for f in input_api.AffectedFiles(file_filter=file_filter):
503 for line_num, line in f.ChangedContents():
504 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26505 matched = False
506 if func_name[0:1] == '/':
507 regex = func_name[1:]
508 if input_api.re.search(regex, line):
509 matched = True
510 elif func_name in line:
511 matched = True
512 if matched:
[email protected]127f18ec2012-06-16 05:05:59513 problems = warnings;
514 if error:
515 problems = errors;
516 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
517 for message_line in message:
518 problems.append(' %s' % message_line)
519
520 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
521 for f in input_api.AffectedFiles(file_filter=file_filter):
522 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49523 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
524 def IsBlacklisted(affected_file, blacklist):
525 local_path = affected_file.LocalPath()
526 for item in blacklist:
527 if input_api.re.match(item, local_path):
528 return True
529 return False
530 if IsBlacklisted(f, excluded_paths):
531 continue
[email protected]d89eec82013-12-03 14:10:59532 matched = False
533 if func_name[0:1] == '/':
534 regex = func_name[1:]
535 if input_api.re.search(regex, line):
536 matched = True
537 elif func_name in line:
538 matched = True
539 if matched:
[email protected]127f18ec2012-06-16 05:05:59540 problems = warnings;
541 if error:
542 problems = errors;
543 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
544 for message_line in message:
545 problems.append(' %s' % message_line)
546
547 result = []
548 if (warnings):
549 result.append(output_api.PresubmitPromptWarning(
550 'Banned functions were used.\n' + '\n'.join(warnings)))
551 if (errors):
552 result.append(output_api.PresubmitError(
553 'Banned functions were used.\n' + '\n'.join(errors)))
554 return result
555
556
[email protected]6c063c62012-07-11 19:11:06557def _CheckNoPragmaOnce(input_api, output_api):
558 """Make sure that banned functions are not used."""
559 files = []
560 pattern = input_api.re.compile(r'^#pragma\s+once',
561 input_api.re.MULTILINE)
562 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
563 if not f.LocalPath().endswith('.h'):
564 continue
565 contents = input_api.ReadFile(f)
566 if pattern.search(contents):
567 files.append(f)
568
569 if files:
570 return [output_api.PresubmitError(
571 'Do not use #pragma once in header files.\n'
572 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
573 files)]
574 return []
575
[email protected]127f18ec2012-06-16 05:05:59576
[email protected]e7479052012-09-19 00:26:12577def _CheckNoTrinaryTrueFalse(input_api, output_api):
578 """Checks to make sure we don't introduce use of foo ? true : false."""
579 problems = []
580 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
581 for f in input_api.AffectedFiles():
582 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
583 continue
584
585 for line_num, line in f.ChangedContents():
586 if pattern.match(line):
587 problems.append(' %s:%d' % (f.LocalPath(), line_num))
588
589 if not problems:
590 return []
591 return [output_api.PresubmitPromptWarning(
592 'Please consider avoiding the "? true : false" pattern if possible.\n' +
593 '\n'.join(problems))]
594
595
[email protected]55f9f382012-07-31 11:02:18596def _CheckUnwantedDependencies(input_api, output_api):
597 """Runs checkdeps on #include statements added in this
598 change. Breaking - rules is an error, breaking ! rules is a
599 warning.
600 """
mohan.reddyf21db962014-10-16 12:26:47601 import sys
[email protected]55f9f382012-07-31 11:02:18602 # We need to wait until we have an input_api object and use this
603 # roundabout construct to import checkdeps because this file is
604 # eval-ed and thus doesn't have __file__.
605 original_sys_path = sys.path
606 try:
607 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47608 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18609 import checkdeps
610 from cpp_checker import CppChecker
611 from rules import Rule
612 finally:
613 # Restore sys.path to what it was before.
614 sys.path = original_sys_path
615
616 added_includes = []
617 for f in input_api.AffectedFiles():
618 if not CppChecker.IsCppFile(f.LocalPath()):
619 continue
620
621 changed_lines = [line for line_num, line in f.ChangedContents()]
622 added_includes.append([f.LocalPath(), changed_lines])
623
[email protected]26385172013-05-09 23:11:35624 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18625
626 error_descriptions = []
627 warning_descriptions = []
628 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
629 added_includes):
630 description_with_path = '%s\n %s' % (path, rule_description)
631 if rule_type == Rule.DISALLOW:
632 error_descriptions.append(description_with_path)
633 else:
634 warning_descriptions.append(description_with_path)
635
636 results = []
637 if error_descriptions:
638 results.append(output_api.PresubmitError(
639 'You added one or more #includes that violate checkdeps rules.',
640 error_descriptions))
641 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42642 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18643 'You added one or more #includes of files that are temporarily\n'
644 'allowed but being removed. Can you avoid introducing the\n'
645 '#include? See relevant DEPS file(s) for details and contacts.',
646 warning_descriptions))
647 return results
648
649
[email protected]fbcafe5a2012-08-08 15:31:22650def _CheckFilePermissions(input_api, output_api):
651 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15652 if input_api.platform == 'win32':
653 return []
mohan.reddyf21db962014-10-16 12:26:47654 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
655 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22656 for f in input_api.AffectedFiles():
657 args += ['--file', f.LocalPath()]
[email protected]f0d330f2014-01-30 01:44:34658 checkperms = input_api.subprocess.Popen(args,
659 stdout=input_api.subprocess.PIPE)
660 errors = checkperms.communicate()[0].strip()
[email protected]fbcafe5a2012-08-08 15:31:22661 if errors:
[email protected]f0d330f2014-01-30 01:44:34662 return [output_api.PresubmitError('checkperms.py failed.',
663 errors.splitlines())]
664 return []
[email protected]fbcafe5a2012-08-08 15:31:22665
666
[email protected]c8278b32012-10-30 20:35:49667def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
668 """Makes sure we don't include ui/aura/window_property.h
669 in header files.
670 """
671 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
672 errors = []
673 for f in input_api.AffectedFiles():
674 if not f.LocalPath().endswith('.h'):
675 continue
676 for line_num, line in f.ChangedContents():
677 if pattern.match(line):
678 errors.append(' %s:%d' % (f.LocalPath(), line_num))
679
680 results = []
681 if errors:
682 results.append(output_api.PresubmitError(
683 'Header files should not include ui/aura/window_property.h', errors))
684 return results
685
686
[email protected]cf9b78f2012-11-14 11:40:28687def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
688 """Checks that the lines in scope occur in the right order.
689
690 1. C system files in alphabetical order
691 2. C++ system files in alphabetical order
692 3. Project's .h files
693 """
694
695 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
696 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
697 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
698
699 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
700
701 state = C_SYSTEM_INCLUDES
702
703 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57704 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28705 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55706 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28707 for line_num, line in scope:
708 if c_system_include_pattern.match(line):
709 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55710 problem_linenums.append((line_num, previous_line_num,
711 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28712 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55713 problem_linenums.append((line_num, previous_line_num,
714 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28715 elif cpp_system_include_pattern.match(line):
716 if state == C_SYSTEM_INCLUDES:
717 state = CPP_SYSTEM_INCLUDES
718 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55719 problem_linenums.append((line_num, previous_line_num,
720 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28721 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55722 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28723 elif custom_include_pattern.match(line):
724 if state != CUSTOM_INCLUDES:
725 state = CUSTOM_INCLUDES
726 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55727 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28728 else:
brucedawson70fadb02015-06-30 17:47:55729 problem_linenums.append((line_num, previous_line_num,
730 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28731 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57732 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28733
734 warnings = []
brucedawson70fadb02015-06-30 17:47:55735 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57736 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55737 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28738 return warnings
739
740
[email protected]ac294a12012-12-06 16:38:43741def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28742 """Checks the #include order for the given file f."""
743
[email protected]2299dcf2012-11-15 19:56:24744 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30745 # Exclude the following includes from the check:
746 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
747 # specific order.
748 # 2) <atlbase.h>, "build/build_config.h"
749 excluded_include_pattern = input_api.re.compile(
750 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24751 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33752 # Match the final or penultimate token if it is xxxtest so we can ignore it
753 # when considering the special first include.
754 test_file_tag_pattern = input_api.re.compile(
755 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11756 if_pattern = input_api.re.compile(
757 r'\s*#\s*(if|elif|else|endif|define|undef).*')
758 # Some files need specialized order of includes; exclude such files from this
759 # check.
760 uncheckable_includes_pattern = input_api.re.compile(
761 r'\s*#include '
762 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28763
764 contents = f.NewContents()
765 warnings = []
766 line_num = 0
767
[email protected]ac294a12012-12-06 16:38:43768 # Handle the special first include. If the first include file is
769 # some/path/file.h, the corresponding including file can be some/path/file.cc,
770 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
771 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33772 # If the included file is some/path/file_platform.h the including file could
773 # also be some/path/file_xxxtest_platform.h.
774 including_file_base_name = test_file_tag_pattern.sub(
775 '', input_api.os_path.basename(f.LocalPath()))
776
[email protected]ac294a12012-12-06 16:38:43777 for line in contents:
778 line_num += 1
779 if system_include_pattern.match(line):
780 # No special first include -> process the line again along with normal
781 # includes.
782 line_num -= 1
783 break
784 match = custom_include_pattern.match(line)
785 if match:
786 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33787 header_basename = test_file_tag_pattern.sub(
788 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
789
790 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24791 # No special first include -> process the line again along with normal
792 # includes.
793 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43794 break
[email protected]cf9b78f2012-11-14 11:40:28795
796 # Split into scopes: Each region between #if and #endif is its own scope.
797 scopes = []
798 current_scope = []
799 for line in contents[line_num:]:
800 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11801 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54802 continue
[email protected]2309b0fa02012-11-16 12:18:27803 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28804 scopes.append(current_scope)
805 current_scope = []
[email protected]962f117e2012-11-22 18:11:56806 elif ((system_include_pattern.match(line) or
807 custom_include_pattern.match(line)) and
808 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28809 current_scope.append((line_num, line))
810 scopes.append(current_scope)
811
812 for scope in scopes:
813 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
814 changed_linenums))
815 return warnings
816
817
818def _CheckIncludeOrder(input_api, output_api):
819 """Checks that the #include order is correct.
820
821 1. The corresponding header for source files.
822 2. C system files in alphabetical order
823 3. C++ system files in alphabetical order
824 4. Project's .h files in alphabetical order
825
[email protected]ac294a12012-12-06 16:38:43826 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
827 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28828 """
[email protected]e120b012014-08-15 19:08:35829 def FileFilterIncludeOrder(affected_file):
830 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
831 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28832
833 warnings = []
[email protected]e120b012014-08-15 19:08:35834 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08835 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43836 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
837 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28838
839 results = []
840 if warnings:
[email protected]f7051d52013-04-02 18:31:42841 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53842 warnings))
[email protected]cf9b78f2012-11-14 11:40:28843 return results
844
845
[email protected]70ca77752012-11-20 03:45:03846def _CheckForVersionControlConflictsInFile(input_api, f):
847 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
848 errors = []
849 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23850 if f.LocalPath().endswith('.md'):
851 # First-level headers in markdown look a lot like version control
852 # conflict markers. http://daringfireball.net/projects/markdown/basics
853 continue
[email protected]70ca77752012-11-20 03:45:03854 if pattern.match(line):
855 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
856 return errors
857
858
859def _CheckForVersionControlConflicts(input_api, output_api):
860 """Usually this is not intentional and will cause a compile failure."""
861 errors = []
862 for f in input_api.AffectedFiles():
863 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
864
865 results = []
866 if errors:
867 results.append(output_api.PresubmitError(
868 'Version control conflict markers found, please resolve.', errors))
869 return results
870
871
[email protected]06e6d0ff2012-12-11 01:36:44872def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
873 def FilterFile(affected_file):
874 """Filter function for use with input_api.AffectedSourceFiles,
875 below. This filters out everything except non-test files from
876 top-level directories that generally speaking should not hard-code
877 service URLs (e.g. src/android_webview/, src/content/ and others).
878 """
879 return input_api.FilterSourceFile(
880 affected_file,
[email protected]78bb39d62012-12-11 15:11:56881 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44882 black_list=(_EXCLUDED_PATHS +
883 _TEST_CODE_EXCLUDED_PATHS +
884 input_api.DEFAULT_BLACK_LIST))
885
[email protected]de4f7d22013-05-23 14:27:46886 base_pattern = '"[^"]*google\.com[^"]*"'
887 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
888 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44889 problems = [] # items are (filename, line_number, line)
890 for f in input_api.AffectedSourceFiles(FilterFile):
891 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46892 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44893 problems.append((f.LocalPath(), line_num, line))
894
895 if problems:
[email protected]f7051d52013-04-02 18:31:42896 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44897 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58898 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44899 [' %s:%d: %s' % (
900 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03901 else:
902 return []
[email protected]06e6d0ff2012-12-11 01:36:44903
904
[email protected]d2530012013-01-25 16:39:27905def _CheckNoAbbreviationInPngFileName(input_api, output_api):
906 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31907 The native_client_sdk directory is excluded because it has auto-generated PNG
908 files for documentation.
[email protected]d2530012013-01-25 16:39:27909 """
[email protected]d2530012013-01-25 16:39:27910 errors = []
binji0dcdf342014-12-12 18:32:31911 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
912 black_list = (r'^native_client_sdk[\\\/]',)
913 file_filter = lambda f: input_api.FilterSourceFile(
914 f, white_list=white_list, black_list=black_list)
915 for f in input_api.AffectedFiles(include_deletes=False,
916 file_filter=file_filter):
917 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27918
919 results = []
920 if errors:
921 results.append(output_api.PresubmitError(
922 'The name of PNG files should not have abbreviations. \n'
923 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
924 'Contact [email protected] if you have questions.', errors))
925 return results
926
927
[email protected]14a6131c2014-01-08 01:15:41928def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08929 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41930 a set of DEPS entries that we should look up.
931
932 For a directory (rather than a specific filename) we fake a path to
933 a specific filename by adding /DEPS. This is chosen as a file that
934 will seldom or never be subject to per-file include_rules.
935 """
[email protected]2b438d62013-11-14 17:54:14936 # We ignore deps entries on auto-generated directories.
937 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08938
939 # This pattern grabs the path without basename in the first
940 # parentheses, and the basename (if present) in the second. It
941 # relies on the simple heuristic that if there is a basename it will
942 # be a header file ending in ".h".
943 pattern = re.compile(
944 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14945 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08946 for changed_line in changed_lines:
947 m = pattern.match(changed_line)
948 if m:
949 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14950 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41951 if m.group(2):
952 results.add('%s%s' % (path, m.group(2)))
953 else:
954 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08955 return results
956
957
[email protected]e871964c2013-05-13 14:14:55958def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
959 """When a dependency prefixed with + is added to a DEPS file, we
960 want to make sure that the change is reviewed by an OWNER of the
961 target file or directory, to avoid layering violations from being
962 introduced. This check verifies that this happens.
963 """
964 changed_lines = set()
965 for f in input_api.AffectedFiles():
966 filename = input_api.os_path.basename(f.LocalPath())
967 if filename == 'DEPS':
968 changed_lines |= set(line.strip()
969 for line_num, line
970 in f.ChangedContents())
971 if not changed_lines:
972 return []
973
[email protected]14a6131c2014-01-08 01:15:41974 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
975 changed_lines)
[email protected]e871964c2013-05-13 14:14:55976 if not virtual_depended_on_files:
977 return []
978
979 if input_api.is_committing:
980 if input_api.tbr:
981 return [output_api.PresubmitNotifyResult(
982 '--tbr was specified, skipping OWNERS check for DEPS additions')]
983 if not input_api.change.issue:
984 return [output_api.PresubmitError(
985 "DEPS approval by OWNERS check failed: this change has "
986 "no Rietveld issue number, so we can't check it for approvals.")]
987 output = output_api.PresubmitError
988 else:
989 output = output_api.PresubmitNotifyResult
990
991 owners_db = input_api.owners_db
992 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
993 input_api,
994 owners_db.email_regexp,
995 approval_needed=input_api.is_committing)
996
997 owner_email = owner_email or input_api.change.author_email
998
[email protected]de4f7d22013-05-23 14:27:46999 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511000 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461001 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551002 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1003 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411004
1005 # We strip the /DEPS part that was added by
1006 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1007 # directory.
1008 def StripDeps(path):
1009 start_deps = path.rfind('/DEPS')
1010 if start_deps != -1:
1011 return path[:start_deps]
1012 else:
1013 return path
1014 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551015 for path in missing_files]
1016
1017 if unapproved_dependencies:
1018 output_list = [
[email protected]14a6131c2014-01-08 01:15:411019 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551020 '\n '.join(sorted(unapproved_dependencies)))]
1021 if not input_api.is_committing:
1022 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1023 output_list.append(output(
1024 'Suggested missing target path OWNERS:\n %s' %
1025 '\n '.join(suggested_owners or [])))
1026 return output_list
1027
1028 return []
1029
1030
[email protected]85218562013-11-22 07:41:401031def _CheckSpamLogging(input_api, output_api):
1032 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1033 black_list = (_EXCLUDED_PATHS +
1034 _TEST_CODE_EXCLUDED_PATHS +
1035 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501036 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191037 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481038 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461039 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121040 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1041 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581042 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161043 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031044 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151045 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1046 r"^chromecast[\\\/]",
1047 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311048 r"^components[\\\/]html_viewer[\\\/]"
1049 r"web_test_delegate_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251050 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1051 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111052 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151053 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111054 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521055 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501056 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361057 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311058 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131059 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441060 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021061 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441062 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401063 source_file_filter = lambda x: input_api.FilterSourceFile(
1064 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1065
1066 log_info = []
1067 printf = []
1068
1069 for f in input_api.AffectedSourceFiles(source_file_filter):
1070 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471071 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401072 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471073 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131074 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371075
mohan.reddyf21db962014-10-16 12:26:471076 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371077 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471078 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401079 printf.append(f.LocalPath())
1080
1081 if log_info:
1082 return [output_api.PresubmitError(
1083 'These files spam the console log with LOG(INFO):',
1084 items=log_info)]
1085 if printf:
1086 return [output_api.PresubmitError(
1087 'These files spam the console log with printf/fprintf:',
1088 items=printf)]
1089 return []
1090
1091
[email protected]49aa76a2013-12-04 06:59:161092def _CheckForAnonymousVariables(input_api, output_api):
1093 """These types are all expected to hold locks while in scope and
1094 so should never be anonymous (which causes them to be immediately
1095 destroyed)."""
1096 they_who_must_be_named = [
1097 'base::AutoLock',
1098 'base::AutoReset',
1099 'base::AutoUnlock',
1100 'SkAutoAlphaRestore',
1101 'SkAutoBitmapShaderInstall',
1102 'SkAutoBlitterChoose',
1103 'SkAutoBounderCommit',
1104 'SkAutoCallProc',
1105 'SkAutoCanvasRestore',
1106 'SkAutoCommentBlock',
1107 'SkAutoDescriptor',
1108 'SkAutoDisableDirectionCheck',
1109 'SkAutoDisableOvalCheck',
1110 'SkAutoFree',
1111 'SkAutoGlyphCache',
1112 'SkAutoHDC',
1113 'SkAutoLockColors',
1114 'SkAutoLockPixels',
1115 'SkAutoMalloc',
1116 'SkAutoMaskFreeImage',
1117 'SkAutoMutexAcquire',
1118 'SkAutoPathBoundsUpdate',
1119 'SkAutoPDFRelease',
1120 'SkAutoRasterClipValidate',
1121 'SkAutoRef',
1122 'SkAutoTime',
1123 'SkAutoTrace',
1124 'SkAutoUnref',
1125 ]
1126 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1127 # bad: base::AutoLock(lock.get());
1128 # not bad: base::AutoLock lock(lock.get());
1129 bad_pattern = input_api.re.compile(anonymous)
1130 # good: new base::AutoLock(lock.get())
1131 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1132 errors = []
1133
1134 for f in input_api.AffectedFiles():
1135 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1136 continue
1137 for linenum, line in f.ChangedContents():
1138 if bad_pattern.search(line) and not good_pattern.search(line):
1139 errors.append('%s:%d' % (f.LocalPath(), linenum))
1140
1141 if errors:
1142 return [output_api.PresubmitError(
1143 'These lines create anonymous variables that need to be named:',
1144 items=errors)]
1145 return []
1146
1147
[email protected]5fe0f8742013-11-29 01:04:591148def _CheckCygwinShell(input_api, output_api):
1149 source_file_filter = lambda x: input_api.FilterSourceFile(
1150 x, white_list=(r'.+\.(gyp|gypi)$',))
1151 cygwin_shell = []
1152
1153 for f in input_api.AffectedSourceFiles(source_file_filter):
1154 for linenum, line in f.ChangedContents():
1155 if 'msvs_cygwin_shell' in line:
1156 cygwin_shell.append(f.LocalPath())
1157 break
1158
1159 if cygwin_shell:
1160 return [output_api.PresubmitError(
1161 'These files should not use msvs_cygwin_shell (the default is 0):',
1162 items=cygwin_shell)]
1163 return []
1164
[email protected]85218562013-11-22 07:41:401165
[email protected]999261d2014-03-03 20:08:081166def _CheckUserActionUpdate(input_api, output_api):
1167 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521168 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081169 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521170 # If actions.xml is already included in the changelist, the PRESUBMIT
1171 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081172 return []
1173
[email protected]999261d2014-03-03 20:08:081174 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1175 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521176 current_actions = None
[email protected]999261d2014-03-03 20:08:081177 for f in input_api.AffectedFiles(file_filter=file_filter):
1178 for line_num, line in f.ChangedContents():
1179 match = input_api.re.search(action_re, line)
1180 if match:
[email protected]2f92dec2014-03-07 19:21:521181 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1182 # loaded only once.
1183 if not current_actions:
1184 with open('tools/metrics/actions/actions.xml') as actions_f:
1185 current_actions = actions_f.read()
1186 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081187 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521188 action = 'name="{0}"'.format(action_name)
1189 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081190 return [output_api.PresubmitPromptWarning(
1191 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521192 'tools/metrics/actions/actions.xml. Please run '
1193 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081194 % (f.LocalPath(), line_num, action_name))]
1195 return []
1196
1197
[email protected]99171a92014-06-03 08:44:471198def _GetJSONParseError(input_api, filename, eat_comments=True):
1199 try:
1200 contents = input_api.ReadFile(filename)
1201 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131202 import sys
1203 original_sys_path = sys.path
1204 try:
1205 sys.path = sys.path + [input_api.os_path.join(
1206 input_api.PresubmitLocalPath(),
1207 'tools', 'json_comment_eater')]
1208 import json_comment_eater
1209 finally:
1210 sys.path = original_sys_path
1211 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471212
1213 input_api.json.loads(contents)
1214 except ValueError as e:
1215 return e
1216 return None
1217
1218
1219def _GetIDLParseError(input_api, filename):
1220 try:
1221 contents = input_api.ReadFile(filename)
1222 idl_schema = input_api.os_path.join(
1223 input_api.PresubmitLocalPath(),
1224 'tools', 'json_schema_compiler', 'idl_schema.py')
1225 process = input_api.subprocess.Popen(
1226 [input_api.python_executable, idl_schema],
1227 stdin=input_api.subprocess.PIPE,
1228 stdout=input_api.subprocess.PIPE,
1229 stderr=input_api.subprocess.PIPE,
1230 universal_newlines=True)
1231 (_, error) = process.communicate(input=contents)
1232 return error or None
1233 except ValueError as e:
1234 return e
1235
1236
1237def _CheckParseErrors(input_api, output_api):
1238 """Check that IDL and JSON files do not contain syntax errors."""
1239 actions = {
1240 '.idl': _GetIDLParseError,
1241 '.json': _GetJSONParseError,
1242 }
1243 # These paths contain test data and other known invalid JSON files.
1244 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491245 r'test[\\\/]data[\\\/]',
1246 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471247 ]
1248 # Most JSON files are preprocessed and support comments, but these do not.
1249 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491250 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471251 ]
1252 # Only run IDL checker on files in these directories.
1253 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491254 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1255 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471256 ]
1257
1258 def get_action(affected_file):
1259 filename = affected_file.LocalPath()
1260 return actions.get(input_api.os_path.splitext(filename)[1])
1261
1262 def MatchesFile(patterns, path):
1263 for pattern in patterns:
1264 if input_api.re.search(pattern, path):
1265 return True
1266 return False
1267
1268 def FilterFile(affected_file):
1269 action = get_action(affected_file)
1270 if not action:
1271 return False
1272 path = affected_file.LocalPath()
1273
1274 if MatchesFile(excluded_patterns, path):
1275 return False
1276
1277 if (action == _GetIDLParseError and
1278 not MatchesFile(idl_included_patterns, path)):
1279 return False
1280 return True
1281
1282 results = []
1283 for affected_file in input_api.AffectedFiles(
1284 file_filter=FilterFile, include_deletes=False):
1285 action = get_action(affected_file)
1286 kwargs = {}
1287 if (action == _GetJSONParseError and
1288 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1289 kwargs['eat_comments'] = False
1290 parse_error = action(input_api,
1291 affected_file.AbsoluteLocalPath(),
1292 **kwargs)
1293 if parse_error:
1294 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1295 (affected_file.LocalPath(), parse_error)))
1296 return results
1297
1298
[email protected]760deea2013-12-10 19:33:491299def _CheckJavaStyle(input_api, output_api):
1300 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471301 import sys
[email protected]760deea2013-12-10 19:33:491302 original_sys_path = sys.path
1303 try:
1304 sys.path = sys.path + [input_api.os_path.join(
1305 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1306 import checkstyle
1307 finally:
1308 # Restore sys.path to what it was before.
1309 sys.path = original_sys_path
1310
1311 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091312 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511313 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491314
1315
dskiba88634f4e2015-08-14 23:03:291316def _CheckAndroidToastUsage(input_api, output_api):
1317 """Checks that code uses org.chromium.ui.widget.Toast instead of
1318 android.widget.Toast (Chromium Toast doesn't force hardware
1319 acceleration on low-end devices, saving memory).
1320 """
1321 toast_import_pattern = input_api.re.compile(
1322 r'^import android\.widget\.Toast;$')
1323
1324 errors = []
1325
1326 sources = lambda affected_file: input_api.FilterSourceFile(
1327 affected_file,
1328 black_list=(_EXCLUDED_PATHS +
1329 _TEST_CODE_EXCLUDED_PATHS +
1330 input_api.DEFAULT_BLACK_LIST +
1331 (r'^chromecast[\\\/].*',
1332 r'^remoting[\\\/].*')),
1333 white_list=(r'.*\.java$',))
1334
1335 for f in input_api.AffectedSourceFiles(sources):
1336 for line_num, line in f.ChangedContents():
1337 if toast_import_pattern.search(line):
1338 errors.append("%s:%d" % (f.LocalPath(), line_num))
1339
1340 results = []
1341
1342 if errors:
1343 results.append(output_api.PresubmitError(
1344 'android.widget.Toast usage is detected. Android toasts use hardware'
1345 ' acceleration, and can be\ncostly on low-end devices. Please use'
1346 ' org.chromium.ui.widget.Toast instead.\n'
1347 'Contact [email protected] if you have any questions.',
1348 errors))
1349
1350 return results
1351
1352
dgnaa68d5e2015-06-10 10:08:221353def _CheckAndroidCrLogUsage(input_api, output_api):
1354 """Checks that new logs using org.chromium.base.Log:
1355 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511356 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221357 """
1358 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121359 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1360 class_in_base_pattern = input_api.re.compile(
1361 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1362 has_some_log_import_pattern = input_api.re.compile(
1363 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221364 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121365 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221366 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511367 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221368 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221369
Vincent Scheib16d7b272015-09-15 18:09:071370 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221371 'or contact [email protected] for more info.')
1372 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121373
dgnaa68d5e2015-06-10 10:08:221374 tag_decl_errors = []
1375 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121376 tag_errors = []
dgn38736db2015-09-18 19:20:511377 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121378 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221379
1380 for f in input_api.AffectedSourceFiles(sources):
1381 file_content = input_api.ReadFile(f)
1382 has_modified_logs = False
1383
1384 # Per line checks
dgn87d9fb62015-06-12 09:15:121385 if (cr_log_import_pattern.search(file_content) or
1386 (class_in_base_pattern.search(file_content) and
1387 not has_some_log_import_pattern.search(file_content))):
1388 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221389 for line_num, line in f.ChangedContents():
1390
1391 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121392 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221393 if match:
1394 has_modified_logs = True
1395
1396 # Make sure it uses "TAG"
1397 if not match.group('tag') == 'TAG':
1398 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121399 else:
1400 # Report non cr Log function calls in changed lines
1401 for line_num, line in f.ChangedContents():
1402 if log_call_pattern.search(line):
1403 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221404
1405 # Per file checks
1406 if has_modified_logs:
1407 # Make sure the tag is using the "cr" prefix and is not too long
1408 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511409 tag_name = match.group('name') if match else None
1410 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221411 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511412 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221413 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511414 elif '.' in tag_name:
1415 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221416
1417 results = []
1418 if tag_decl_errors:
1419 results.append(output_api.PresubmitPromptWarning(
1420 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511421 '"private static final String TAG = "<package tag>".\n'
1422 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221423 tag_decl_errors))
1424
1425 if tag_length_errors:
1426 results.append(output_api.PresubmitError(
1427 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511428 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221429 tag_length_errors))
1430
1431 if tag_errors:
1432 results.append(output_api.PresubmitPromptWarning(
1433 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1434 tag_errors))
1435
dgn87d9fb62015-06-12 09:15:121436 if util_log_errors:
dgn4401aa52015-04-29 16:26:171437 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121438 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1439 util_log_errors))
1440
dgn38736db2015-09-18 19:20:511441 if tag_with_dot_errors:
1442 results.append(output_api.PresubmitPromptWarning(
1443 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1444 tag_with_dot_errors))
1445
dgn4401aa52015-04-29 16:26:171446 return results
1447
1448
mnaganov9b9b1fe82014-12-11 16:30:361449def _CheckForCopyrightedCode(input_api, output_api):
1450 """Verifies that newly added code doesn't contain copyrighted material
1451 and is properly licensed under the standard Chromium license.
1452
1453 As there can be false positives, we maintain a whitelist file. This check
1454 also verifies that the whitelist file is up to date.
1455 """
1456 import sys
1457 original_sys_path = sys.path
1458 try:
1459 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221460 input_api.PresubmitLocalPath(), 'tools')]
1461 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361462 finally:
1463 # Restore sys.path to what it was before.
1464 sys.path = original_sys_path
1465
1466 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1467
1468
glidere61efad2015-02-18 17:39:431469def _CheckSingletonInHeaders(input_api, output_api):
1470 """Checks to make sure no header files have |Singleton<|."""
1471 def FileFilter(affected_file):
1472 # It's ok for base/memory/singleton.h to have |Singleton<|.
1473 black_list = (_EXCLUDED_PATHS +
1474 input_api.DEFAULT_BLACK_LIST +
1475 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1476 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1477
sergeyu34d21222015-09-16 00:11:441478 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431479 files = []
1480 for f in input_api.AffectedSourceFiles(FileFilter):
1481 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1482 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1483 contents = input_api.ReadFile(f)
1484 for line in contents.splitlines(False):
1485 if (not input_api.re.match(r'//', line) and # Strip C++ comment.
1486 pattern.search(line)):
1487 files.append(f)
1488 break
1489
1490 if files:
1491 return [ output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441492 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431493 'Please move them to an appropriate source file so that the ' +
1494 'template gets instantiated in a single compilation unit.',
1495 files) ]
1496 return []
1497
1498
[email protected]fd20b902014-05-09 02:14:531499_DEPRECATED_CSS = [
1500 # Values
1501 ( "-webkit-box", "flex" ),
1502 ( "-webkit-inline-box", "inline-flex" ),
1503 ( "-webkit-flex", "flex" ),
1504 ( "-webkit-inline-flex", "inline-flex" ),
1505 ( "-webkit-min-content", "min-content" ),
1506 ( "-webkit-max-content", "max-content" ),
1507
1508 # Properties
1509 ( "-webkit-background-clip", "background-clip" ),
1510 ( "-webkit-background-origin", "background-origin" ),
1511 ( "-webkit-background-size", "background-size" ),
1512 ( "-webkit-box-shadow", "box-shadow" ),
1513
1514 # Functions
1515 ( "-webkit-gradient", "gradient" ),
1516 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1517 ( "-webkit-linear-gradient", "linear-gradient" ),
1518 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1519 ( "-webkit-radial-gradient", "radial-gradient" ),
1520 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1521]
1522
1523def _CheckNoDeprecatedCSS(input_api, output_api):
1524 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251525 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341526 documentation and iOS CSS for dom distiller
1527 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251528 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531529 results = []
dbeam070cfe62014-10-22 06:44:021530 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251531 black_list = (_EXCLUDED_PATHS +
1532 _TEST_CODE_EXCLUDED_PATHS +
1533 input_api.DEFAULT_BLACK_LIST +
1534 (r"^chrome/common/extensions/docs",
1535 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341536 r"^components/dom_distiller/core/css/distilledpage_ios.css",
[email protected]9a48e3f82014-05-22 00:06:251537 r"^native_client_sdk"))
1538 file_filter = lambda f: input_api.FilterSourceFile(
1539 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531540 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1541 for line_num, line in fpath.ChangedContents():
1542 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021543 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531544 results.append(output_api.PresubmitError(
1545 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1546 (fpath.LocalPath(), line_num, deprecated_value, value)))
1547 return results
1548
mohan.reddyf21db962014-10-16 12:26:471549
dbeam070cfe62014-10-22 06:44:021550_DEPRECATED_JS = [
1551 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1552 ( "__defineGetter__", "Object.defineProperty" ),
1553 ( "__defineSetter__", "Object.defineProperty" ),
1554]
1555
1556def _CheckNoDeprecatedJS(input_api, output_api):
1557 """Make sure that we don't use deprecated JS in Chrome code."""
1558 results = []
1559 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1560 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1561 input_api.DEFAULT_BLACK_LIST)
1562 file_filter = lambda f: input_api.FilterSourceFile(
1563 f, white_list=file_inclusion_pattern, black_list=black_list)
1564 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1565 for lnum, line in fpath.ChangedContents():
1566 for (deprecated, replacement) in _DEPRECATED_JS:
1567 if deprecated in line:
1568 results.append(output_api.PresubmitError(
1569 "%s:%d: Use of deprecated JS %s, use %s instead" %
1570 (fpath.LocalPath(), lnum, deprecated, replacement)))
1571 return results
1572
1573
dgnaa68d5e2015-06-10 10:08:221574def _AndroidSpecificOnUploadChecks(input_api, output_api):
1575 """Groups checks that target android code."""
1576 results = []
dgnaa68d5e2015-06-10 10:08:221577 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291578 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221579 return results
1580
1581
[email protected]22c9bd72011-03-27 16:47:391582def _CommonChecks(input_api, output_api):
1583 """Checks common to both upload and commit."""
1584 results = []
1585 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381586 input_api, output_api,
1587 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461588 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191589 results.extend(
[email protected]760deea2013-12-10 19:33:491590 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541591 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181592 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221593 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441594 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591595 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061596 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121597 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181598 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221599 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491600 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271601 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031602 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491603 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441604 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271605 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541606 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441607 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461608 # TODO(danakj): Remove this when base/move.h is removed.
1609 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551610 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041611 results.extend(
1612 input_api.canned_checks.CheckChangeHasNoTabs(
1613 input_api,
1614 output_api,
1615 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401616 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161617 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591618 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081619 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531620 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021621 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471622 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041623 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361624 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231625 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431626 results.extend(_CheckSingletonInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241627
1628 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1629 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1630 input_api, output_api,
1631 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381632 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391633 return results
[email protected]1f7b4172010-01-28 01:17:341634
[email protected]b337cb5b2011-01-23 21:24:051635
[email protected]66daa702011-05-28 14:41:461636def _CheckAuthorizedAuthor(input_api, output_api):
1637 """For non-googler/chromites committers, verify the author's email address is
1638 in AUTHORS.
1639 """
[email protected]9bb9cb82011-06-13 20:43:011640 # TODO(maruel): Add it to input_api?
1641 import fnmatch
1642
[email protected]66daa702011-05-28 14:41:461643 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011644 if not author:
1645 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461646 return []
[email protected]c99663292011-05-31 19:46:081647 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461648 input_api.PresubmitLocalPath(), 'AUTHORS')
1649 valid_authors = (
1650 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1651 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181652 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441653 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231654 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461655 return [output_api.PresubmitPromptWarning(
1656 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1657 '\n'
1658 'http://www.chromium.org/developers/contributing-code and read the '
1659 '"Legal" section\n'
1660 'If you are a chromite, verify the contributor signed the CLA.') %
1661 author)]
1662 return []
1663
1664
[email protected]b8079ae4a2012-12-05 19:56:491665def _CheckPatchFiles(input_api, output_api):
1666 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1667 if f.LocalPath().endswith(('.orig', '.rej'))]
1668 if problems:
1669 return [output_api.PresubmitError(
1670 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031671 else:
1672 return []
[email protected]b8079ae4a2012-12-05 19:56:491673
1674
[email protected]b00342e7f2013-03-26 16:21:541675def _DidYouMeanOSMacro(bad_macro):
1676 try:
1677 return {'A': 'OS_ANDROID',
1678 'B': 'OS_BSD',
1679 'C': 'OS_CHROMEOS',
1680 'F': 'OS_FREEBSD',
1681 'L': 'OS_LINUX',
1682 'M': 'OS_MACOSX',
1683 'N': 'OS_NACL',
1684 'O': 'OS_OPENBSD',
1685 'P': 'OS_POSIX',
1686 'S': 'OS_SOLARIS',
1687 'W': 'OS_WIN'}[bad_macro[3].upper()]
1688 except KeyError:
1689 return ''
1690
1691
1692def _CheckForInvalidOSMacrosInFile(input_api, f):
1693 """Check for sensible looking, totally invalid OS macros."""
1694 preprocessor_statement = input_api.re.compile(r'^\s*#')
1695 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1696 results = []
1697 for lnum, line in f.ChangedContents():
1698 if preprocessor_statement.search(line):
1699 for match in os_macro.finditer(line):
1700 if not match.group(1) in _VALID_OS_MACROS:
1701 good = _DidYouMeanOSMacro(match.group(1))
1702 did_you_mean = ' (did you mean %s?)' % good if good else ''
1703 results.append(' %s:%d %s%s' % (f.LocalPath(),
1704 lnum,
1705 match.group(1),
1706 did_you_mean))
1707 return results
1708
1709
1710def _CheckForInvalidOSMacros(input_api, output_api):
1711 """Check all affected files for invalid OS macros."""
1712 bad_macros = []
1713 for f in input_api.AffectedFiles():
1714 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1715 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1716
1717 if not bad_macros:
1718 return []
1719
1720 return [output_api.PresubmitError(
1721 'Possibly invalid OS macro[s] found. Please fix your code\n'
1722 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1723
lliabraa35bab3932014-10-01 12:16:441724
1725def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1726 """Check all affected files for invalid "if defined" macros."""
1727 ALWAYS_DEFINED_MACROS = (
1728 "TARGET_CPU_PPC",
1729 "TARGET_CPU_PPC64",
1730 "TARGET_CPU_68K",
1731 "TARGET_CPU_X86",
1732 "TARGET_CPU_ARM",
1733 "TARGET_CPU_MIPS",
1734 "TARGET_CPU_SPARC",
1735 "TARGET_CPU_ALPHA",
1736 "TARGET_IPHONE_SIMULATOR",
1737 "TARGET_OS_EMBEDDED",
1738 "TARGET_OS_IPHONE",
1739 "TARGET_OS_MAC",
1740 "TARGET_OS_UNIX",
1741 "TARGET_OS_WIN32",
1742 )
1743 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1744 results = []
1745 for lnum, line in f.ChangedContents():
1746 for match in ifdef_macro.finditer(line):
1747 if match.group(1) in ALWAYS_DEFINED_MACROS:
1748 always_defined = ' %s is always defined. ' % match.group(1)
1749 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1750 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1751 lnum,
1752 always_defined,
1753 did_you_mean))
1754 return results
1755
1756
1757def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1758 """Check all affected files for invalid "if defined" macros."""
1759 bad_macros = []
1760 for f in input_api.AffectedFiles():
1761 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1762 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1763
1764 if not bad_macros:
1765 return []
1766
1767 return [output_api.PresubmitError(
1768 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1769 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1770 bad_macros)]
1771
1772
danakj3c84d0c2014-10-06 15:35:461773def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1774 """Check all affected files for using side effects of Pass."""
1775 errors = []
1776 for f in input_api.AffectedFiles():
1777 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1778 for lnum, line in f.ChangedContents():
1779 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471780 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461781 errors.append(output_api.PresubmitError(
1782 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1783 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1784 return errors
1785
1786
mlamouria82272622014-09-16 18:45:041787def _CheckForIPCRules(input_api, output_api):
1788 """Check for same IPC rules described in
1789 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1790 """
1791 base_pattern = r'IPC_ENUM_TRAITS\('
1792 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1793 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1794
1795 problems = []
1796 for f in input_api.AffectedSourceFiles(None):
1797 local_path = f.LocalPath()
1798 if not local_path.endswith('.h'):
1799 continue
1800 for line_number, line in f.ChangedContents():
1801 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1802 problems.append(
1803 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1804
1805 if problems:
1806 return [output_api.PresubmitPromptWarning(
1807 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1808 else:
1809 return []
1810
[email protected]b00342e7f2013-03-26 16:21:541811
mostynbb639aca52015-01-07 20:31:231812def _CheckForWindowsLineEndings(input_api, output_api):
1813 """Check source code and known ascii text files for Windows style line
1814 endings.
1815 """
earthdok1b5e0ee2015-03-10 15:19:101816 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231817
1818 file_inclusion_pattern = (
1819 known_text_files,
1820 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1821 )
1822
1823 filter = lambda f: input_api.FilterSourceFile(
1824 f, white_list=file_inclusion_pattern, black_list=None)
1825 files = [f.LocalPath() for f in
1826 input_api.AffectedSourceFiles(filter)]
1827
1828 problems = []
1829
1830 for file in files:
1831 fp = open(file, 'r')
1832 for line in fp:
1833 if line.endswith('\r\n'):
1834 problems.append(file)
1835 break
1836 fp.close()
1837
1838 if problems:
1839 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1840 'these files to contain Windows style line endings?\n' +
1841 '\n'.join(problems))]
1842
1843 return []
1844
1845
[email protected]1f7b4172010-01-28 01:17:341846def CheckChangeOnUpload(input_api, output_api):
1847 results = []
1848 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471849 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171850 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281851 results.extend(
1852 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191853 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221854 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541855 return results
[email protected]ca8d19842009-02-19 16:33:121856
1857
[email protected]1bfb8322014-04-23 01:02:411858def GetTryServerMasterForBot(bot):
1859 """Returns the Try Server master for the given bot.
1860
[email protected]0bb112362014-07-26 04:38:321861 It tries to guess the master from the bot name, but may still fail
1862 and return None. There is no longer a default master.
1863 """
1864 # Potentially ambiguous bot names are listed explicitly.
1865 master_map = {
[email protected]0bb112362014-07-26 04:38:321866 'chromium_presubmit': 'tryserver.chromium.linux',
1867 'blink_presubmit': 'tryserver.chromium.linux',
1868 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411869 }
[email protected]0bb112362014-07-26 04:38:321870 master = master_map.get(bot)
1871 if not master:
sergiyb37fd293f2015-02-26 06:55:011872 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321873 master = 'tryserver.chromium.linux'
1874 elif 'win' in bot:
1875 master = 'tryserver.chromium.win'
1876 elif 'mac' in bot or 'ios' in bot:
1877 master = 'tryserver.chromium.mac'
1878 return master
[email protected]1bfb8322014-04-23 01:02:411879
1880
Paweł Hajdan, Jr55083782014-12-19 20:32:561881def GetDefaultTryConfigs(bots):
1882 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011883 """
1884
Paweł Hajdan, Jr55083782014-12-19 20:32:561885 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411886
1887 # Build up the mapping from tryserver master to bot/test.
1888 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561889 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411890 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1891 return out
[email protected]38c6a512013-12-18 23:48:011892
1893
[email protected]ca8d19842009-02-19 16:33:121894def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541895 results = []
[email protected]1f7b4172010-01-28 01:17:341896 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:511897 # TODO(thestig) temporarily disabled, doesn't work in third_party/
1898 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
1899 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:541900 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271901 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341902 input_api,
1903 output_api,
[email protected]2fdd1f362013-01-16 03:56:031904 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271905
[email protected]3e4eb112011-01-18 03:29:541906 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1907 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411908 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1909 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541910 return results
[email protected]ca8d19842009-02-19 16:33:121911
1912
[email protected]7468ac522014-03-12 23:35:571913def GetPreferredTryMasters(project, change):
Paweł Hajdan, Jref2afd42015-01-07 15:59:521914 import json
sergiyb57a71e32015-06-03 18:44:001915 import os.path
1916 import platform
1917 import subprocess
smut3ef206e12015-03-20 09:30:001918
sergiyb57a71e32015-06-03 18:44:001919 cq_config_path = os.path.join(
1920 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
1921 # commit_queue.py below is a script in depot_tools directory, which has a
1922 # 'builders' command to retrieve a list of CQ builders from the CQ config.
1923 is_win = platform.system() == 'Windows'
1924 masters = json.loads(subprocess.check_output(
1925 ['commit_queue', 'builders', cq_config_path], shell=is_win))
[email protected]911753b2012-08-02 12:11:541926
sergiyb6092f742015-06-16 09:00:521927 try_config = {}
1928 for master in masters:
1929 try_config.setdefault(master, {})
1930 for builder in masters[master]:
sergiyb57a71e32015-06-03 18:44:001931 # Do not trigger presubmit builders, since they're likely to fail
1932 # (e.g. OWNERS checks before finished code review), and we're
1933 # running local presubmit anyway.
sergiyb6092f742015-06-16 09:00:521934 if 'presubmit' not in builder:
1935 try_config[master][builder] = ['defaulttests']
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321936
sergiyb6092f742015-06-16 09:00:521937 return try_config