blob: 8cb86fe1622e0d526043e1cfc38e9aeb41a66ad4 [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[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
vapierb2053f542017-03-09 19:46:1028 r"tools[\\\/]md_browser[\\\/].*\.css$",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d19842009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[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
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5344 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4750 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4951 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0852 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4953 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4454)
[email protected]ca8d19842009-02-19 16:33:1255
wnwenbdc444e2016-05-25 13:44:1556
[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 '
avice9a8982015-11-24 20:36:2166 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
67 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
wnwenbdc444e2016-05-25 13:44:1569
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
jif65398702016-10-27 10:19:48143 (
144 r"/\s+UTF8String\s*]",
145 (
146 'The use of -[NSString UTF8String] is dangerous as it can return null',
147 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
148 'Please use |SysNSStringToUTF8| instead.',
149 ),
150 True,
151 ),
[email protected]127f18ec2012-06-16 05:05:59152)
153
154
155_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20156 # Make sure that gtest's FRIEND_TEST() macro is not used; the
157 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30158 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20159 (
thomasandersone7caaa9b2017-03-29 19:22:53160 r'\bNULL\b',
161 (
162 'New code should not use NULL. Use nullptr instead.',
163 ),
164 True,
165 (),
166 ),
167 (
[email protected]23e6cbc2012-06-16 18:51:20168 'FRIEND_TEST(',
169 (
[email protected]e3c945502012-06-26 20:01:49170 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20171 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
172 ),
173 False,
[email protected]7345da02012-11-27 14:31:49174 (),
[email protected]23e6cbc2012-06-16 18:51:20175 ),
176 (
thomasanderson4b569052016-09-14 20:15:53177 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
178 (
179 'Chrome clients wishing to select events on X windows should use',
180 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
181 'you are selecting events from the GPU process, or if you are using',
182 'an XDisplay other than gfx::GetXDisplay().',
183 ),
184 True,
185 (
186 r"^ui[\\\/]gl[\\\/].*\.cc$",
187 r"^media[\\\/]gpu[\\\/].*\.cc$",
188 r"^gpu[\\\/].*\.cc$",
189 ),
190 ),
191 (
thomasandersone043e3ce2017-06-08 00:43:20192 r'XInternAtom|xcb_intern_atom',
193 (
thomasanderson11aa41d2017-06-08 22:22:38194 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20195 ),
196 True,
197 (
thomasanderson11aa41d2017-06-08 22:22:38198 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
199 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20200 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
201 ),
202 ),
203 (
[email protected]23e6cbc2012-06-16 18:51:20204 'ScopedAllowIO',
205 (
satoruxe1396f8a2017-06-01 06:40:39206 'New production code should not use ScopedAllowIO (using it in',
Marijn Kruisselbrink085ef092017-07-12 23:56:55207 'tests is fine). Post a task to a MayBlock task runner instead.',
[email protected]23e6cbc2012-06-16 18:51:20208 ),
[email protected]e3c945502012-06-26 20:01:49209 True,
[email protected]7345da02012-11-27 14:31:49210 (
Marijn Kruisselbrink085ef092017-07-12 23:56:55211 r"^.*(browser|unit)(|_)test[a-z_]*\.cc$",
hajimehoshi2acea432017-03-08 08:55:37212 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
rayb0088ee52017-04-26 22:35:08213 r"^base[\\\/]process[\\\/]internal_aix\.cc$",
nyad2c548b2015-12-09 03:22:32214 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10215 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22216 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
rdevlin.cronin62018a12017-06-22 17:34:06217 r"^chrome[\\\/]browser[\\\/]extensions[\\\/]" +
218 r"chrome_test_extension_loader.cc$",
sky0e07a142016-03-25 21:27:31219 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
philipj3f9d5bde2014-08-28 14:09:09220 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49221 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
222 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41223 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
224 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25225 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
miu8e0e80c2017-05-31 03:35:57226 r"^media[\\\/]cast[\\\/]test[\\\/]utility[\\\/]" +
227 r"standalone_cast_environment\.cc$",
jamesra03ae492014-10-03 04:26:48228 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
229 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01230 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25231 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
232 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
233 r"embedded_test_server\.cc$",
234 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
235 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54236 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16237 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53238 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
239 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45240 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
241 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
242 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
243 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
244 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49245 ),
[email protected]23e6cbc2012-06-16 18:51:20246 ),
[email protected]52657f62013-05-20 05:30:31247 (
tomhudsone2c14d552016-05-26 17:07:46248 'setMatrixClip',
249 (
250 'Overriding setMatrixClip() is prohibited; ',
251 'the base function is deprecated. ',
252 ),
253 True,
254 (),
255 ),
256 (
[email protected]52657f62013-05-20 05:30:31257 'SkRefPtr',
258 (
259 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22260 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31261 ),
262 True,
263 (),
264 ),
265 (
266 'SkAutoRef',
267 (
268 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22269 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31270 ),
271 True,
272 (),
273 ),
274 (
275 'SkAutoTUnref',
276 (
277 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22278 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31279 ),
280 True,
281 (),
282 ),
283 (
284 'SkAutoUnref',
285 (
286 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
287 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22288 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31289 ),
290 True,
291 (),
292 ),
[email protected]d89eec82013-12-03 14:10:59293 (
294 r'/HANDLE_EINTR\(.*close',
295 (
296 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
297 'descriptor will be closed, and it is incorrect to retry the close.',
298 'Either call close directly and ignore its return value, or wrap close',
299 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
300 ),
301 True,
302 (),
303 ),
304 (
305 r'/IGNORE_EINTR\((?!.*close)',
306 (
307 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
308 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
309 ),
310 True,
311 (
312 # Files that #define IGNORE_EINTR.
313 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
314 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
315 ),
316 ),
[email protected]ec5b3f02014-04-04 18:43:43317 (
318 r'/v8::Extension\(',
319 (
320 'Do not introduce new v8::Extensions into the code base, use',
321 'gin::Wrappable instead. See http://crbug.com/334679',
322 ),
323 True,
[email protected]f55c90ee62014-04-12 00:50:03324 (
joaodasilva718f87672014-08-30 09:25:49325 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03326 ),
[email protected]ec5b3f02014-04-04 18:43:43327 ),
skyostilf9469f72015-04-20 10:38:52328 (
jame2d1a952016-04-02 00:27:10329 '#pragma comment(lib,',
330 (
331 'Specify libraries to link with in build files and not in the source.',
332 ),
333 True,
334 (),
335 ),
fdorayc4ac18d2017-05-01 21:39:59336 (
337 'BrowserThread::GetBlockingPool',
338 (
339 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
340 'mapping between both APIs in content/public/browser/browser_thread.h.',
341 'For questions, contact base/task_scheduler/OWNERS.',
342 ),
343 True,
344 (),
345 ),
gabd52c912a2017-05-11 04:15:59346 (
Gabriel Charette664e4482017-06-13 19:55:29347 'BrowserThread::(FILE|FILE_USER_BLOCKING|DB|PROCESS_LAUNCHER|CACHE)',
348 (
349 'The non-UI/IO BrowserThreads are deprecated, please migrate this',
350 'code to TaskScheduler. See https://goo.gl/mDSxKl for details.',
351 'For questions, contact base/task_scheduler/OWNERS.',
352 ),
353 True,
354 (),
355 ),
356 (
gabd52c912a2017-05-11 04:15:59357 'base::SequenceChecker',
358 (
359 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
360 ),
361 False,
362 (),
363 ),
364 (
365 'base::ThreadChecker',
366 (
367 'Consider using THREAD_CHECKER macros instead of the class directly.',
368 ),
369 False,
370 (),
371 ),
dbeamb6f4fde2017-06-15 04:03:06372 (
373 'CallJavascriptFunctionUnsafe',
374 (
375 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
376 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
377 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
378 ),
379 False,
380 (
381 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
382 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
383 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
384 ),
385 ),
[email protected]127f18ec2012-06-16 05:05:59386)
387
wnwenbdc444e2016-05-25 13:44:15388
mlamouria82272622014-09-16 18:45:04389_IPC_ENUM_TRAITS_DEPRECATED = (
390 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
391 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
392
[email protected]127f18ec2012-06-16 05:05:59393
[email protected]b00342e7f2013-03-26 16:21:54394_VALID_OS_MACROS = (
395 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08396 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54397 'OS_ANDROID',
398 'OS_BSD',
399 'OS_CAT', # For testing.
400 'OS_CHROMEOS',
401 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37402 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54403 'OS_IOS',
404 'OS_LINUX',
405 'OS_MACOSX',
406 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21407 'OS_NACL_NONSFI',
408 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12409 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54410 'OS_OPENBSD',
411 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37412 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54413 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54414 'OS_WIN',
415)
416
417
agrievef32bcc72016-04-04 14:57:40418_ANDROID_SPECIFIC_PYDEPS_FILES = [
419 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04420 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58421 'build/secondary/third_party/android_platform/'
422 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19423 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40424]
425
wnwenbdc444e2016-05-25 13:44:15426
agrievef32bcc72016-04-04 14:57:40427_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40428]
429
wnwenbdc444e2016-05-25 13:44:15430
agrievef32bcc72016-04-04 14:57:40431_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
432
433
[email protected]55459852011-08-10 15:17:19434def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
435 """Attempts to prevent use of functions intended only for testing in
436 non-testing code. For now this is just a best-effort implementation
437 that ignores header files and may have some false positives. A
438 better implementation would probably need a proper C++ parser.
439 """
440 # We only scan .cc files and the like, as the declaration of
441 # for-testing functions in header files are hard to distinguish from
442 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44443 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19444
jochenc0d4808c2015-07-27 09:25:42445 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19446 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09447 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19448 exclusion_pattern = input_api.re.compile(
449 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
450 base_function_pattern, base_function_pattern))
451
452 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44453 black_list = (_EXCLUDED_PATHS +
454 _TEST_CODE_EXCLUDED_PATHS +
455 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19456 return input_api.FilterSourceFile(
457 affected_file,
458 white_list=(file_inclusion_pattern, ),
459 black_list=black_list)
460
461 problems = []
462 for f in input_api.AffectedSourceFiles(FilterFile):
463 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24464 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03465 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46466 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03467 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19468 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03469 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19470
471 if problems:
[email protected]f7051d52013-04-02 18:31:42472 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03473 else:
474 return []
[email protected]55459852011-08-10 15:17:19475
476
[email protected]10689ca2011-09-02 02:31:54477def _CheckNoIOStreamInHeaders(input_api, output_api):
478 """Checks to make sure no .h files include <iostream>."""
479 files = []
480 pattern = input_api.re.compile(r'^#include\s*<iostream>',
481 input_api.re.MULTILINE)
482 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
483 if not f.LocalPath().endswith('.h'):
484 continue
485 contents = input_api.ReadFile(f)
486 if pattern.search(contents):
487 files.append(f)
488
489 if len(files):
yolandyandaabc6d2016-04-18 18:29:39490 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06491 'Do not #include <iostream> in header files, since it inserts static '
492 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54493 '#include <ostream>. See http://crbug.com/94794',
494 files) ]
495 return []
496
497
[email protected]72df4e782012-06-21 16:28:18498def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52499 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18500 problems = []
501 for f in input_api.AffectedFiles():
502 if (not f.LocalPath().endswith(('.cc', '.mm'))):
503 continue
504
505 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04506 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18507 problems.append(' %s:%d' % (f.LocalPath(), line_num))
508
509 if not problems:
510 return []
511 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
512 '\n'.join(problems))]
513
514
danakj61c1aa22015-10-26 19:55:52515def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57516 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52517 errors = []
518 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
519 input_api.re.MULTILINE)
520 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
521 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
522 continue
523 for lnum, line in f.ChangedContents():
524 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17525 errors.append(output_api.PresubmitError(
526 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57527 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17528 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52529 return errors
530
531
mcasasb7440c282015-02-04 14:52:19532def _FindHistogramNameInLine(histogram_name, line):
533 """Tries to find a histogram name or prefix in a line."""
534 if not "affected-histogram" in line:
535 return histogram_name in line
536 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
537 # the histogram_name.
538 if not '"' in line:
539 return False
540 histogram_prefix = line.split('\"')[1]
541 return histogram_prefix in histogram_name
542
543
544def _CheckUmaHistogramChanges(input_api, output_api):
545 """Check that UMA histogram names in touched lines can still be found in other
546 lines of the patch or in histograms.xml. Note that this check would not catch
547 the reverse: changes in histograms.xml not matched in the code itself."""
548 touched_histograms = []
549 histograms_xml_modifications = []
550 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
551 for f in input_api.AffectedFiles():
552 # If histograms.xml itself is modified, keep the modified lines for later.
553 if f.LocalPath().endswith(('histograms.xml')):
554 histograms_xml_modifications = f.ChangedContents()
555 continue
556 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
557 continue
558 for line_num, line in f.ChangedContents():
559 found = pattern.search(line)
560 if found:
561 touched_histograms.append([found.group(1), f, line_num])
562
563 # Search for the touched histogram names in the local modifications to
564 # histograms.xml, and, if not found, on the base histograms.xml file.
565 unmatched_histograms = []
566 for histogram_info in touched_histograms:
567 histogram_name_found = False
568 for line_num, line in histograms_xml_modifications:
569 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
570 if histogram_name_found:
571 break
572 if not histogram_name_found:
573 unmatched_histograms.append(histogram_info)
574
eromanb90c82e7e32015-04-01 15:13:49575 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19576 problems = []
577 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49578 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19579 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45580 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19581 histogram_name_found = False
582 for line in histograms_xml:
583 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
584 if histogram_name_found:
585 break
586 if not histogram_name_found:
587 problems.append(' [%s:%d] %s' %
588 (f.LocalPath(), line_num, histogram_name))
589
590 if not problems:
591 return []
592 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
593 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49594 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19595
wnwenbdc444e2016-05-25 13:44:15596
yolandyandaabc6d2016-04-18 18:29:39597def _CheckFlakyTestUsage(input_api, output_api):
598 """Check that FlakyTest annotation is our own instead of the android one"""
599 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
600 files = []
601 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
602 if f.LocalPath().endswith('Test.java'):
603 if pattern.search(input_api.ReadFile(f)):
604 files.append(f)
605 if len(files):
606 return [output_api.PresubmitError(
607 'Use org.chromium.base.test.util.FlakyTest instead of '
608 'android.test.FlakyTest',
609 files)]
610 return []
mcasasb7440c282015-02-04 14:52:19611
wnwenbdc444e2016-05-25 13:44:15612
[email protected]8ea5d4b2011-09-13 21:49:22613def _CheckNoNewWStrings(input_api, output_api):
614 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27615 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22616 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20617 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57618 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34619 '/win/' in f.LocalPath() or
620 'chrome_elf' in f.LocalPath() or
621 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20622 continue
[email protected]8ea5d4b2011-09-13 21:49:22623
[email protected]a11dbe9b2012-08-07 01:32:58624 allowWString = False
[email protected]b5c24292011-11-28 14:38:20625 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58626 if 'presubmit: allow wstring' in line:
627 allowWString = True
628 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27629 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58630 allowWString = False
631 else:
632 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22633
[email protected]55463aa62011-10-12 00:48:27634 if not problems:
635 return []
636 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58637 ' If you are calling a cross-platform API that accepts a wstring, '
638 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27639 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22640
641
[email protected]2a8ac9c2011-10-19 17:20:44642def _CheckNoDEPSGIT(input_api, output_api):
643 """Make sure .DEPS.git is never modified manually."""
644 if any(f.LocalPath().endswith('.DEPS.git') for f in
645 input_api.AffectedFiles()):
646 return [output_api.PresubmitError(
647 'Never commit changes to .DEPS.git. This file is maintained by an\n'
648 'automated system based on what\'s in DEPS and your changes will be\n'
649 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34650 '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:44651 'for more information')]
652 return []
653
654
tandriief664692014-09-23 14:51:47655def _CheckValidHostsInDEPS(input_api, output_api):
656 """Checks that DEPS file deps are from allowed_hosts."""
657 # Run only if DEPS file has been modified to annoy fewer bystanders.
658 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
659 return []
660 # Outsource work to gclient verify
661 try:
662 input_api.subprocess.check_output(['gclient', 'verify'])
663 return []
664 except input_api.subprocess.CalledProcessError, error:
665 return [output_api.PresubmitError(
666 'DEPS file must have only git dependencies.',
667 long_text=error.output)]
668
669
[email protected]127f18ec2012-06-16 05:05:59670def _CheckNoBannedFunctions(input_api, output_api):
671 """Make sure that banned functions are not used."""
672 warnings = []
673 errors = []
674
wnwenbdc444e2016-05-25 13:44:15675 def IsBlacklisted(affected_file, blacklist):
676 local_path = affected_file.LocalPath()
677 for item in blacklist:
678 if input_api.re.match(item, local_path):
679 return True
680 return False
681
682 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
683 matched = False
684 if func_name[0:1] == '/':
685 regex = func_name[1:]
686 if input_api.re.search(regex, line):
687 matched = True
688 elif func_name in line:
dchenge07de812016-06-20 19:27:17689 matched = True
wnwenbdc444e2016-05-25 13:44:15690 if matched:
dchenge07de812016-06-20 19:27:17691 problems = warnings
wnwenbdc444e2016-05-25 13:44:15692 if error:
dchenge07de812016-06-20 19:27:17693 problems = errors
wnwenbdc444e2016-05-25 13:44:15694 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
695 for message_line in message:
696 problems.append(' %s' % message_line)
697
[email protected]127f18ec2012-06-16 05:05:59698 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
699 for f in input_api.AffectedFiles(file_filter=file_filter):
700 for line_num, line in f.ChangedContents():
701 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15702 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59703
704 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
705 for f in input_api.AffectedFiles(file_filter=file_filter):
706 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49707 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49708 if IsBlacklisted(f, excluded_paths):
709 continue
wnwenbdc444e2016-05-25 13:44:15710 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59711
712 result = []
713 if (warnings):
714 result.append(output_api.PresubmitPromptWarning(
715 'Banned functions were used.\n' + '\n'.join(warnings)))
716 if (errors):
717 result.append(output_api.PresubmitError(
718 'Banned functions were used.\n' + '\n'.join(errors)))
719 return result
720
721
[email protected]6c063c62012-07-11 19:11:06722def _CheckNoPragmaOnce(input_api, output_api):
723 """Make sure that banned functions are not used."""
724 files = []
725 pattern = input_api.re.compile(r'^#pragma\s+once',
726 input_api.re.MULTILINE)
727 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
728 if not f.LocalPath().endswith('.h'):
729 continue
730 contents = input_api.ReadFile(f)
731 if pattern.search(contents):
732 files.append(f)
733
734 if files:
735 return [output_api.PresubmitError(
736 'Do not use #pragma once in header files.\n'
737 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
738 files)]
739 return []
740
[email protected]127f18ec2012-06-16 05:05:59741
[email protected]e7479052012-09-19 00:26:12742def _CheckNoTrinaryTrueFalse(input_api, output_api):
743 """Checks to make sure we don't introduce use of foo ? true : false."""
744 problems = []
745 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
746 for f in input_api.AffectedFiles():
747 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
748 continue
749
750 for line_num, line in f.ChangedContents():
751 if pattern.match(line):
752 problems.append(' %s:%d' % (f.LocalPath(), line_num))
753
754 if not problems:
755 return []
756 return [output_api.PresubmitPromptWarning(
757 'Please consider avoiding the "? true : false" pattern if possible.\n' +
758 '\n'.join(problems))]
759
760
[email protected]55f9f382012-07-31 11:02:18761def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28762 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18763 change. Breaking - rules is an error, breaking ! rules is a
764 warning.
765 """
mohan.reddyf21db962014-10-16 12:26:47766 import sys
[email protected]55f9f382012-07-31 11:02:18767 # We need to wait until we have an input_api object and use this
768 # roundabout construct to import checkdeps because this file is
769 # eval-ed and thus doesn't have __file__.
770 original_sys_path = sys.path
771 try:
772 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47773 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18774 import checkdeps
775 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28776 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18777 from rules import Rule
778 finally:
779 # Restore sys.path to what it was before.
780 sys.path = original_sys_path
781
782 added_includes = []
rhalavati08acd232017-04-03 07:23:28783 added_imports = []
[email protected]55f9f382012-07-31 11:02:18784 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28785 if CppChecker.IsCppFile(f.LocalPath()):
786 changed_lines = [line for line_num, line in f.ChangedContents()]
787 added_includes.append([f.LocalPath(), changed_lines])
788 elif ProtoChecker.IsProtoFile(f.LocalPath()):
789 changed_lines = [line for line_num, line in f.ChangedContents()]
790 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18791
[email protected]26385172013-05-09 23:11:35792 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18793
794 error_descriptions = []
795 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28796 error_subjects = set()
797 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18798 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
799 added_includes):
800 description_with_path = '%s\n %s' % (path, rule_description)
801 if rule_type == Rule.DISALLOW:
802 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28803 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18804 else:
805 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28806 warning_subjects.add("#includes")
807
808 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
809 added_imports):
810 description_with_path = '%s\n %s' % (path, rule_description)
811 if rule_type == Rule.DISALLOW:
812 error_descriptions.append(description_with_path)
813 error_subjects.add("imports")
814 else:
815 warning_descriptions.append(description_with_path)
816 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18817
818 results = []
819 if error_descriptions:
820 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28821 'You added one or more %s that violate checkdeps rules.'
822 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18823 error_descriptions))
824 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42825 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28826 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18827 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28828 '%s? See relevant DEPS file(s) for details and contacts.' %
829 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18830 warning_descriptions))
831 return results
832
833
[email protected]fbcafe5a2012-08-08 15:31:22834def _CheckFilePermissions(input_api, output_api):
835 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15836 if input_api.platform == 'win32':
837 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29838 checkperms_tool = input_api.os_path.join(
839 input_api.PresubmitLocalPath(),
840 'tools', 'checkperms', 'checkperms.py')
841 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47842 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22843 for f in input_api.AffectedFiles():
844 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11845 try:
846 input_api.subprocess.check_output(args)
847 return []
848 except input_api.subprocess.CalledProcessError as error:
849 return [output_api.PresubmitError(
850 'checkperms.py failed:',
851 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22852
853
robertocn832f5992017-01-04 19:01:30854def _CheckTeamTags(input_api, output_api):
855 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
856 checkteamtags_tool = input_api.os_path.join(
857 input_api.PresubmitLocalPath(),
858 'tools', 'checkteamtags', 'checkteamtags.py')
859 args = [input_api.python_executable, checkteamtags_tool,
860 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22861 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30862 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
863 'OWNERS']
864 try:
865 if files:
866 input_api.subprocess.check_output(args + files)
867 return []
868 except input_api.subprocess.CalledProcessError as error:
869 return [output_api.PresubmitError(
870 'checkteamtags.py failed:',
871 long_text=error.output)]
872
873
[email protected]c8278b32012-10-30 20:35:49874def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
875 """Makes sure we don't include ui/aura/window_property.h
876 in header files.
877 """
878 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
879 errors = []
880 for f in input_api.AffectedFiles():
881 if not f.LocalPath().endswith('.h'):
882 continue
883 for line_num, line in f.ChangedContents():
884 if pattern.match(line):
885 errors.append(' %s:%d' % (f.LocalPath(), line_num))
886
887 results = []
888 if errors:
889 results.append(output_api.PresubmitError(
890 'Header files should not include ui/aura/window_property.h', errors))
891 return results
892
893
[email protected]70ca77752012-11-20 03:45:03894def _CheckForVersionControlConflictsInFile(input_api, f):
895 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
896 errors = []
897 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23898 if f.LocalPath().endswith('.md'):
899 # First-level headers in markdown look a lot like version control
900 # conflict markers. http://daringfireball.net/projects/markdown/basics
901 continue
[email protected]70ca77752012-11-20 03:45:03902 if pattern.match(line):
903 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
904 return errors
905
906
907def _CheckForVersionControlConflicts(input_api, output_api):
908 """Usually this is not intentional and will cause a compile failure."""
909 errors = []
910 for f in input_api.AffectedFiles():
911 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
912
913 results = []
914 if errors:
915 results.append(output_api.PresubmitError(
916 'Version control conflict markers found, please resolve.', errors))
917 return results
918
estadee17314a02017-01-12 16:22:16919def _CheckGoogleSupportAnswerUrl(input_api, output_api):
920 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
921 errors = []
922 for f in input_api.AffectedFiles():
923 for line_num, line in f.ChangedContents():
924 if pattern.search(line):
925 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
926
927 results = []
928 if errors:
929 results.append(output_api.PresubmitPromptWarning(
930 'Found Google support URL addressed by answer number. Please replace with '
931 'a p= identifier instead. See crbug.com/679462\n', errors))
932 return results
933
[email protected]70ca77752012-11-20 03:45:03934
[email protected]06e6d0ff2012-12-11 01:36:44935def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
936 def FilterFile(affected_file):
937 """Filter function for use with input_api.AffectedSourceFiles,
938 below. This filters out everything except non-test files from
939 top-level directories that generally speaking should not hard-code
940 service URLs (e.g. src/android_webview/, src/content/ and others).
941 """
942 return input_api.FilterSourceFile(
943 affected_file,
[email protected]78bb39d62012-12-11 15:11:56944 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44945 black_list=(_EXCLUDED_PATHS +
946 _TEST_CODE_EXCLUDED_PATHS +
947 input_api.DEFAULT_BLACK_LIST))
948
reillyi38965732015-11-16 18:27:33949 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
950 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46951 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
952 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44953 problems = [] # items are (filename, line_number, line)
954 for f in input_api.AffectedSourceFiles(FilterFile):
955 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46956 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44957 problems.append((f.LocalPath(), line_num, line))
958
959 if problems:
[email protected]f7051d52013-04-02 18:31:42960 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44961 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58962 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44963 [' %s:%d: %s' % (
964 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03965 else:
966 return []
[email protected]06e6d0ff2012-12-11 01:36:44967
968
[email protected]d2530012013-01-25 16:39:27969def _CheckNoAbbreviationInPngFileName(input_api, output_api):
970 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31971 The native_client_sdk directory is excluded because it has auto-generated PNG
972 files for documentation.
[email protected]d2530012013-01-25 16:39:27973 """
[email protected]d2530012013-01-25 16:39:27974 errors = []
binji0dcdf342014-12-12 18:32:31975 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
976 black_list = (r'^native_client_sdk[\\\/]',)
977 file_filter = lambda f: input_api.FilterSourceFile(
978 f, white_list=white_list, black_list=black_list)
979 for f in input_api.AffectedFiles(include_deletes=False,
980 file_filter=file_filter):
981 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27982
983 results = []
984 if errors:
985 results.append(output_api.PresubmitError(
986 'The name of PNG files should not have abbreviations. \n'
987 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
988 'Contact [email protected] if you have questions.', errors))
989 return results
990
991
Daniel Cheng4dcdb6b2017-04-13 08:30:17992def _ExtractAddRulesFromParsedDeps(parsed_deps):
993 """Extract the rules that add dependencies from a parsed DEPS file.
994
995 Args:
996 parsed_deps: the locals dictionary from evaluating the DEPS file."""
997 add_rules = set()
998 add_rules.update([
999 rule[1:] for rule in parsed_deps.get('include_rules', [])
1000 if rule.startswith('+') or rule.startswith('!')
1001 ])
1002 for specific_file, rules in parsed_deps.get('specific_include_rules',
1003 {}).iteritems():
1004 add_rules.update([
1005 rule[1:] for rule in rules
1006 if rule.startswith('+') or rule.startswith('!')
1007 ])
1008 return add_rules
1009
1010
1011def _ParseDeps(contents):
1012 """Simple helper for parsing DEPS files."""
1013 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171014 class _VarImpl:
1015
1016 def __init__(self, local_scope):
1017 self._local_scope = local_scope
1018
1019 def Lookup(self, var_name):
1020 """Implements the Var syntax."""
1021 try:
1022 return self._local_scope['vars'][var_name]
1023 except KeyError:
1024 raise Exception('Var is not defined: %s' % var_name)
1025
1026 local_scope = {}
1027 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171028 'Var': _VarImpl(local_scope).Lookup,
1029 }
1030 exec contents in global_scope, local_scope
1031 return local_scope
1032
1033
1034def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081035 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411036 a set of DEPS entries that we should look up.
1037
1038 For a directory (rather than a specific filename) we fake a path to
1039 a specific filename by adding /DEPS. This is chosen as a file that
1040 will seldom or never be subject to per-file include_rules.
1041 """
[email protected]2b438d62013-11-14 17:54:141042 # We ignore deps entries on auto-generated directories.
1043 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081044
Daniel Cheng4dcdb6b2017-04-13 08:30:171045 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1046 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1047
1048 added_deps = new_deps.difference(old_deps)
1049
[email protected]2b438d62013-11-14 17:54:141050 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171051 for added_dep in added_deps:
1052 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1053 continue
1054 # Assume that a rule that ends in .h is a rule for a specific file.
1055 if added_dep.endswith('.h'):
1056 results.add(added_dep)
1057 else:
1058 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081059 return results
1060
1061
[email protected]e871964c2013-05-13 14:14:551062def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1063 """When a dependency prefixed with + is added to a DEPS file, we
1064 want to make sure that the change is reviewed by an OWNER of the
1065 target file or directory, to avoid layering violations from being
1066 introduced. This check verifies that this happens.
1067 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171068 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241069
1070 file_filter = lambda f: not input_api.re.match(
1071 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1072 for f in input_api.AffectedFiles(include_deletes=False,
1073 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551074 filename = input_api.os_path.basename(f.LocalPath())
1075 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171076 virtual_depended_on_files.update(_CalculateAddedDeps(
1077 input_api.os_path,
1078 '\n'.join(f.OldContents()),
1079 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551080
[email protected]e871964c2013-05-13 14:14:551081 if not virtual_depended_on_files:
1082 return []
1083
1084 if input_api.is_committing:
1085 if input_api.tbr:
1086 return [output_api.PresubmitNotifyResult(
1087 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271088 if input_api.dry_run:
1089 return [output_api.PresubmitNotifyResult(
1090 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551091 if not input_api.change.issue:
1092 return [output_api.PresubmitError(
1093 "DEPS approval by OWNERS check failed: this change has "
1094 "no Rietveld issue number, so we can't check it for approvals.")]
1095 output = output_api.PresubmitError
1096 else:
1097 output = output_api.PresubmitNotifyResult
1098
1099 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501100 owner_email, reviewers = (
1101 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1102 input_api,
1103 owners_db.email_regexp,
1104 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551105
1106 owner_email = owner_email or input_api.change.author_email
1107
[email protected]de4f7d22013-05-23 14:27:461108 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511109 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461110 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551111 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1112 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411113
1114 # We strip the /DEPS part that was added by
1115 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1116 # directory.
1117 def StripDeps(path):
1118 start_deps = path.rfind('/DEPS')
1119 if start_deps != -1:
1120 return path[:start_deps]
1121 else:
1122 return path
1123 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551124 for path in missing_files]
1125
1126 if unapproved_dependencies:
1127 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151128 output('You need LGTM from owners of depends-on paths in DEPS that were '
1129 'modified in this CL:\n %s' %
1130 '\n '.join(sorted(unapproved_dependencies)))]
1131 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1132 output_list.append(output(
1133 'Suggested missing target path OWNERS:\n %s' %
1134 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551135 return output_list
1136
1137 return []
1138
1139
[email protected]85218562013-11-22 07:41:401140def _CheckSpamLogging(input_api, output_api):
1141 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1142 black_list = (_EXCLUDED_PATHS +
1143 _TEST_CODE_EXCLUDED_PATHS +
1144 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501145 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191146 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481147 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461148 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121149 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1150 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581151 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161152 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031153 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151154 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1155 r"^chromecast[\\\/]",
1156 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481157 r"^components[\\\/]browser_watcher[\\\/]"
1158 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311159 r"^components[\\\/]html_viewer[\\\/]"
1160 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461161 # TODO(peter): Remove this exception. https://crbug.com/534537
1162 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1163 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251164 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1165 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241166 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111167 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151168 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111169 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521170 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501171 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361172 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311173 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131174 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001175 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441176 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451177 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021178 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351179 r"dump_file_system.cc$",
1180 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401181 source_file_filter = lambda x: input_api.FilterSourceFile(
1182 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1183
thomasanderson625d3932017-03-29 07:16:581184 log_info = set([])
1185 printf = set([])
[email protected]85218562013-11-22 07:41:401186
1187 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581188 for _, line in f.ChangedContents():
1189 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1190 log_info.add(f.LocalPath())
1191 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1192 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371193
thomasanderson625d3932017-03-29 07:16:581194 if input_api.re.search(r"\bprintf\(", line):
1195 printf.add(f.LocalPath())
1196 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1197 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401198
1199 if log_info:
1200 return [output_api.PresubmitError(
1201 'These files spam the console log with LOG(INFO):',
1202 items=log_info)]
1203 if printf:
1204 return [output_api.PresubmitError(
1205 'These files spam the console log with printf/fprintf:',
1206 items=printf)]
1207 return []
1208
1209
[email protected]49aa76a2013-12-04 06:59:161210def _CheckForAnonymousVariables(input_api, output_api):
1211 """These types are all expected to hold locks while in scope and
1212 so should never be anonymous (which causes them to be immediately
1213 destroyed)."""
1214 they_who_must_be_named = [
1215 'base::AutoLock',
1216 'base::AutoReset',
1217 'base::AutoUnlock',
1218 'SkAutoAlphaRestore',
1219 'SkAutoBitmapShaderInstall',
1220 'SkAutoBlitterChoose',
1221 'SkAutoBounderCommit',
1222 'SkAutoCallProc',
1223 'SkAutoCanvasRestore',
1224 'SkAutoCommentBlock',
1225 'SkAutoDescriptor',
1226 'SkAutoDisableDirectionCheck',
1227 'SkAutoDisableOvalCheck',
1228 'SkAutoFree',
1229 'SkAutoGlyphCache',
1230 'SkAutoHDC',
1231 'SkAutoLockColors',
1232 'SkAutoLockPixels',
1233 'SkAutoMalloc',
1234 'SkAutoMaskFreeImage',
1235 'SkAutoMutexAcquire',
1236 'SkAutoPathBoundsUpdate',
1237 'SkAutoPDFRelease',
1238 'SkAutoRasterClipValidate',
1239 'SkAutoRef',
1240 'SkAutoTime',
1241 'SkAutoTrace',
1242 'SkAutoUnref',
1243 ]
1244 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1245 # bad: base::AutoLock(lock.get());
1246 # not bad: base::AutoLock lock(lock.get());
1247 bad_pattern = input_api.re.compile(anonymous)
1248 # good: new base::AutoLock(lock.get())
1249 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1250 errors = []
1251
1252 for f in input_api.AffectedFiles():
1253 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1254 continue
1255 for linenum, line in f.ChangedContents():
1256 if bad_pattern.search(line) and not good_pattern.search(line):
1257 errors.append('%s:%d' % (f.LocalPath(), linenum))
1258
1259 if errors:
1260 return [output_api.PresubmitError(
1261 'These lines create anonymous variables that need to be named:',
1262 items=errors)]
1263 return []
1264
1265
[email protected]999261d2014-03-03 20:08:081266def _CheckUserActionUpdate(input_api, output_api):
1267 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521268 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081269 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521270 # If actions.xml is already included in the changelist, the PRESUBMIT
1271 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081272 return []
1273
[email protected]999261d2014-03-03 20:08:081274 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1275 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521276 current_actions = None
[email protected]999261d2014-03-03 20:08:081277 for f in input_api.AffectedFiles(file_filter=file_filter):
1278 for line_num, line in f.ChangedContents():
1279 match = input_api.re.search(action_re, line)
1280 if match:
[email protected]2f92dec2014-03-07 19:21:521281 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1282 # loaded only once.
1283 if not current_actions:
1284 with open('tools/metrics/actions/actions.xml') as actions_f:
1285 current_actions = actions_f.read()
1286 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081287 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521288 action = 'name="{0}"'.format(action_name)
1289 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081290 return [output_api.PresubmitPromptWarning(
1291 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521292 'tools/metrics/actions/actions.xml. Please run '
1293 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081294 % (f.LocalPath(), line_num, action_name))]
1295 return []
1296
1297
[email protected]99171a92014-06-03 08:44:471298def _GetJSONParseError(input_api, filename, eat_comments=True):
1299 try:
1300 contents = input_api.ReadFile(filename)
1301 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131302 import sys
1303 original_sys_path = sys.path
1304 try:
1305 sys.path = sys.path + [input_api.os_path.join(
1306 input_api.PresubmitLocalPath(),
1307 'tools', 'json_comment_eater')]
1308 import json_comment_eater
1309 finally:
1310 sys.path = original_sys_path
1311 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471312
1313 input_api.json.loads(contents)
1314 except ValueError as e:
1315 return e
1316 return None
1317
1318
1319def _GetIDLParseError(input_api, filename):
1320 try:
1321 contents = input_api.ReadFile(filename)
1322 idl_schema = input_api.os_path.join(
1323 input_api.PresubmitLocalPath(),
1324 'tools', 'json_schema_compiler', 'idl_schema.py')
1325 process = input_api.subprocess.Popen(
1326 [input_api.python_executable, idl_schema],
1327 stdin=input_api.subprocess.PIPE,
1328 stdout=input_api.subprocess.PIPE,
1329 stderr=input_api.subprocess.PIPE,
1330 universal_newlines=True)
1331 (_, error) = process.communicate(input=contents)
1332 return error or None
1333 except ValueError as e:
1334 return e
1335
1336
1337def _CheckParseErrors(input_api, output_api):
1338 """Check that IDL and JSON files do not contain syntax errors."""
1339 actions = {
1340 '.idl': _GetIDLParseError,
1341 '.json': _GetJSONParseError,
1342 }
1343 # These paths contain test data and other known invalid JSON files.
1344 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491345 r'test[\\\/]data[\\\/]',
1346 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471347 ]
1348 # Most JSON files are preprocessed and support comments, but these do not.
1349 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491350 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471351 ]
1352 # Only run IDL checker on files in these directories.
1353 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491354 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1355 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471356 ]
1357
1358 def get_action(affected_file):
1359 filename = affected_file.LocalPath()
1360 return actions.get(input_api.os_path.splitext(filename)[1])
1361
1362 def MatchesFile(patterns, path):
1363 for pattern in patterns:
1364 if input_api.re.search(pattern, path):
1365 return True
1366 return False
1367
1368 def FilterFile(affected_file):
1369 action = get_action(affected_file)
1370 if not action:
1371 return False
1372 path = affected_file.LocalPath()
1373
1374 if MatchesFile(excluded_patterns, path):
1375 return False
1376
1377 if (action == _GetIDLParseError and
1378 not MatchesFile(idl_included_patterns, path)):
1379 return False
1380 return True
1381
1382 results = []
1383 for affected_file in input_api.AffectedFiles(
1384 file_filter=FilterFile, include_deletes=False):
1385 action = get_action(affected_file)
1386 kwargs = {}
1387 if (action == _GetJSONParseError and
1388 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1389 kwargs['eat_comments'] = False
1390 parse_error = action(input_api,
1391 affected_file.AbsoluteLocalPath(),
1392 **kwargs)
1393 if parse_error:
1394 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1395 (affected_file.LocalPath(), parse_error)))
1396 return results
1397
1398
[email protected]760deea2013-12-10 19:33:491399def _CheckJavaStyle(input_api, output_api):
1400 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471401 import sys
[email protected]760deea2013-12-10 19:33:491402 original_sys_path = sys.path
1403 try:
1404 sys.path = sys.path + [input_api.os_path.join(
1405 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1406 import checkstyle
1407 finally:
1408 # Restore sys.path to what it was before.
1409 sys.path = original_sys_path
1410
1411 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091412 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511413 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491414
1415
dchenge07de812016-06-20 19:27:171416def _CheckIpcOwners(input_api, output_api):
1417 """Checks that affected files involving IPC have an IPC OWNERS rule.
1418
1419 Whether or not a file affects IPC is determined by a simple whitelist of
1420 filename patterns."""
1421 file_patterns = [
palmerb19a0932017-01-24 04:00:311422 # Legacy IPC:
dchenge07de812016-06-20 19:27:171423 '*_messages.cc',
1424 '*_messages*.h',
1425 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311426 # Mojo IPC:
dchenge07de812016-06-20 19:27:171427 '*.mojom',
1428 '*_struct_traits*.*',
1429 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311430 '*.typemap',
1431 # Android native IPC:
1432 '*.aidl',
1433 # Blink uses a different file naming convention:
1434 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171435 '*StructTraits*.*',
1436 '*TypeConverter*.*',
1437 ]
1438
scottmg7a6ed5ba2016-11-04 18:22:041439 # These third_party directories do not contain IPCs, but contain files
1440 # matching the above patterns, which trigger false positives.
1441 exclude_paths = [
1442 'third_party/crashpad/*',
1443 ]
1444
dchenge07de812016-06-20 19:27:171445 # Dictionary mapping an OWNERS file path to Patterns.
1446 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1447 # rules ) to a PatternEntry.
1448 # PatternEntry is a dictionary with two keys:
1449 # - 'files': the files that are matched by this pattern
1450 # - 'rules': the per-file rules needed for this pattern
1451 # For example, if we expect OWNERS file to contain rules for *.mojom and
1452 # *_struct_traits*.*, Patterns might look like this:
1453 # {
1454 # '*.mojom': {
1455 # 'files': ...,
1456 # 'rules': [
1457 # 'per-file *.mojom=set noparent',
1458 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1459 # ],
1460 # },
1461 # '*_struct_traits*.*': {
1462 # 'files': ...,
1463 # 'rules': [
1464 # 'per-file *_struct_traits*.*=set noparent',
1465 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1466 # ],
1467 # },
1468 # }
1469 to_check = {}
1470
1471 # Iterate through the affected files to see what we actually need to check
1472 # for. We should only nag patch authors about per-file rules if a file in that
1473 # directory would match that pattern. If a directory only contains *.mojom
1474 # files and no *_messages*.h files, we should only nag about rules for
1475 # *.mojom files.
rockot51249332016-06-23 16:32:251476 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171477 for pattern in file_patterns:
1478 if input_api.fnmatch.fnmatch(
1479 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041480 skip = False
1481 for exclude in exclude_paths:
1482 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1483 skip = True
1484 break
1485 if skip:
1486 continue
dchenge07de812016-06-20 19:27:171487 owners_file = input_api.os_path.join(
1488 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1489 if owners_file not in to_check:
1490 to_check[owners_file] = {}
1491 if pattern not in to_check[owners_file]:
1492 to_check[owners_file][pattern] = {
1493 'files': [],
1494 'rules': [
1495 'per-file %s=set noparent' % pattern,
1496 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1497 ]
1498 }
1499 to_check[owners_file][pattern]['files'].append(f)
1500 break
1501
1502 # Now go through the OWNERS files we collected, filtering out rules that are
1503 # already present in that OWNERS file.
1504 for owners_file, patterns in to_check.iteritems():
1505 try:
1506 with file(owners_file) as f:
1507 lines = set(f.read().splitlines())
1508 for entry in patterns.itervalues():
1509 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1510 ]
1511 except IOError:
1512 # No OWNERS file, so all the rules are definitely missing.
1513 continue
1514
1515 # All the remaining lines weren't found in OWNERS files, so emit an error.
1516 errors = []
1517 for owners_file, patterns in to_check.iteritems():
1518 missing_lines = []
1519 files = []
1520 for pattern, entry in patterns.iteritems():
1521 missing_lines.extend(entry['rules'])
1522 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1523 if missing_lines:
1524 errors.append(
Daniel Cheng52111692017-06-14 08:00:591525 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171526 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1527
1528 results = []
1529 if errors:
vabrf5ce3bf92016-07-11 14:52:411530 if input_api.is_committing:
1531 output = output_api.PresubmitError
1532 else:
1533 output = output_api.PresubmitPromptWarning
1534 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591535 'Found OWNERS files that need to be updated for IPC security ' +
1536 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171537 long_text='\n\n'.join(errors)))
1538
1539 return results
1540
1541
jbriance9e12f162016-11-25 07:57:501542def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311543 """Checks that added or removed lines in non third party affected
1544 header files do not lead to new useless class or struct forward
1545 declaration.
jbriance9e12f162016-11-25 07:57:501546 """
1547 results = []
1548 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1549 input_api.re.MULTILINE)
1550 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1551 input_api.re.MULTILINE)
1552 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311553 if (f.LocalPath().startswith('third_party') and
1554 not f.LocalPath().startswith('third_party/WebKit') and
1555 not f.LocalPath().startswith('third_party\\WebKit')):
1556 continue
1557
jbriance9e12f162016-11-25 07:57:501558 if not f.LocalPath().endswith('.h'):
1559 continue
1560
1561 contents = input_api.ReadFile(f)
1562 fwd_decls = input_api.re.findall(class_pattern, contents)
1563 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1564
1565 useless_fwd_decls = []
1566 for decl in fwd_decls:
1567 count = sum(1 for _ in input_api.re.finditer(
1568 r'\b%s\b' % input_api.re.escape(decl), contents))
1569 if count == 1:
1570 useless_fwd_decls.append(decl)
1571
1572 if not useless_fwd_decls:
1573 continue
1574
1575 for line in f.GenerateScmDiff().splitlines():
1576 if (line.startswith('-') and not line.startswith('--') or
1577 line.startswith('+') and not line.startswith('++')):
1578 for decl in useless_fwd_decls:
1579 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1580 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241581 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501582 (f.LocalPath(), decl)))
1583 useless_fwd_decls.remove(decl)
1584
1585 return results
1586
1587
dskiba88634f4e2015-08-14 23:03:291588def _CheckAndroidToastUsage(input_api, output_api):
1589 """Checks that code uses org.chromium.ui.widget.Toast instead of
1590 android.widget.Toast (Chromium Toast doesn't force hardware
1591 acceleration on low-end devices, saving memory).
1592 """
1593 toast_import_pattern = input_api.re.compile(
1594 r'^import android\.widget\.Toast;$')
1595
1596 errors = []
1597
1598 sources = lambda affected_file: input_api.FilterSourceFile(
1599 affected_file,
1600 black_list=(_EXCLUDED_PATHS +
1601 _TEST_CODE_EXCLUDED_PATHS +
1602 input_api.DEFAULT_BLACK_LIST +
1603 (r'^chromecast[\\\/].*',
1604 r'^remoting[\\\/].*')),
1605 white_list=(r'.*\.java$',))
1606
1607 for f in input_api.AffectedSourceFiles(sources):
1608 for line_num, line in f.ChangedContents():
1609 if toast_import_pattern.search(line):
1610 errors.append("%s:%d" % (f.LocalPath(), line_num))
1611
1612 results = []
1613
1614 if errors:
1615 results.append(output_api.PresubmitError(
1616 'android.widget.Toast usage is detected. Android toasts use hardware'
1617 ' acceleration, and can be\ncostly on low-end devices. Please use'
1618 ' org.chromium.ui.widget.Toast instead.\n'
1619 'Contact [email protected] if you have any questions.',
1620 errors))
1621
1622 return results
1623
1624
dgnaa68d5e2015-06-10 10:08:221625def _CheckAndroidCrLogUsage(input_api, output_api):
1626 """Checks that new logs using org.chromium.base.Log:
1627 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511628 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221629 """
pkotwicza1dd0b002016-05-16 14:41:041630
torne89540622017-03-24 19:41:301631 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041632 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301633 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041634 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301635 # WebView license viewer code cannot depend on //base; used in stub APK.
1636 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1637 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041638 ]
1639
dgnaa68d5e2015-06-10 10:08:221640 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121641 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1642 class_in_base_pattern = input_api.re.compile(
1643 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1644 has_some_log_import_pattern = input_api.re.compile(
1645 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221646 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121647 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221648 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511649 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221650 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221651
Vincent Scheib16d7b272015-09-15 18:09:071652 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221653 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041654 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1655 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121656
dgnaa68d5e2015-06-10 10:08:221657 tag_decl_errors = []
1658 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121659 tag_errors = []
dgn38736db2015-09-18 19:20:511660 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121661 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221662
1663 for f in input_api.AffectedSourceFiles(sources):
1664 file_content = input_api.ReadFile(f)
1665 has_modified_logs = False
1666
1667 # Per line checks
dgn87d9fb62015-06-12 09:15:121668 if (cr_log_import_pattern.search(file_content) or
1669 (class_in_base_pattern.search(file_content) and
1670 not has_some_log_import_pattern.search(file_content))):
1671 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221672 for line_num, line in f.ChangedContents():
1673
1674 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121675 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221676 if match:
1677 has_modified_logs = True
1678
1679 # Make sure it uses "TAG"
1680 if not match.group('tag') == 'TAG':
1681 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121682 else:
1683 # Report non cr Log function calls in changed lines
1684 for line_num, line in f.ChangedContents():
1685 if log_call_pattern.search(line):
1686 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221687
1688 # Per file checks
1689 if has_modified_logs:
1690 # Make sure the tag is using the "cr" prefix and is not too long
1691 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511692 tag_name = match.group('name') if match else None
1693 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221694 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511695 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221696 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511697 elif '.' in tag_name:
1698 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221699
1700 results = []
1701 if tag_decl_errors:
1702 results.append(output_api.PresubmitPromptWarning(
1703 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511704 '"private static final String TAG = "<package tag>".\n'
1705 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221706 tag_decl_errors))
1707
1708 if tag_length_errors:
1709 results.append(output_api.PresubmitError(
1710 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511711 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221712 tag_length_errors))
1713
1714 if tag_errors:
1715 results.append(output_api.PresubmitPromptWarning(
1716 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1717 tag_errors))
1718
dgn87d9fb62015-06-12 09:15:121719 if util_log_errors:
dgn4401aa52015-04-29 16:26:171720 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121721 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1722 util_log_errors))
1723
dgn38736db2015-09-18 19:20:511724 if tag_with_dot_errors:
1725 results.append(output_api.PresubmitPromptWarning(
1726 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1727 tag_with_dot_errors))
1728
dgn4401aa52015-04-29 16:26:171729 return results
1730
1731
yolandyan45001472016-12-21 21:12:421732def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1733 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1734 deprecated_annotation_import_pattern = input_api.re.compile(
1735 r'^import android\.test\.suitebuilder\.annotation\..*;',
1736 input_api.re.MULTILINE)
1737 sources = lambda x: input_api.FilterSourceFile(
1738 x, white_list=(r'.*\.java$',), black_list=None)
1739 errors = []
1740 for f in input_api.AffectedFiles(sources):
1741 for line_num, line in f.ChangedContents():
1742 if deprecated_annotation_import_pattern.search(line):
1743 errors.append("%s:%d" % (f.LocalPath(), line_num))
1744
1745 results = []
1746 if errors:
1747 results.append(output_api.PresubmitError(
1748 'Annotations in android.test.suitebuilder.annotation have been'
1749 ' deprecated since API level 24. Please use android.support.test.filters'
1750 ' from //third_party/android_support_test_runner:runner_java instead.'
1751 ' Contact [email protected] if you have any questions.', errors))
1752 return results
1753
1754
agrieve7b6479d82015-10-07 14:24:221755def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1756 """Checks if MDPI assets are placed in a correct directory."""
1757 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1758 ('/res/drawable/' in f.LocalPath() or
1759 '/res/drawable-ldrtl/' in f.LocalPath()))
1760 errors = []
1761 for f in input_api.AffectedFiles(include_deletes=False,
1762 file_filter=file_filter):
1763 errors.append(' %s' % f.LocalPath())
1764
1765 results = []
1766 if errors:
1767 results.append(output_api.PresubmitError(
1768 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1769 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1770 '/res/drawable-ldrtl/.\n'
1771 'Contact [email protected] if you have questions.', errors))
1772 return results
1773
1774
agrievef32bcc72016-04-04 14:57:401775class PydepsChecker(object):
1776 def __init__(self, input_api, pydeps_files):
1777 self._file_cache = {}
1778 self._input_api = input_api
1779 self._pydeps_files = pydeps_files
1780
1781 def _LoadFile(self, path):
1782 """Returns the list of paths within a .pydeps file relative to //."""
1783 if path not in self._file_cache:
1784 with open(path) as f:
1785 self._file_cache[path] = f.read()
1786 return self._file_cache[path]
1787
1788 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1789 """Returns an interable of paths within the .pydep, relativized to //."""
1790 os_path = self._input_api.os_path
1791 pydeps_dir = os_path.dirname(pydeps_path)
1792 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1793 if not l.startswith('*'))
1794 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1795
1796 def _CreateFilesToPydepsMap(self):
1797 """Returns a map of local_path -> list_of_pydeps."""
1798 ret = {}
1799 for pydep_local_path in self._pydeps_files:
1800 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1801 ret.setdefault(path, []).append(pydep_local_path)
1802 return ret
1803
1804 def ComputeAffectedPydeps(self):
1805 """Returns an iterable of .pydeps files that might need regenerating."""
1806 affected_pydeps = set()
1807 file_to_pydeps_map = None
1808 for f in self._input_api.AffectedFiles(include_deletes=True):
1809 local_path = f.LocalPath()
1810 if local_path == 'DEPS':
1811 return self._pydeps_files
1812 elif local_path.endswith('.pydeps'):
1813 if local_path in self._pydeps_files:
1814 affected_pydeps.add(local_path)
1815 elif local_path.endswith('.py'):
1816 if file_to_pydeps_map is None:
1817 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1818 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1819 return affected_pydeps
1820
1821 def DetermineIfStale(self, pydeps_path):
1822 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411823 import difflib
agrievef32bcc72016-04-04 14:57:401824 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1825 cmd = old_pydeps_data[1][1:].strip()
1826 new_pydeps_data = self._input_api.subprocess.check_output(
1827 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411828 old_contents = old_pydeps_data[2:]
1829 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401830 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411831 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401832
1833
1834def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1835 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001836 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281837 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1838 # Mac, so skip it on other platforms.
1839 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001840 return []
agrievef32bcc72016-04-04 14:57:401841 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1842 is_android = input_api.os_path.exists('third_party/android_tools')
1843 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1844 results = []
1845 # First, check for new / deleted .pydeps.
1846 for f in input_api.AffectedFiles(include_deletes=True):
1847 if f.LocalPath().endswith('.pydeps'):
1848 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1849 results.append(output_api.PresubmitError(
1850 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1851 'remove %s' % f.LocalPath()))
1852 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1853 results.append(output_api.PresubmitError(
1854 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1855 'include %s' % f.LocalPath()))
1856
1857 if results:
1858 return results
1859
1860 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1861
1862 for pydep_path in checker.ComputeAffectedPydeps():
1863 try:
phajdan.jr0d9878552016-11-04 10:49:411864 result = checker.DetermineIfStale(pydep_path)
1865 if result:
1866 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401867 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411868 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1869 'To regenerate, run:\n\n %s' %
1870 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401871 except input_api.subprocess.CalledProcessError as error:
1872 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1873 long_text=error.output)]
1874
1875 return results
1876
1877
glidere61efad2015-02-18 17:39:431878def _CheckSingletonInHeaders(input_api, output_api):
1879 """Checks to make sure no header files have |Singleton<|."""
1880 def FileFilter(affected_file):
1881 # It's ok for base/memory/singleton.h to have |Singleton<|.
1882 black_list = (_EXCLUDED_PATHS +
1883 input_api.DEFAULT_BLACK_LIST +
1884 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1885 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1886
sergeyu34d21222015-09-16 00:11:441887 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431888 files = []
1889 for f in input_api.AffectedSourceFiles(FileFilter):
1890 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1891 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1892 contents = input_api.ReadFile(f)
1893 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241894 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431895 pattern.search(line)):
1896 files.append(f)
1897 break
1898
1899 if files:
yolandyandaabc6d2016-04-18 18:29:391900 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441901 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431902 'Please move them to an appropriate source file so that the ' +
1903 'template gets instantiated in a single compilation unit.',
1904 files) ]
1905 return []
1906
1907
[email protected]fd20b902014-05-09 02:14:531908_DEPRECATED_CSS = [
1909 # Values
1910 ( "-webkit-box", "flex" ),
1911 ( "-webkit-inline-box", "inline-flex" ),
1912 ( "-webkit-flex", "flex" ),
1913 ( "-webkit-inline-flex", "inline-flex" ),
1914 ( "-webkit-min-content", "min-content" ),
1915 ( "-webkit-max-content", "max-content" ),
1916
1917 # Properties
1918 ( "-webkit-background-clip", "background-clip" ),
1919 ( "-webkit-background-origin", "background-origin" ),
1920 ( "-webkit-background-size", "background-size" ),
1921 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441922 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531923
1924 # Functions
1925 ( "-webkit-gradient", "gradient" ),
1926 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1927 ( "-webkit-linear-gradient", "linear-gradient" ),
1928 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1929 ( "-webkit-radial-gradient", "radial-gradient" ),
1930 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1931]
1932
dbeam1ec68ac2016-12-15 05:22:241933def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531934 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251935 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341936 documentation and iOS CSS for dom distiller
1937 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251938 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531939 results = []
dbeam070cfe62014-10-22 06:44:021940 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251941 black_list = (_EXCLUDED_PATHS +
1942 _TEST_CODE_EXCLUDED_PATHS +
1943 input_api.DEFAULT_BLACK_LIST +
1944 (r"^chrome/common/extensions/docs",
1945 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341946 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051947 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441948 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251949 r"^native_client_sdk"))
1950 file_filter = lambda f: input_api.FilterSourceFile(
1951 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531952 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1953 for line_num, line in fpath.ChangedContents():
1954 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021955 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531956 results.append(output_api.PresubmitError(
1957 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1958 (fpath.LocalPath(), line_num, deprecated_value, value)))
1959 return results
1960
mohan.reddyf21db962014-10-16 12:26:471961
dbeam070cfe62014-10-22 06:44:021962_DEPRECATED_JS = [
1963 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1964 ( "__defineGetter__", "Object.defineProperty" ),
1965 ( "__defineSetter__", "Object.defineProperty" ),
1966]
1967
dbeam1ec68ac2016-12-15 05:22:241968def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:021969 """Make sure that we don't use deprecated JS in Chrome code."""
1970 results = []
1971 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1972 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1973 input_api.DEFAULT_BLACK_LIST)
1974 file_filter = lambda f: input_api.FilterSourceFile(
1975 f, white_list=file_inclusion_pattern, black_list=black_list)
1976 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1977 for lnum, line in fpath.ChangedContents():
1978 for (deprecated, replacement) in _DEPRECATED_JS:
1979 if deprecated in line:
1980 results.append(output_api.PresubmitError(
1981 "%s:%d: Use of deprecated JS %s, use %s instead" %
1982 (fpath.LocalPath(), lnum, deprecated, replacement)))
1983 return results
1984
1985
dbeam1ec68ac2016-12-15 05:22:241986def _CheckForRiskyJsFeatures(input_api, output_api):
1987 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
1988 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
1989
1990 arrow_lines = []
1991 for f in input_api.AffectedFiles(file_filter=file_filter):
1992 for lnum, line in f.ChangedContents():
1993 if ' => ' in line:
1994 arrow_lines.append((f.LocalPath(), lnum))
1995
1996 if not arrow_lines:
1997 return []
1998
1999 return [output_api.PresubmitPromptWarning("""
2000Use of => operator detected in:
2001%s
2002Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2003https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2004""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2005
2006
rlanday6802cf632017-05-30 17:48:362007def _CheckForRelativeIncludes(input_api, output_api):
2008 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2009 import sys
2010 original_sys_path = sys.path
2011 try:
2012 sys.path = sys.path + [input_api.os_path.join(
2013 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2014 from cpp_checker import CppChecker
2015 finally:
2016 # Restore sys.path to what it was before.
2017 sys.path = original_sys_path
2018
2019 bad_files = {}
2020 for f in input_api.AffectedFiles(include_deletes=False):
2021 if (f.LocalPath().startswith('third_party') and
2022 not f.LocalPath().startswith('third_party/WebKit') and
2023 not f.LocalPath().startswith('third_party\\WebKit')):
2024 continue
2025
2026 if not CppChecker.IsCppFile(f.LocalPath()):
2027 continue
2028
2029 relative_includes = [line for line_num, line in f.ChangedContents()
2030 if "#include" in line and "../" in line]
2031 if not relative_includes:
2032 continue
2033 bad_files[f.LocalPath()] = relative_includes
2034
2035 if not bad_files:
2036 return []
2037
2038 error_descriptions = []
2039 for file_path, bad_lines in bad_files.iteritems():
2040 error_description = file_path
2041 for line in bad_lines:
2042 error_description += '\n ' + line
2043 error_descriptions.append(error_description)
2044
2045 results = []
2046 results.append(output_api.PresubmitError(
2047 'You added one or more relative #include paths (including "../").\n'
2048 'These shouldn\'t be used because they can be used to include headers\n'
2049 'from code that\'s not correctly specified as a dependency in the\n'
2050 'relevant BUILD.gn file(s).',
2051 error_descriptions))
2052
2053 return results
2054
dgnaa68d5e2015-06-10 10:08:222055def _AndroidSpecificOnUploadChecks(input_api, output_api):
2056 """Groups checks that target android code."""
2057 results = []
dgnaa68d5e2015-06-10 10:08:222058 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222059 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292060 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422061 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222062 return results
2063
2064
[email protected]22c9bd72011-03-27 16:47:392065def _CommonChecks(input_api, output_api):
2066 """Checks common to both upload and commit."""
2067 results = []
2068 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382069 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542070 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582071 results.extend(
2072 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192073 results.extend(
[email protected]760deea2013-12-10 19:33:492074 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542075 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182076 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522077 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222078 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442079 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592080 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062081 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122082 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182083 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222084 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302085 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492086 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032087 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492088 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442089 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272090 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072091 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542092 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442093 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392094 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552095 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042096 results.extend(
2097 input_api.canned_checks.CheckChangeHasNoTabs(
2098 input_api,
2099 output_api,
2100 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402101 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162102 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082103 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242104 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2105 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472106 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042107 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232108 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432109 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402110 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152111 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172112 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502113 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242114 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362115 results.extend(_CheckForRelativeIncludes(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242116
2117 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2118 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2119 input_api, output_api,
2120 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382121 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392122 return results
[email protected]1f7b4172010-01-28 01:17:342123
[email protected]b337cb5b2011-01-23 21:24:052124
[email protected]b8079ae4a2012-12-05 19:56:492125def _CheckPatchFiles(input_api, output_api):
2126 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2127 if f.LocalPath().endswith(('.orig', '.rej'))]
2128 if problems:
2129 return [output_api.PresubmitError(
2130 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032131 else:
2132 return []
[email protected]b8079ae4a2012-12-05 19:56:492133
2134
Kent Tamura5a8755d2017-06-29 23:37:072135def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
2136 macro_re = input_api.re.compile(
2137 r'^\s*#(el)?if.*\bdefined\(((OS_|COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
2138 include_re = input_api.re.compile(
2139 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2140 extension_re = input_api.re.compile(r'\.[a-z]+$')
2141 errors = []
2142 for f in input_api.AffectedFiles():
2143 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2144 continue
2145 found_line_number = None
2146 found_macro = None
2147 for line_num, line in f.ChangedContents():
2148 match = macro_re.search(line)
2149 if match:
2150 found_line_number = line_num
2151 found_macro = match.group(2)
2152 break
2153 if not found_line_number:
2154 continue
2155
2156 found_include = False
2157 for line in f.NewContents():
2158 if include_re.search(line):
2159 found_include = True
2160 break
2161 if found_include:
2162 continue
2163
2164 if not f.LocalPath().endswith('.h'):
2165 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2166 try:
2167 content = input_api.ReadFile(primary_header_path, 'r')
2168 if include_re.search(content):
2169 continue
2170 except IOError:
2171 pass
2172 errors.append('%s:%d %s macro is used without including build/'
2173 'build_config.h.'
2174 % (f.LocalPath(), found_line_number, found_macro))
2175 if errors:
2176 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2177 return []
2178
2179
[email protected]b00342e7f2013-03-26 16:21:542180def _DidYouMeanOSMacro(bad_macro):
2181 try:
2182 return {'A': 'OS_ANDROID',
2183 'B': 'OS_BSD',
2184 'C': 'OS_CHROMEOS',
2185 'F': 'OS_FREEBSD',
2186 'L': 'OS_LINUX',
2187 'M': 'OS_MACOSX',
2188 'N': 'OS_NACL',
2189 'O': 'OS_OPENBSD',
2190 'P': 'OS_POSIX',
2191 'S': 'OS_SOLARIS',
2192 'W': 'OS_WIN'}[bad_macro[3].upper()]
2193 except KeyError:
2194 return ''
2195
2196
2197def _CheckForInvalidOSMacrosInFile(input_api, f):
2198 """Check for sensible looking, totally invalid OS macros."""
2199 preprocessor_statement = input_api.re.compile(r'^\s*#')
2200 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2201 results = []
2202 for lnum, line in f.ChangedContents():
2203 if preprocessor_statement.search(line):
2204 for match in os_macro.finditer(line):
2205 if not match.group(1) in _VALID_OS_MACROS:
2206 good = _DidYouMeanOSMacro(match.group(1))
2207 did_you_mean = ' (did you mean %s?)' % good if good else ''
2208 results.append(' %s:%d %s%s' % (f.LocalPath(),
2209 lnum,
2210 match.group(1),
2211 did_you_mean))
2212 return results
2213
2214
2215def _CheckForInvalidOSMacros(input_api, output_api):
2216 """Check all affected files for invalid OS macros."""
2217 bad_macros = []
2218 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472219 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542220 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2221
2222 if not bad_macros:
2223 return []
2224
2225 return [output_api.PresubmitError(
2226 'Possibly invalid OS macro[s] found. Please fix your code\n'
2227 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2228
lliabraa35bab3932014-10-01 12:16:442229
2230def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2231 """Check all affected files for invalid "if defined" macros."""
2232 ALWAYS_DEFINED_MACROS = (
2233 "TARGET_CPU_PPC",
2234 "TARGET_CPU_PPC64",
2235 "TARGET_CPU_68K",
2236 "TARGET_CPU_X86",
2237 "TARGET_CPU_ARM",
2238 "TARGET_CPU_MIPS",
2239 "TARGET_CPU_SPARC",
2240 "TARGET_CPU_ALPHA",
2241 "TARGET_IPHONE_SIMULATOR",
2242 "TARGET_OS_EMBEDDED",
2243 "TARGET_OS_IPHONE",
2244 "TARGET_OS_MAC",
2245 "TARGET_OS_UNIX",
2246 "TARGET_OS_WIN32",
2247 )
2248 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2249 results = []
2250 for lnum, line in f.ChangedContents():
2251 for match in ifdef_macro.finditer(line):
2252 if match.group(1) in ALWAYS_DEFINED_MACROS:
2253 always_defined = ' %s is always defined. ' % match.group(1)
2254 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2255 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2256 lnum,
2257 always_defined,
2258 did_you_mean))
2259 return results
2260
2261
2262def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2263 """Check all affected files for invalid "if defined" macros."""
2264 bad_macros = []
2265 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212266 if f.LocalPath().startswith('third_party/sqlite/'):
2267 continue
lliabraa35bab3932014-10-01 12:16:442268 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2269 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2270
2271 if not bad_macros:
2272 return []
2273
2274 return [output_api.PresubmitError(
2275 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2276 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2277 bad_macros)]
2278
2279
mlamouria82272622014-09-16 18:45:042280def _CheckForIPCRules(input_api, output_api):
2281 """Check for same IPC rules described in
2282 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2283 """
2284 base_pattern = r'IPC_ENUM_TRAITS\('
2285 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2286 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2287
2288 problems = []
2289 for f in input_api.AffectedSourceFiles(None):
2290 local_path = f.LocalPath()
2291 if not local_path.endswith('.h'):
2292 continue
2293 for line_number, line in f.ChangedContents():
2294 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2295 problems.append(
2296 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2297
2298 if problems:
2299 return [output_api.PresubmitPromptWarning(
2300 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2301 else:
2302 return []
2303
[email protected]b00342e7f2013-03-26 16:21:542304
mostynbb639aca52015-01-07 20:31:232305def _CheckForWindowsLineEndings(input_api, output_api):
2306 """Check source code and known ascii text files for Windows style line
2307 endings.
2308 """
earthdok1b5e0ee2015-03-10 15:19:102309 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232310
2311 file_inclusion_pattern = (
2312 known_text_files,
2313 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2314 )
2315
2316 filter = lambda f: input_api.FilterSourceFile(
2317 f, white_list=file_inclusion_pattern, black_list=None)
2318 files = [f.LocalPath() for f in
2319 input_api.AffectedSourceFiles(filter)]
2320
2321 problems = []
2322
2323 for file in files:
2324 fp = open(file, 'r')
2325 for line in fp:
2326 if line.endswith('\r\n'):
2327 problems.append(file)
2328 break
2329 fp.close()
2330
2331 if problems:
2332 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2333 'these files to contain Windows style line endings?\n' +
2334 '\n'.join(problems))]
2335
2336 return []
2337
2338
pastarmovj89f7ee12016-09-20 14:58:132339def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2340 lint_filters=None, verbose_level=None):
2341 """Checks that all source files use SYSLOG properly."""
2342 syslog_files = []
2343 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562344 for line_number, line in f.ChangedContents():
2345 if 'SYSLOG' in line:
2346 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2347
pastarmovj89f7ee12016-09-20 14:58:132348 if syslog_files:
2349 return [output_api.PresubmitPromptWarning(
2350 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2351 ' calls.\nFiles to check:\n', items=syslog_files)]
2352 return []
2353
2354
[email protected]1f7b4172010-01-28 01:17:342355def CheckChangeOnUpload(input_api, output_api):
2356 results = []
2357 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472358 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282359 results.extend(
jam93a6ee792017-02-08 23:59:222360 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192361 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222362 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132363 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162364 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542365 return results
[email protected]ca8d19842009-02-19 16:33:122366
2367
[email protected]1bfb8322014-04-23 01:02:412368def GetTryServerMasterForBot(bot):
2369 """Returns the Try Server master for the given bot.
2370
[email protected]0bb112362014-07-26 04:38:322371 It tries to guess the master from the bot name, but may still fail
2372 and return None. There is no longer a default master.
2373 """
2374 # Potentially ambiguous bot names are listed explicitly.
2375 master_map = {
tandriie5587792016-07-14 00:34:502376 'chromium_presubmit': 'master.tryserver.chromium.linux',
2377 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412378 }
[email protected]0bb112362014-07-26 04:38:322379 master = master_map.get(bot)
2380 if not master:
wnwen4fbaab82016-05-25 12:54:362381 if 'android' in bot:
tandriie5587792016-07-14 00:34:502382 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362383 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502384 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322385 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502386 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322387 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502388 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322389 return master
[email protected]1bfb8322014-04-23 01:02:412390
2391
Paweł Hajdan, Jr55083782014-12-19 20:32:562392def GetDefaultTryConfigs(bots):
2393 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012394 """
2395
Paweł Hajdan, Jr55083782014-12-19 20:32:562396 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412397
2398 # Build up the mapping from tryserver master to bot/test.
2399 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562400 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412401 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2402 return out
[email protected]38c6a512013-12-18 23:48:012403
2404
[email protected]ca8d19842009-02-19 16:33:122405def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542406 results = []
[email protected]1f7b4172010-01-28 01:17:342407 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542408 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272409 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342410 input_api,
2411 output_api,
[email protected]2fdd1f362013-01-16 03:56:032412 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272413
jam93a6ee792017-02-08 23:59:222414 results.extend(
2415 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542416 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2417 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412418 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2419 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542420 return results