blob: 9ffa555eaa1849b604f3d52c82d1e6d5b1de808a [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 ),
dskiba1474c2bfd62017-07-20 02:19:24386 (
387 'leveldb::DB::Open',
388 (
389 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
390 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
391 "Chrome's tracing, making their memory usage visible.",
392 ),
393 True,
394 (
395 r'^third_party/leveldatabase/.*\.(cc|h)$',
396 ),
397 )
[email protected]127f18ec2012-06-16 05:05:59398)
399
wnwenbdc444e2016-05-25 13:44:15400
mlamouria82272622014-09-16 18:45:04401_IPC_ENUM_TRAITS_DEPRECATED = (
402 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
403 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
404
[email protected]127f18ec2012-06-16 05:05:59405
[email protected]b00342e7f2013-03-26 16:21:54406_VALID_OS_MACROS = (
407 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08408 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54409 'OS_ANDROID',
410 'OS_BSD',
411 'OS_CAT', # For testing.
412 'OS_CHROMEOS',
413 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37414 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54415 'OS_IOS',
416 'OS_LINUX',
417 'OS_MACOSX',
418 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21419 'OS_NACL_NONSFI',
420 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12421 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54422 'OS_OPENBSD',
423 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37424 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54425 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54426 'OS_WIN',
427)
428
429
agrievef32bcc72016-04-04 14:57:40430_ANDROID_SPECIFIC_PYDEPS_FILES = [
431 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04432 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58433 'build/secondary/third_party/android_platform/'
434 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19435 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40436]
437
wnwenbdc444e2016-05-25 13:44:15438
agrievef32bcc72016-04-04 14:57:40439_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40440]
441
wnwenbdc444e2016-05-25 13:44:15442
agrievef32bcc72016-04-04 14:57:40443_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
444
445
[email protected]55459852011-08-10 15:17:19446def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
447 """Attempts to prevent use of functions intended only for testing in
448 non-testing code. For now this is just a best-effort implementation
449 that ignores header files and may have some false positives. A
450 better implementation would probably need a proper C++ parser.
451 """
452 # We only scan .cc files and the like, as the declaration of
453 # for-testing functions in header files are hard to distinguish from
454 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44455 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19456
jochenc0d4808c2015-07-27 09:25:42457 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19458 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09459 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19460 exclusion_pattern = input_api.re.compile(
461 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
462 base_function_pattern, base_function_pattern))
463
464 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44465 black_list = (_EXCLUDED_PATHS +
466 _TEST_CODE_EXCLUDED_PATHS +
467 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19468 return input_api.FilterSourceFile(
469 affected_file,
470 white_list=(file_inclusion_pattern, ),
471 black_list=black_list)
472
473 problems = []
474 for f in input_api.AffectedSourceFiles(FilterFile):
475 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24476 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03477 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46478 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03479 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19480 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03481 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19482
483 if problems:
[email protected]f7051d52013-04-02 18:31:42484 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03485 else:
486 return []
[email protected]55459852011-08-10 15:17:19487
488
[email protected]10689ca2011-09-02 02:31:54489def _CheckNoIOStreamInHeaders(input_api, output_api):
490 """Checks to make sure no .h files include <iostream>."""
491 files = []
492 pattern = input_api.re.compile(r'^#include\s*<iostream>',
493 input_api.re.MULTILINE)
494 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
495 if not f.LocalPath().endswith('.h'):
496 continue
497 contents = input_api.ReadFile(f)
498 if pattern.search(contents):
499 files.append(f)
500
501 if len(files):
yolandyandaabc6d2016-04-18 18:29:39502 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06503 'Do not #include <iostream> in header files, since it inserts static '
504 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54505 '#include <ostream>. See http://crbug.com/94794',
506 files) ]
507 return []
508
509
[email protected]72df4e782012-06-21 16:28:18510def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52511 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18512 problems = []
513 for f in input_api.AffectedFiles():
514 if (not f.LocalPath().endswith(('.cc', '.mm'))):
515 continue
516
517 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04518 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18519 problems.append(' %s:%d' % (f.LocalPath(), line_num))
520
521 if not problems:
522 return []
523 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
524 '\n'.join(problems))]
525
526
danakj61c1aa22015-10-26 19:55:52527def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57528 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52529 errors = []
530 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
531 input_api.re.MULTILINE)
532 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
533 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
534 continue
535 for lnum, line in f.ChangedContents():
536 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17537 errors.append(output_api.PresubmitError(
538 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57539 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17540 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52541 return errors
542
543
mcasasb7440c282015-02-04 14:52:19544def _FindHistogramNameInLine(histogram_name, line):
545 """Tries to find a histogram name or prefix in a line."""
546 if not "affected-histogram" in line:
547 return histogram_name in line
548 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
549 # the histogram_name.
550 if not '"' in line:
551 return False
552 histogram_prefix = line.split('\"')[1]
553 return histogram_prefix in histogram_name
554
555
556def _CheckUmaHistogramChanges(input_api, output_api):
557 """Check that UMA histogram names in touched lines can still be found in other
558 lines of the patch or in histograms.xml. Note that this check would not catch
559 the reverse: changes in histograms.xml not matched in the code itself."""
560 touched_histograms = []
561 histograms_xml_modifications = []
562 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
563 for f in input_api.AffectedFiles():
564 # If histograms.xml itself is modified, keep the modified lines for later.
565 if f.LocalPath().endswith(('histograms.xml')):
566 histograms_xml_modifications = f.ChangedContents()
567 continue
568 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
569 continue
570 for line_num, line in f.ChangedContents():
571 found = pattern.search(line)
572 if found:
573 touched_histograms.append([found.group(1), f, line_num])
574
575 # Search for the touched histogram names in the local modifications to
576 # histograms.xml, and, if not found, on the base histograms.xml file.
577 unmatched_histograms = []
578 for histogram_info in touched_histograms:
579 histogram_name_found = False
580 for line_num, line in histograms_xml_modifications:
581 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
582 if histogram_name_found:
583 break
584 if not histogram_name_found:
585 unmatched_histograms.append(histogram_info)
586
eromanb90c82e7e32015-04-01 15:13:49587 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19588 problems = []
589 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49590 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19591 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45592 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19593 histogram_name_found = False
594 for line in histograms_xml:
595 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
596 if histogram_name_found:
597 break
598 if not histogram_name_found:
599 problems.append(' [%s:%d] %s' %
600 (f.LocalPath(), line_num, histogram_name))
601
602 if not problems:
603 return []
604 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
605 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49606 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19607
wnwenbdc444e2016-05-25 13:44:15608
yolandyandaabc6d2016-04-18 18:29:39609def _CheckFlakyTestUsage(input_api, output_api):
610 """Check that FlakyTest annotation is our own instead of the android one"""
611 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
612 files = []
613 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
614 if f.LocalPath().endswith('Test.java'):
615 if pattern.search(input_api.ReadFile(f)):
616 files.append(f)
617 if len(files):
618 return [output_api.PresubmitError(
619 'Use org.chromium.base.test.util.FlakyTest instead of '
620 'android.test.FlakyTest',
621 files)]
622 return []
mcasasb7440c282015-02-04 14:52:19623
wnwenbdc444e2016-05-25 13:44:15624
[email protected]8ea5d4b2011-09-13 21:49:22625def _CheckNoNewWStrings(input_api, output_api):
626 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27627 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22628 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20629 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57630 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34631 '/win/' in f.LocalPath() or
632 'chrome_elf' in f.LocalPath() or
633 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20634 continue
[email protected]8ea5d4b2011-09-13 21:49:22635
[email protected]a11dbe9b2012-08-07 01:32:58636 allowWString = False
[email protected]b5c24292011-11-28 14:38:20637 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58638 if 'presubmit: allow wstring' in line:
639 allowWString = True
640 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27641 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58642 allowWString = False
643 else:
644 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22645
[email protected]55463aa62011-10-12 00:48:27646 if not problems:
647 return []
648 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58649 ' If you are calling a cross-platform API that accepts a wstring, '
650 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27651 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22652
653
[email protected]2a8ac9c2011-10-19 17:20:44654def _CheckNoDEPSGIT(input_api, output_api):
655 """Make sure .DEPS.git is never modified manually."""
656 if any(f.LocalPath().endswith('.DEPS.git') for f in
657 input_api.AffectedFiles()):
658 return [output_api.PresubmitError(
659 'Never commit changes to .DEPS.git. This file is maintained by an\n'
660 'automated system based on what\'s in DEPS and your changes will be\n'
661 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34662 '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:44663 'for more information')]
664 return []
665
666
tandriief664692014-09-23 14:51:47667def _CheckValidHostsInDEPS(input_api, output_api):
668 """Checks that DEPS file deps are from allowed_hosts."""
669 # Run only if DEPS file has been modified to annoy fewer bystanders.
670 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
671 return []
672 # Outsource work to gclient verify
673 try:
674 input_api.subprocess.check_output(['gclient', 'verify'])
675 return []
676 except input_api.subprocess.CalledProcessError, error:
677 return [output_api.PresubmitError(
678 'DEPS file must have only git dependencies.',
679 long_text=error.output)]
680
681
[email protected]127f18ec2012-06-16 05:05:59682def _CheckNoBannedFunctions(input_api, output_api):
683 """Make sure that banned functions are not used."""
684 warnings = []
685 errors = []
686
wnwenbdc444e2016-05-25 13:44:15687 def IsBlacklisted(affected_file, blacklist):
688 local_path = affected_file.LocalPath()
689 for item in blacklist:
690 if input_api.re.match(item, local_path):
691 return True
692 return False
693
694 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
695 matched = False
696 if func_name[0:1] == '/':
697 regex = func_name[1:]
698 if input_api.re.search(regex, line):
699 matched = True
700 elif func_name in line:
dchenge07de812016-06-20 19:27:17701 matched = True
wnwenbdc444e2016-05-25 13:44:15702 if matched:
dchenge07de812016-06-20 19:27:17703 problems = warnings
wnwenbdc444e2016-05-25 13:44:15704 if error:
dchenge07de812016-06-20 19:27:17705 problems = errors
wnwenbdc444e2016-05-25 13:44:15706 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
707 for message_line in message:
708 problems.append(' %s' % message_line)
709
[email protected]127f18ec2012-06-16 05:05:59710 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
711 for f in input_api.AffectedFiles(file_filter=file_filter):
712 for line_num, line in f.ChangedContents():
713 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15714 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59715
716 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
717 for f in input_api.AffectedFiles(file_filter=file_filter):
718 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49719 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49720 if IsBlacklisted(f, excluded_paths):
721 continue
wnwenbdc444e2016-05-25 13:44:15722 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59723
724 result = []
725 if (warnings):
726 result.append(output_api.PresubmitPromptWarning(
727 'Banned functions were used.\n' + '\n'.join(warnings)))
728 if (errors):
729 result.append(output_api.PresubmitError(
730 'Banned functions were used.\n' + '\n'.join(errors)))
731 return result
732
733
[email protected]6c063c62012-07-11 19:11:06734def _CheckNoPragmaOnce(input_api, output_api):
735 """Make sure that banned functions are not used."""
736 files = []
737 pattern = input_api.re.compile(r'^#pragma\s+once',
738 input_api.re.MULTILINE)
739 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
740 if not f.LocalPath().endswith('.h'):
741 continue
742 contents = input_api.ReadFile(f)
743 if pattern.search(contents):
744 files.append(f)
745
746 if files:
747 return [output_api.PresubmitError(
748 'Do not use #pragma once in header files.\n'
749 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
750 files)]
751 return []
752
[email protected]127f18ec2012-06-16 05:05:59753
[email protected]e7479052012-09-19 00:26:12754def _CheckNoTrinaryTrueFalse(input_api, output_api):
755 """Checks to make sure we don't introduce use of foo ? true : false."""
756 problems = []
757 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
758 for f in input_api.AffectedFiles():
759 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
760 continue
761
762 for line_num, line in f.ChangedContents():
763 if pattern.match(line):
764 problems.append(' %s:%d' % (f.LocalPath(), line_num))
765
766 if not problems:
767 return []
768 return [output_api.PresubmitPromptWarning(
769 'Please consider avoiding the "? true : false" pattern if possible.\n' +
770 '\n'.join(problems))]
771
772
[email protected]55f9f382012-07-31 11:02:18773def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28774 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18775 change. Breaking - rules is an error, breaking ! rules is a
776 warning.
777 """
mohan.reddyf21db962014-10-16 12:26:47778 import sys
[email protected]55f9f382012-07-31 11:02:18779 # We need to wait until we have an input_api object and use this
780 # roundabout construct to import checkdeps because this file is
781 # eval-ed and thus doesn't have __file__.
782 original_sys_path = sys.path
783 try:
784 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47785 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18786 import checkdeps
787 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28788 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18789 from rules import Rule
790 finally:
791 # Restore sys.path to what it was before.
792 sys.path = original_sys_path
793
794 added_includes = []
rhalavati08acd232017-04-03 07:23:28795 added_imports = []
[email protected]55f9f382012-07-31 11:02:18796 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28797 if CppChecker.IsCppFile(f.LocalPath()):
798 changed_lines = [line for line_num, line in f.ChangedContents()]
799 added_includes.append([f.LocalPath(), changed_lines])
800 elif ProtoChecker.IsProtoFile(f.LocalPath()):
801 changed_lines = [line for line_num, line in f.ChangedContents()]
802 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18803
[email protected]26385172013-05-09 23:11:35804 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18805
806 error_descriptions = []
807 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28808 error_subjects = set()
809 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18810 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
811 added_includes):
812 description_with_path = '%s\n %s' % (path, rule_description)
813 if rule_type == Rule.DISALLOW:
814 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28815 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18816 else:
817 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28818 warning_subjects.add("#includes")
819
820 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
821 added_imports):
822 description_with_path = '%s\n %s' % (path, rule_description)
823 if rule_type == Rule.DISALLOW:
824 error_descriptions.append(description_with_path)
825 error_subjects.add("imports")
826 else:
827 warning_descriptions.append(description_with_path)
828 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18829
830 results = []
831 if error_descriptions:
832 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28833 'You added one or more %s that violate checkdeps rules.'
834 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18835 error_descriptions))
836 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42837 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28838 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18839 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28840 '%s? See relevant DEPS file(s) for details and contacts.' %
841 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18842 warning_descriptions))
843 return results
844
845
[email protected]fbcafe5a2012-08-08 15:31:22846def _CheckFilePermissions(input_api, output_api):
847 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15848 if input_api.platform == 'win32':
849 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29850 checkperms_tool = input_api.os_path.join(
851 input_api.PresubmitLocalPath(),
852 'tools', 'checkperms', 'checkperms.py')
853 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47854 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22855 for f in input_api.AffectedFiles():
856 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11857 try:
858 input_api.subprocess.check_output(args)
859 return []
860 except input_api.subprocess.CalledProcessError as error:
861 return [output_api.PresubmitError(
862 'checkperms.py failed:',
863 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22864
865
robertocn832f5992017-01-04 19:01:30866def _CheckTeamTags(input_api, output_api):
867 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
868 checkteamtags_tool = input_api.os_path.join(
869 input_api.PresubmitLocalPath(),
870 'tools', 'checkteamtags', 'checkteamtags.py')
871 args = [input_api.python_executable, checkteamtags_tool,
872 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22873 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30874 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
875 'OWNERS']
876 try:
877 if files:
878 input_api.subprocess.check_output(args + files)
879 return []
880 except input_api.subprocess.CalledProcessError as error:
881 return [output_api.PresubmitError(
882 'checkteamtags.py failed:',
883 long_text=error.output)]
884
885
[email protected]c8278b32012-10-30 20:35:49886def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
887 """Makes sure we don't include ui/aura/window_property.h
888 in header files.
889 """
890 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
891 errors = []
892 for f in input_api.AffectedFiles():
893 if not f.LocalPath().endswith('.h'):
894 continue
895 for line_num, line in f.ChangedContents():
896 if pattern.match(line):
897 errors.append(' %s:%d' % (f.LocalPath(), line_num))
898
899 results = []
900 if errors:
901 results.append(output_api.PresubmitError(
902 'Header files should not include ui/aura/window_property.h', errors))
903 return results
904
905
[email protected]70ca77752012-11-20 03:45:03906def _CheckForVersionControlConflictsInFile(input_api, f):
907 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
908 errors = []
909 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23910 if f.LocalPath().endswith('.md'):
911 # First-level headers in markdown look a lot like version control
912 # conflict markers. http://daringfireball.net/projects/markdown/basics
913 continue
[email protected]70ca77752012-11-20 03:45:03914 if pattern.match(line):
915 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
916 return errors
917
918
919def _CheckForVersionControlConflicts(input_api, output_api):
920 """Usually this is not intentional and will cause a compile failure."""
921 errors = []
922 for f in input_api.AffectedFiles():
923 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
924
925 results = []
926 if errors:
927 results.append(output_api.PresubmitError(
928 'Version control conflict markers found, please resolve.', errors))
929 return results
930
estadee17314a02017-01-12 16:22:16931def _CheckGoogleSupportAnswerUrl(input_api, output_api):
932 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
933 errors = []
934 for f in input_api.AffectedFiles():
935 for line_num, line in f.ChangedContents():
936 if pattern.search(line):
937 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
938
939 results = []
940 if errors:
941 results.append(output_api.PresubmitPromptWarning(
942 'Found Google support URL addressed by answer number. Please replace with '
943 'a p= identifier instead. See crbug.com/679462\n', errors))
944 return results
945
[email protected]70ca77752012-11-20 03:45:03946
[email protected]06e6d0ff2012-12-11 01:36:44947def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
948 def FilterFile(affected_file):
949 """Filter function for use with input_api.AffectedSourceFiles,
950 below. This filters out everything except non-test files from
951 top-level directories that generally speaking should not hard-code
952 service URLs (e.g. src/android_webview/, src/content/ and others).
953 """
954 return input_api.FilterSourceFile(
955 affected_file,
[email protected]78bb39d62012-12-11 15:11:56956 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44957 black_list=(_EXCLUDED_PATHS +
958 _TEST_CODE_EXCLUDED_PATHS +
959 input_api.DEFAULT_BLACK_LIST))
960
reillyi38965732015-11-16 18:27:33961 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
962 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46963 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
964 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44965 problems = [] # items are (filename, line_number, line)
966 for f in input_api.AffectedSourceFiles(FilterFile):
967 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46968 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44969 problems.append((f.LocalPath(), line_num, line))
970
971 if problems:
[email protected]f7051d52013-04-02 18:31:42972 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44973 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58974 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44975 [' %s:%d: %s' % (
976 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03977 else:
978 return []
[email protected]06e6d0ff2012-12-11 01:36:44979
980
[email protected]d2530012013-01-25 16:39:27981def _CheckNoAbbreviationInPngFileName(input_api, output_api):
982 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31983 The native_client_sdk directory is excluded because it has auto-generated PNG
984 files for documentation.
[email protected]d2530012013-01-25 16:39:27985 """
[email protected]d2530012013-01-25 16:39:27986 errors = []
binji0dcdf342014-12-12 18:32:31987 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
988 black_list = (r'^native_client_sdk[\\\/]',)
989 file_filter = lambda f: input_api.FilterSourceFile(
990 f, white_list=white_list, black_list=black_list)
991 for f in input_api.AffectedFiles(include_deletes=False,
992 file_filter=file_filter):
993 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27994
995 results = []
996 if errors:
997 results.append(output_api.PresubmitError(
998 'The name of PNG files should not have abbreviations. \n'
999 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1000 'Contact [email protected] if you have questions.', errors))
1001 return results
1002
1003
Daniel Cheng4dcdb6b2017-04-13 08:30:171004def _ExtractAddRulesFromParsedDeps(parsed_deps):
1005 """Extract the rules that add dependencies from a parsed DEPS file.
1006
1007 Args:
1008 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1009 add_rules = set()
1010 add_rules.update([
1011 rule[1:] for rule in parsed_deps.get('include_rules', [])
1012 if rule.startswith('+') or rule.startswith('!')
1013 ])
1014 for specific_file, rules in parsed_deps.get('specific_include_rules',
1015 {}).iteritems():
1016 add_rules.update([
1017 rule[1:] for rule in rules
1018 if rule.startswith('+') or rule.startswith('!')
1019 ])
1020 return add_rules
1021
1022
1023def _ParseDeps(contents):
1024 """Simple helper for parsing DEPS files."""
1025 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171026 class _VarImpl:
1027
1028 def __init__(self, local_scope):
1029 self._local_scope = local_scope
1030
1031 def Lookup(self, var_name):
1032 """Implements the Var syntax."""
1033 try:
1034 return self._local_scope['vars'][var_name]
1035 except KeyError:
1036 raise Exception('Var is not defined: %s' % var_name)
1037
1038 local_scope = {}
1039 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171040 'Var': _VarImpl(local_scope).Lookup,
1041 }
1042 exec contents in global_scope, local_scope
1043 return local_scope
1044
1045
1046def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081047 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411048 a set of DEPS entries that we should look up.
1049
1050 For a directory (rather than a specific filename) we fake a path to
1051 a specific filename by adding /DEPS. This is chosen as a file that
1052 will seldom or never be subject to per-file include_rules.
1053 """
[email protected]2b438d62013-11-14 17:54:141054 # We ignore deps entries on auto-generated directories.
1055 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081056
Daniel Cheng4dcdb6b2017-04-13 08:30:171057 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1058 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1059
1060 added_deps = new_deps.difference(old_deps)
1061
[email protected]2b438d62013-11-14 17:54:141062 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171063 for added_dep in added_deps:
1064 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1065 continue
1066 # Assume that a rule that ends in .h is a rule for a specific file.
1067 if added_dep.endswith('.h'):
1068 results.add(added_dep)
1069 else:
1070 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081071 return results
1072
1073
[email protected]e871964c2013-05-13 14:14:551074def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1075 """When a dependency prefixed with + is added to a DEPS file, we
1076 want to make sure that the change is reviewed by an OWNER of the
1077 target file or directory, to avoid layering violations from being
1078 introduced. This check verifies that this happens.
1079 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171080 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241081
1082 file_filter = lambda f: not input_api.re.match(
1083 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1084 for f in input_api.AffectedFiles(include_deletes=False,
1085 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551086 filename = input_api.os_path.basename(f.LocalPath())
1087 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171088 virtual_depended_on_files.update(_CalculateAddedDeps(
1089 input_api.os_path,
1090 '\n'.join(f.OldContents()),
1091 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551092
[email protected]e871964c2013-05-13 14:14:551093 if not virtual_depended_on_files:
1094 return []
1095
1096 if input_api.is_committing:
1097 if input_api.tbr:
1098 return [output_api.PresubmitNotifyResult(
1099 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271100 if input_api.dry_run:
1101 return [output_api.PresubmitNotifyResult(
1102 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551103 if not input_api.change.issue:
1104 return [output_api.PresubmitError(
1105 "DEPS approval by OWNERS check failed: this change has "
1106 "no Rietveld issue number, so we can't check it for approvals.")]
1107 output = output_api.PresubmitError
1108 else:
1109 output = output_api.PresubmitNotifyResult
1110
1111 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501112 owner_email, reviewers = (
1113 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1114 input_api,
1115 owners_db.email_regexp,
1116 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551117
1118 owner_email = owner_email or input_api.change.author_email
1119
[email protected]de4f7d22013-05-23 14:27:461120 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511121 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461122 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551123 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1124 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411125
1126 # We strip the /DEPS part that was added by
1127 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1128 # directory.
1129 def StripDeps(path):
1130 start_deps = path.rfind('/DEPS')
1131 if start_deps != -1:
1132 return path[:start_deps]
1133 else:
1134 return path
1135 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551136 for path in missing_files]
1137
1138 if unapproved_dependencies:
1139 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151140 output('You need LGTM from owners of depends-on paths in DEPS that were '
1141 'modified in this CL:\n %s' %
1142 '\n '.join(sorted(unapproved_dependencies)))]
1143 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1144 output_list.append(output(
1145 'Suggested missing target path OWNERS:\n %s' %
1146 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551147 return output_list
1148
1149 return []
1150
1151
[email protected]85218562013-11-22 07:41:401152def _CheckSpamLogging(input_api, output_api):
1153 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1154 black_list = (_EXCLUDED_PATHS +
1155 _TEST_CODE_EXCLUDED_PATHS +
1156 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501157 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191158 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481159 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461160 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121161 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1162 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581163 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
huangsa13b5a02017-07-14 15:17:591164 r"^chrome[\\\/]installer[\\\/]zucchini[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161165 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031166 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151167 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1168 r"^chromecast[\\\/]",
1169 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481170 r"^components[\\\/]browser_watcher[\\\/]"
1171 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311172 r"^components[\\\/]html_viewer[\\\/]"
1173 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461174 # TODO(peter): Remove this exception. https://crbug.com/534537
1175 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1176 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251177 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1178 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241179 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111180 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151181 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111182 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521183 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501184 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361185 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311186 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131187 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001188 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441189 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451190 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021191 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351192 r"dump_file_system.cc$",
1193 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401194 source_file_filter = lambda x: input_api.FilterSourceFile(
1195 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1196
thomasanderson625d3932017-03-29 07:16:581197 log_info = set([])
1198 printf = set([])
[email protected]85218562013-11-22 07:41:401199
1200 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581201 for _, line in f.ChangedContents():
1202 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1203 log_info.add(f.LocalPath())
1204 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1205 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371206
thomasanderson625d3932017-03-29 07:16:581207 if input_api.re.search(r"\bprintf\(", line):
1208 printf.add(f.LocalPath())
1209 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1210 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401211
1212 if log_info:
1213 return [output_api.PresubmitError(
1214 'These files spam the console log with LOG(INFO):',
1215 items=log_info)]
1216 if printf:
1217 return [output_api.PresubmitError(
1218 'These files spam the console log with printf/fprintf:',
1219 items=printf)]
1220 return []
1221
1222
[email protected]49aa76a2013-12-04 06:59:161223def _CheckForAnonymousVariables(input_api, output_api):
1224 """These types are all expected to hold locks while in scope and
1225 so should never be anonymous (which causes them to be immediately
1226 destroyed)."""
1227 they_who_must_be_named = [
1228 'base::AutoLock',
1229 'base::AutoReset',
1230 'base::AutoUnlock',
1231 'SkAutoAlphaRestore',
1232 'SkAutoBitmapShaderInstall',
1233 'SkAutoBlitterChoose',
1234 'SkAutoBounderCommit',
1235 'SkAutoCallProc',
1236 'SkAutoCanvasRestore',
1237 'SkAutoCommentBlock',
1238 'SkAutoDescriptor',
1239 'SkAutoDisableDirectionCheck',
1240 'SkAutoDisableOvalCheck',
1241 'SkAutoFree',
1242 'SkAutoGlyphCache',
1243 'SkAutoHDC',
1244 'SkAutoLockColors',
1245 'SkAutoLockPixels',
1246 'SkAutoMalloc',
1247 'SkAutoMaskFreeImage',
1248 'SkAutoMutexAcquire',
1249 'SkAutoPathBoundsUpdate',
1250 'SkAutoPDFRelease',
1251 'SkAutoRasterClipValidate',
1252 'SkAutoRef',
1253 'SkAutoTime',
1254 'SkAutoTrace',
1255 'SkAutoUnref',
1256 ]
1257 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1258 # bad: base::AutoLock(lock.get());
1259 # not bad: base::AutoLock lock(lock.get());
1260 bad_pattern = input_api.re.compile(anonymous)
1261 # good: new base::AutoLock(lock.get())
1262 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1263 errors = []
1264
1265 for f in input_api.AffectedFiles():
1266 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1267 continue
1268 for linenum, line in f.ChangedContents():
1269 if bad_pattern.search(line) and not good_pattern.search(line):
1270 errors.append('%s:%d' % (f.LocalPath(), linenum))
1271
1272 if errors:
1273 return [output_api.PresubmitError(
1274 'These lines create anonymous variables that need to be named:',
1275 items=errors)]
1276 return []
1277
1278
[email protected]999261d2014-03-03 20:08:081279def _CheckUserActionUpdate(input_api, output_api):
1280 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521281 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081282 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521283 # If actions.xml is already included in the changelist, the PRESUBMIT
1284 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081285 return []
1286
[email protected]999261d2014-03-03 20:08:081287 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1288 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521289 current_actions = None
[email protected]999261d2014-03-03 20:08:081290 for f in input_api.AffectedFiles(file_filter=file_filter):
1291 for line_num, line in f.ChangedContents():
1292 match = input_api.re.search(action_re, line)
1293 if match:
[email protected]2f92dec2014-03-07 19:21:521294 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1295 # loaded only once.
1296 if not current_actions:
1297 with open('tools/metrics/actions/actions.xml') as actions_f:
1298 current_actions = actions_f.read()
1299 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081300 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521301 action = 'name="{0}"'.format(action_name)
1302 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081303 return [output_api.PresubmitPromptWarning(
1304 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521305 'tools/metrics/actions/actions.xml. Please run '
1306 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081307 % (f.LocalPath(), line_num, action_name))]
1308 return []
1309
1310
[email protected]99171a92014-06-03 08:44:471311def _GetJSONParseError(input_api, filename, eat_comments=True):
1312 try:
1313 contents = input_api.ReadFile(filename)
1314 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131315 import sys
1316 original_sys_path = sys.path
1317 try:
1318 sys.path = sys.path + [input_api.os_path.join(
1319 input_api.PresubmitLocalPath(),
1320 'tools', 'json_comment_eater')]
1321 import json_comment_eater
1322 finally:
1323 sys.path = original_sys_path
1324 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471325
1326 input_api.json.loads(contents)
1327 except ValueError as e:
1328 return e
1329 return None
1330
1331
1332def _GetIDLParseError(input_api, filename):
1333 try:
1334 contents = input_api.ReadFile(filename)
1335 idl_schema = input_api.os_path.join(
1336 input_api.PresubmitLocalPath(),
1337 'tools', 'json_schema_compiler', 'idl_schema.py')
1338 process = input_api.subprocess.Popen(
1339 [input_api.python_executable, idl_schema],
1340 stdin=input_api.subprocess.PIPE,
1341 stdout=input_api.subprocess.PIPE,
1342 stderr=input_api.subprocess.PIPE,
1343 universal_newlines=True)
1344 (_, error) = process.communicate(input=contents)
1345 return error or None
1346 except ValueError as e:
1347 return e
1348
1349
1350def _CheckParseErrors(input_api, output_api):
1351 """Check that IDL and JSON files do not contain syntax errors."""
1352 actions = {
1353 '.idl': _GetIDLParseError,
1354 '.json': _GetJSONParseError,
1355 }
1356 # These paths contain test data and other known invalid JSON files.
1357 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491358 r'test[\\\/]data[\\\/]',
1359 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471360 ]
1361 # Most JSON files are preprocessed and support comments, but these do not.
1362 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491363 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471364 ]
1365 # Only run IDL checker on files in these directories.
1366 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491367 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1368 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471369 ]
1370
1371 def get_action(affected_file):
1372 filename = affected_file.LocalPath()
1373 return actions.get(input_api.os_path.splitext(filename)[1])
1374
1375 def MatchesFile(patterns, path):
1376 for pattern in patterns:
1377 if input_api.re.search(pattern, path):
1378 return True
1379 return False
1380
1381 def FilterFile(affected_file):
1382 action = get_action(affected_file)
1383 if not action:
1384 return False
1385 path = affected_file.LocalPath()
1386
1387 if MatchesFile(excluded_patterns, path):
1388 return False
1389
1390 if (action == _GetIDLParseError and
1391 not MatchesFile(idl_included_patterns, path)):
1392 return False
1393 return True
1394
1395 results = []
1396 for affected_file in input_api.AffectedFiles(
1397 file_filter=FilterFile, include_deletes=False):
1398 action = get_action(affected_file)
1399 kwargs = {}
1400 if (action == _GetJSONParseError and
1401 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1402 kwargs['eat_comments'] = False
1403 parse_error = action(input_api,
1404 affected_file.AbsoluteLocalPath(),
1405 **kwargs)
1406 if parse_error:
1407 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1408 (affected_file.LocalPath(), parse_error)))
1409 return results
1410
1411
[email protected]760deea2013-12-10 19:33:491412def _CheckJavaStyle(input_api, output_api):
1413 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471414 import sys
[email protected]760deea2013-12-10 19:33:491415 original_sys_path = sys.path
1416 try:
1417 sys.path = sys.path + [input_api.os_path.join(
1418 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1419 import checkstyle
1420 finally:
1421 # Restore sys.path to what it was before.
1422 sys.path = original_sys_path
1423
1424 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091425 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511426 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491427
1428
dchenge07de812016-06-20 19:27:171429def _CheckIpcOwners(input_api, output_api):
1430 """Checks that affected files involving IPC have an IPC OWNERS rule.
1431
1432 Whether or not a file affects IPC is determined by a simple whitelist of
1433 filename patterns."""
1434 file_patterns = [
palmerb19a0932017-01-24 04:00:311435 # Legacy IPC:
dchenge07de812016-06-20 19:27:171436 '*_messages.cc',
1437 '*_messages*.h',
1438 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311439 # Mojo IPC:
dchenge07de812016-06-20 19:27:171440 '*.mojom',
1441 '*_struct_traits*.*',
1442 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311443 '*.typemap',
1444 # Android native IPC:
1445 '*.aidl',
1446 # Blink uses a different file naming convention:
1447 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171448 '*StructTraits*.*',
1449 '*TypeConverter*.*',
1450 ]
1451
scottmg7a6ed5ba2016-11-04 18:22:041452 # These third_party directories do not contain IPCs, but contain files
1453 # matching the above patterns, which trigger false positives.
1454 exclude_paths = [
1455 'third_party/crashpad/*',
1456 ]
1457
dchenge07de812016-06-20 19:27:171458 # Dictionary mapping an OWNERS file path to Patterns.
1459 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1460 # rules ) to a PatternEntry.
1461 # PatternEntry is a dictionary with two keys:
1462 # - 'files': the files that are matched by this pattern
1463 # - 'rules': the per-file rules needed for this pattern
1464 # For example, if we expect OWNERS file to contain rules for *.mojom and
1465 # *_struct_traits*.*, Patterns might look like this:
1466 # {
1467 # '*.mojom': {
1468 # 'files': ...,
1469 # 'rules': [
1470 # 'per-file *.mojom=set noparent',
1471 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1472 # ],
1473 # },
1474 # '*_struct_traits*.*': {
1475 # 'files': ...,
1476 # 'rules': [
1477 # 'per-file *_struct_traits*.*=set noparent',
1478 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1479 # ],
1480 # },
1481 # }
1482 to_check = {}
1483
1484 # Iterate through the affected files to see what we actually need to check
1485 # for. We should only nag patch authors about per-file rules if a file in that
1486 # directory would match that pattern. If a directory only contains *.mojom
1487 # files and no *_messages*.h files, we should only nag about rules for
1488 # *.mojom files.
rockot51249332016-06-23 16:32:251489 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171490 for pattern in file_patterns:
1491 if input_api.fnmatch.fnmatch(
1492 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041493 skip = False
1494 for exclude in exclude_paths:
1495 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1496 skip = True
1497 break
1498 if skip:
1499 continue
dchenge07de812016-06-20 19:27:171500 owners_file = input_api.os_path.join(
1501 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1502 if owners_file not in to_check:
1503 to_check[owners_file] = {}
1504 if pattern not in to_check[owners_file]:
1505 to_check[owners_file][pattern] = {
1506 'files': [],
1507 'rules': [
1508 'per-file %s=set noparent' % pattern,
1509 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1510 ]
1511 }
1512 to_check[owners_file][pattern]['files'].append(f)
1513 break
1514
1515 # Now go through the OWNERS files we collected, filtering out rules that are
1516 # already present in that OWNERS file.
1517 for owners_file, patterns in to_check.iteritems():
1518 try:
1519 with file(owners_file) as f:
1520 lines = set(f.read().splitlines())
1521 for entry in patterns.itervalues():
1522 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1523 ]
1524 except IOError:
1525 # No OWNERS file, so all the rules are definitely missing.
1526 continue
1527
1528 # All the remaining lines weren't found in OWNERS files, so emit an error.
1529 errors = []
1530 for owners_file, patterns in to_check.iteritems():
1531 missing_lines = []
1532 files = []
1533 for pattern, entry in patterns.iteritems():
1534 missing_lines.extend(entry['rules'])
1535 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1536 if missing_lines:
1537 errors.append(
Daniel Cheng52111692017-06-14 08:00:591538 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171539 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1540
1541 results = []
1542 if errors:
vabrf5ce3bf92016-07-11 14:52:411543 if input_api.is_committing:
1544 output = output_api.PresubmitError
1545 else:
1546 output = output_api.PresubmitPromptWarning
1547 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591548 'Found OWNERS files that need to be updated for IPC security ' +
1549 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171550 long_text='\n\n'.join(errors)))
1551
1552 return results
1553
1554
jbriance9e12f162016-11-25 07:57:501555def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311556 """Checks that added or removed lines in non third party affected
1557 header files do not lead to new useless class or struct forward
1558 declaration.
jbriance9e12f162016-11-25 07:57:501559 """
1560 results = []
1561 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1562 input_api.re.MULTILINE)
1563 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1564 input_api.re.MULTILINE)
1565 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311566 if (f.LocalPath().startswith('third_party') and
1567 not f.LocalPath().startswith('third_party/WebKit') and
1568 not f.LocalPath().startswith('third_party\\WebKit')):
1569 continue
1570
jbriance9e12f162016-11-25 07:57:501571 if not f.LocalPath().endswith('.h'):
1572 continue
1573
1574 contents = input_api.ReadFile(f)
1575 fwd_decls = input_api.re.findall(class_pattern, contents)
1576 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1577
1578 useless_fwd_decls = []
1579 for decl in fwd_decls:
1580 count = sum(1 for _ in input_api.re.finditer(
1581 r'\b%s\b' % input_api.re.escape(decl), contents))
1582 if count == 1:
1583 useless_fwd_decls.append(decl)
1584
1585 if not useless_fwd_decls:
1586 continue
1587
1588 for line in f.GenerateScmDiff().splitlines():
1589 if (line.startswith('-') and not line.startswith('--') or
1590 line.startswith('+') and not line.startswith('++')):
1591 for decl in useless_fwd_decls:
1592 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1593 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241594 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501595 (f.LocalPath(), decl)))
1596 useless_fwd_decls.remove(decl)
1597
1598 return results
1599
1600
dskiba88634f4e2015-08-14 23:03:291601def _CheckAndroidToastUsage(input_api, output_api):
1602 """Checks that code uses org.chromium.ui.widget.Toast instead of
1603 android.widget.Toast (Chromium Toast doesn't force hardware
1604 acceleration on low-end devices, saving memory).
1605 """
1606 toast_import_pattern = input_api.re.compile(
1607 r'^import android\.widget\.Toast;$')
1608
1609 errors = []
1610
1611 sources = lambda affected_file: input_api.FilterSourceFile(
1612 affected_file,
1613 black_list=(_EXCLUDED_PATHS +
1614 _TEST_CODE_EXCLUDED_PATHS +
1615 input_api.DEFAULT_BLACK_LIST +
1616 (r'^chromecast[\\\/].*',
1617 r'^remoting[\\\/].*')),
1618 white_list=(r'.*\.java$',))
1619
1620 for f in input_api.AffectedSourceFiles(sources):
1621 for line_num, line in f.ChangedContents():
1622 if toast_import_pattern.search(line):
1623 errors.append("%s:%d" % (f.LocalPath(), line_num))
1624
1625 results = []
1626
1627 if errors:
1628 results.append(output_api.PresubmitError(
1629 'android.widget.Toast usage is detected. Android toasts use hardware'
1630 ' acceleration, and can be\ncostly on low-end devices. Please use'
1631 ' org.chromium.ui.widget.Toast instead.\n'
1632 'Contact [email protected] if you have any questions.',
1633 errors))
1634
1635 return results
1636
1637
dgnaa68d5e2015-06-10 10:08:221638def _CheckAndroidCrLogUsage(input_api, output_api):
1639 """Checks that new logs using org.chromium.base.Log:
1640 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511641 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221642 """
pkotwicza1dd0b002016-05-16 14:41:041643
torne89540622017-03-24 19:41:301644 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041645 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301646 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041647 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301648 # WebView license viewer code cannot depend on //base; used in stub APK.
1649 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1650 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041651 ]
1652
dgnaa68d5e2015-06-10 10:08:221653 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121654 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1655 class_in_base_pattern = input_api.re.compile(
1656 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1657 has_some_log_import_pattern = input_api.re.compile(
1658 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221659 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121660 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221661 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511662 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221663 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221664
Vincent Scheib16d7b272015-09-15 18:09:071665 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221666 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041667 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1668 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121669
dgnaa68d5e2015-06-10 10:08:221670 tag_decl_errors = []
1671 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121672 tag_errors = []
dgn38736db2015-09-18 19:20:511673 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121674 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221675
1676 for f in input_api.AffectedSourceFiles(sources):
1677 file_content = input_api.ReadFile(f)
1678 has_modified_logs = False
1679
1680 # Per line checks
dgn87d9fb62015-06-12 09:15:121681 if (cr_log_import_pattern.search(file_content) or
1682 (class_in_base_pattern.search(file_content) and
1683 not has_some_log_import_pattern.search(file_content))):
1684 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221685 for line_num, line in f.ChangedContents():
1686
1687 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121688 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221689 if match:
1690 has_modified_logs = True
1691
1692 # Make sure it uses "TAG"
1693 if not match.group('tag') == 'TAG':
1694 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121695 else:
1696 # Report non cr Log function calls in changed lines
1697 for line_num, line in f.ChangedContents():
1698 if log_call_pattern.search(line):
1699 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221700
1701 # Per file checks
1702 if has_modified_logs:
1703 # Make sure the tag is using the "cr" prefix and is not too long
1704 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511705 tag_name = match.group('name') if match else None
1706 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221707 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511708 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221709 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511710 elif '.' in tag_name:
1711 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221712
1713 results = []
1714 if tag_decl_errors:
1715 results.append(output_api.PresubmitPromptWarning(
1716 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511717 '"private static final String TAG = "<package tag>".\n'
1718 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221719 tag_decl_errors))
1720
1721 if tag_length_errors:
1722 results.append(output_api.PresubmitError(
1723 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511724 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221725 tag_length_errors))
1726
1727 if tag_errors:
1728 results.append(output_api.PresubmitPromptWarning(
1729 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1730 tag_errors))
1731
dgn87d9fb62015-06-12 09:15:121732 if util_log_errors:
dgn4401aa52015-04-29 16:26:171733 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121734 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1735 util_log_errors))
1736
dgn38736db2015-09-18 19:20:511737 if tag_with_dot_errors:
1738 results.append(output_api.PresubmitPromptWarning(
1739 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1740 tag_with_dot_errors))
1741
dgn4401aa52015-04-29 16:26:171742 return results
1743
1744
yolandyan45001472016-12-21 21:12:421745def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1746 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1747 deprecated_annotation_import_pattern = input_api.re.compile(
1748 r'^import android\.test\.suitebuilder\.annotation\..*;',
1749 input_api.re.MULTILINE)
1750 sources = lambda x: input_api.FilterSourceFile(
1751 x, white_list=(r'.*\.java$',), black_list=None)
1752 errors = []
1753 for f in input_api.AffectedFiles(sources):
1754 for line_num, line in f.ChangedContents():
1755 if deprecated_annotation_import_pattern.search(line):
1756 errors.append("%s:%d" % (f.LocalPath(), line_num))
1757
1758 results = []
1759 if errors:
1760 results.append(output_api.PresubmitError(
1761 'Annotations in android.test.suitebuilder.annotation have been'
1762 ' deprecated since API level 24. Please use android.support.test.filters'
1763 ' from //third_party/android_support_test_runner:runner_java instead.'
1764 ' Contact [email protected] if you have any questions.', errors))
1765 return results
1766
1767
agrieve7b6479d82015-10-07 14:24:221768def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1769 """Checks if MDPI assets are placed in a correct directory."""
1770 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1771 ('/res/drawable/' in f.LocalPath() or
1772 '/res/drawable-ldrtl/' in f.LocalPath()))
1773 errors = []
1774 for f in input_api.AffectedFiles(include_deletes=False,
1775 file_filter=file_filter):
1776 errors.append(' %s' % f.LocalPath())
1777
1778 results = []
1779 if errors:
1780 results.append(output_api.PresubmitError(
1781 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1782 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1783 '/res/drawable-ldrtl/.\n'
1784 'Contact [email protected] if you have questions.', errors))
1785 return results
1786
1787
agrievef32bcc72016-04-04 14:57:401788class PydepsChecker(object):
1789 def __init__(self, input_api, pydeps_files):
1790 self._file_cache = {}
1791 self._input_api = input_api
1792 self._pydeps_files = pydeps_files
1793
1794 def _LoadFile(self, path):
1795 """Returns the list of paths within a .pydeps file relative to //."""
1796 if path not in self._file_cache:
1797 with open(path) as f:
1798 self._file_cache[path] = f.read()
1799 return self._file_cache[path]
1800
1801 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1802 """Returns an interable of paths within the .pydep, relativized to //."""
1803 os_path = self._input_api.os_path
1804 pydeps_dir = os_path.dirname(pydeps_path)
1805 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1806 if not l.startswith('*'))
1807 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1808
1809 def _CreateFilesToPydepsMap(self):
1810 """Returns a map of local_path -> list_of_pydeps."""
1811 ret = {}
1812 for pydep_local_path in self._pydeps_files:
1813 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1814 ret.setdefault(path, []).append(pydep_local_path)
1815 return ret
1816
1817 def ComputeAffectedPydeps(self):
1818 """Returns an iterable of .pydeps files that might need regenerating."""
1819 affected_pydeps = set()
1820 file_to_pydeps_map = None
1821 for f in self._input_api.AffectedFiles(include_deletes=True):
1822 local_path = f.LocalPath()
1823 if local_path == 'DEPS':
1824 return self._pydeps_files
1825 elif local_path.endswith('.pydeps'):
1826 if local_path in self._pydeps_files:
1827 affected_pydeps.add(local_path)
1828 elif local_path.endswith('.py'):
1829 if file_to_pydeps_map is None:
1830 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1831 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1832 return affected_pydeps
1833
1834 def DetermineIfStale(self, pydeps_path):
1835 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411836 import difflib
agrievef32bcc72016-04-04 14:57:401837 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1838 cmd = old_pydeps_data[1][1:].strip()
1839 new_pydeps_data = self._input_api.subprocess.check_output(
1840 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411841 old_contents = old_pydeps_data[2:]
1842 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401843 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411844 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401845
1846
1847def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1848 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001849 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281850 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1851 # Mac, so skip it on other platforms.
1852 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001853 return []
agrievef32bcc72016-04-04 14:57:401854 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1855 is_android = input_api.os_path.exists('third_party/android_tools')
1856 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1857 results = []
1858 # First, check for new / deleted .pydeps.
1859 for f in input_api.AffectedFiles(include_deletes=True):
1860 if f.LocalPath().endswith('.pydeps'):
1861 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1862 results.append(output_api.PresubmitError(
1863 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1864 'remove %s' % f.LocalPath()))
1865 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1866 results.append(output_api.PresubmitError(
1867 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1868 'include %s' % f.LocalPath()))
1869
1870 if results:
1871 return results
1872
1873 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1874
1875 for pydep_path in checker.ComputeAffectedPydeps():
1876 try:
phajdan.jr0d9878552016-11-04 10:49:411877 result = checker.DetermineIfStale(pydep_path)
1878 if result:
1879 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401880 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411881 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1882 'To regenerate, run:\n\n %s' %
1883 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401884 except input_api.subprocess.CalledProcessError as error:
1885 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1886 long_text=error.output)]
1887
1888 return results
1889
1890
glidere61efad2015-02-18 17:39:431891def _CheckSingletonInHeaders(input_api, output_api):
1892 """Checks to make sure no header files have |Singleton<|."""
1893 def FileFilter(affected_file):
1894 # It's ok for base/memory/singleton.h to have |Singleton<|.
1895 black_list = (_EXCLUDED_PATHS +
1896 input_api.DEFAULT_BLACK_LIST +
1897 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1898 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1899
sergeyu34d21222015-09-16 00:11:441900 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431901 files = []
1902 for f in input_api.AffectedSourceFiles(FileFilter):
1903 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1904 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1905 contents = input_api.ReadFile(f)
1906 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241907 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431908 pattern.search(line)):
1909 files.append(f)
1910 break
1911
1912 if files:
yolandyandaabc6d2016-04-18 18:29:391913 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441914 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431915 'Please move them to an appropriate source file so that the ' +
1916 'template gets instantiated in a single compilation unit.',
1917 files) ]
1918 return []
1919
1920
[email protected]fd20b902014-05-09 02:14:531921_DEPRECATED_CSS = [
1922 # Values
1923 ( "-webkit-box", "flex" ),
1924 ( "-webkit-inline-box", "inline-flex" ),
1925 ( "-webkit-flex", "flex" ),
1926 ( "-webkit-inline-flex", "inline-flex" ),
1927 ( "-webkit-min-content", "min-content" ),
1928 ( "-webkit-max-content", "max-content" ),
1929
1930 # Properties
1931 ( "-webkit-background-clip", "background-clip" ),
1932 ( "-webkit-background-origin", "background-origin" ),
1933 ( "-webkit-background-size", "background-size" ),
1934 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441935 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531936
1937 # Functions
1938 ( "-webkit-gradient", "gradient" ),
1939 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1940 ( "-webkit-linear-gradient", "linear-gradient" ),
1941 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1942 ( "-webkit-radial-gradient", "radial-gradient" ),
1943 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1944]
1945
dbeam1ec68ac2016-12-15 05:22:241946def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531947 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251948 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341949 documentation and iOS CSS for dom distiller
1950 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251951 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531952 results = []
dbeam070cfe62014-10-22 06:44:021953 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251954 black_list = (_EXCLUDED_PATHS +
1955 _TEST_CODE_EXCLUDED_PATHS +
1956 input_api.DEFAULT_BLACK_LIST +
1957 (r"^chrome/common/extensions/docs",
1958 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341959 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:441960 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251961 r"^native_client_sdk"))
1962 file_filter = lambda f: input_api.FilterSourceFile(
1963 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531964 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1965 for line_num, line in fpath.ChangedContents():
1966 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021967 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531968 results.append(output_api.PresubmitError(
1969 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1970 (fpath.LocalPath(), line_num, deprecated_value, value)))
1971 return results
1972
mohan.reddyf21db962014-10-16 12:26:471973
dbeam070cfe62014-10-22 06:44:021974_DEPRECATED_JS = [
1975 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1976 ( "__defineGetter__", "Object.defineProperty" ),
1977 ( "__defineSetter__", "Object.defineProperty" ),
1978]
1979
dbeam1ec68ac2016-12-15 05:22:241980def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:021981 """Make sure that we don't use deprecated JS in Chrome code."""
1982 results = []
1983 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1984 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1985 input_api.DEFAULT_BLACK_LIST)
1986 file_filter = lambda f: input_api.FilterSourceFile(
1987 f, white_list=file_inclusion_pattern, black_list=black_list)
1988 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1989 for lnum, line in fpath.ChangedContents():
1990 for (deprecated, replacement) in _DEPRECATED_JS:
1991 if deprecated in line:
1992 results.append(output_api.PresubmitError(
1993 "%s:%d: Use of deprecated JS %s, use %s instead" %
1994 (fpath.LocalPath(), lnum, deprecated, replacement)))
1995 return results
1996
1997
dbeam1ec68ac2016-12-15 05:22:241998def _CheckForRiskyJsFeatures(input_api, output_api):
1999 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2000 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2001
2002 arrow_lines = []
2003 for f in input_api.AffectedFiles(file_filter=file_filter):
2004 for lnum, line in f.ChangedContents():
2005 if ' => ' in line:
2006 arrow_lines.append((f.LocalPath(), lnum))
2007
2008 if not arrow_lines:
2009 return []
2010
2011 return [output_api.PresubmitPromptWarning("""
2012Use of => operator detected in:
2013%s
2014Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2015https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2016""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2017
2018
rlanday6802cf632017-05-30 17:48:362019def _CheckForRelativeIncludes(input_api, output_api):
2020 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2021 import sys
2022 original_sys_path = sys.path
2023 try:
2024 sys.path = sys.path + [input_api.os_path.join(
2025 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2026 from cpp_checker import CppChecker
2027 finally:
2028 # Restore sys.path to what it was before.
2029 sys.path = original_sys_path
2030
2031 bad_files = {}
2032 for f in input_api.AffectedFiles(include_deletes=False):
2033 if (f.LocalPath().startswith('third_party') and
2034 not f.LocalPath().startswith('third_party/WebKit') and
2035 not f.LocalPath().startswith('third_party\\WebKit')):
2036 continue
2037
2038 if not CppChecker.IsCppFile(f.LocalPath()):
2039 continue
2040
2041 relative_includes = [line for line_num, line in f.ChangedContents()
2042 if "#include" in line and "../" in line]
2043 if not relative_includes:
2044 continue
2045 bad_files[f.LocalPath()] = relative_includes
2046
2047 if not bad_files:
2048 return []
2049
2050 error_descriptions = []
2051 for file_path, bad_lines in bad_files.iteritems():
2052 error_description = file_path
2053 for line in bad_lines:
2054 error_description += '\n ' + line
2055 error_descriptions.append(error_description)
2056
2057 results = []
2058 results.append(output_api.PresubmitError(
2059 'You added one or more relative #include paths (including "../").\n'
2060 'These shouldn\'t be used because they can be used to include headers\n'
2061 'from code that\'s not correctly specified as a dependency in the\n'
2062 'relevant BUILD.gn file(s).',
2063 error_descriptions))
2064
2065 return results
2066
dgnaa68d5e2015-06-10 10:08:222067def _AndroidSpecificOnUploadChecks(input_api, output_api):
2068 """Groups checks that target android code."""
2069 results = []
dgnaa68d5e2015-06-10 10:08:222070 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222071 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292072 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422073 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222074 return results
2075
2076
[email protected]22c9bd72011-03-27 16:47:392077def _CommonChecks(input_api, output_api):
2078 """Checks common to both upload and commit."""
2079 results = []
2080 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382081 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542082 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582083 results.extend(
2084 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192085 results.extend(
[email protected]760deea2013-12-10 19:33:492086 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542087 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182088 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522089 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222090 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442091 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592092 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062093 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122094 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182095 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222096 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302097 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492098 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032099 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492100 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442101 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272102 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072103 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542104 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442105 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392106 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552107 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042108 results.extend(
2109 input_api.canned_checks.CheckChangeHasNoTabs(
2110 input_api,
2111 output_api,
2112 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402113 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162114 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082115 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242116 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2117 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472118 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042119 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232120 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432121 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402122 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152123 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172124 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502125 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242126 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362127 results.extend(_CheckForRelativeIncludes(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242128
2129 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2130 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2131 input_api, output_api,
2132 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382133 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392134 return results
[email protected]1f7b4172010-01-28 01:17:342135
[email protected]b337cb5b2011-01-23 21:24:052136
[email protected]b8079ae4a2012-12-05 19:56:492137def _CheckPatchFiles(input_api, output_api):
2138 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2139 if f.LocalPath().endswith(('.orig', '.rej'))]
2140 if problems:
2141 return [output_api.PresubmitError(
2142 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032143 else:
2144 return []
[email protected]b8079ae4a2012-12-05 19:56:492145
2146
Kent Tamura5a8755d2017-06-29 23:37:072147def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212148 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2149 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2150 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072151 include_re = input_api.re.compile(
2152 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2153 extension_re = input_api.re.compile(r'\.[a-z]+$')
2154 errors = []
2155 for f in input_api.AffectedFiles():
2156 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2157 continue
2158 found_line_number = None
2159 found_macro = None
2160 for line_num, line in f.ChangedContents():
2161 match = macro_re.search(line)
2162 if match:
2163 found_line_number = line_num
2164 found_macro = match.group(2)
2165 break
2166 if not found_line_number:
2167 continue
2168
2169 found_include = False
2170 for line in f.NewContents():
2171 if include_re.search(line):
2172 found_include = True
2173 break
2174 if found_include:
2175 continue
2176
2177 if not f.LocalPath().endswith('.h'):
2178 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2179 try:
2180 content = input_api.ReadFile(primary_header_path, 'r')
2181 if include_re.search(content):
2182 continue
2183 except IOError:
2184 pass
2185 errors.append('%s:%d %s macro is used without including build/'
2186 'build_config.h.'
2187 % (f.LocalPath(), found_line_number, found_macro))
2188 if errors:
2189 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2190 return []
2191
2192
[email protected]b00342e7f2013-03-26 16:21:542193def _DidYouMeanOSMacro(bad_macro):
2194 try:
2195 return {'A': 'OS_ANDROID',
2196 'B': 'OS_BSD',
2197 'C': 'OS_CHROMEOS',
2198 'F': 'OS_FREEBSD',
2199 'L': 'OS_LINUX',
2200 'M': 'OS_MACOSX',
2201 'N': 'OS_NACL',
2202 'O': 'OS_OPENBSD',
2203 'P': 'OS_POSIX',
2204 'S': 'OS_SOLARIS',
2205 'W': 'OS_WIN'}[bad_macro[3].upper()]
2206 except KeyError:
2207 return ''
2208
2209
2210def _CheckForInvalidOSMacrosInFile(input_api, f):
2211 """Check for sensible looking, totally invalid OS macros."""
2212 preprocessor_statement = input_api.re.compile(r'^\s*#')
2213 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2214 results = []
2215 for lnum, line in f.ChangedContents():
2216 if preprocessor_statement.search(line):
2217 for match in os_macro.finditer(line):
2218 if not match.group(1) in _VALID_OS_MACROS:
2219 good = _DidYouMeanOSMacro(match.group(1))
2220 did_you_mean = ' (did you mean %s?)' % good if good else ''
2221 results.append(' %s:%d %s%s' % (f.LocalPath(),
2222 lnum,
2223 match.group(1),
2224 did_you_mean))
2225 return results
2226
2227
2228def _CheckForInvalidOSMacros(input_api, output_api):
2229 """Check all affected files for invalid OS macros."""
2230 bad_macros = []
2231 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472232 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542233 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2234
2235 if not bad_macros:
2236 return []
2237
2238 return [output_api.PresubmitError(
2239 'Possibly invalid OS macro[s] found. Please fix your code\n'
2240 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2241
lliabraa35bab3932014-10-01 12:16:442242
2243def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2244 """Check all affected files for invalid "if defined" macros."""
2245 ALWAYS_DEFINED_MACROS = (
2246 "TARGET_CPU_PPC",
2247 "TARGET_CPU_PPC64",
2248 "TARGET_CPU_68K",
2249 "TARGET_CPU_X86",
2250 "TARGET_CPU_ARM",
2251 "TARGET_CPU_MIPS",
2252 "TARGET_CPU_SPARC",
2253 "TARGET_CPU_ALPHA",
2254 "TARGET_IPHONE_SIMULATOR",
2255 "TARGET_OS_EMBEDDED",
2256 "TARGET_OS_IPHONE",
2257 "TARGET_OS_MAC",
2258 "TARGET_OS_UNIX",
2259 "TARGET_OS_WIN32",
2260 )
2261 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2262 results = []
2263 for lnum, line in f.ChangedContents():
2264 for match in ifdef_macro.finditer(line):
2265 if match.group(1) in ALWAYS_DEFINED_MACROS:
2266 always_defined = ' %s is always defined. ' % match.group(1)
2267 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2268 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2269 lnum,
2270 always_defined,
2271 did_you_mean))
2272 return results
2273
2274
2275def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2276 """Check all affected files for invalid "if defined" macros."""
2277 bad_macros = []
2278 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212279 if f.LocalPath().startswith('third_party/sqlite/'):
2280 continue
lliabraa35bab3932014-10-01 12:16:442281 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2282 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2283
2284 if not bad_macros:
2285 return []
2286
2287 return [output_api.PresubmitError(
2288 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2289 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2290 bad_macros)]
2291
2292
mlamouria82272622014-09-16 18:45:042293def _CheckForIPCRules(input_api, output_api):
2294 """Check for same IPC rules described in
2295 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2296 """
2297 base_pattern = r'IPC_ENUM_TRAITS\('
2298 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2299 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2300
2301 problems = []
2302 for f in input_api.AffectedSourceFiles(None):
2303 local_path = f.LocalPath()
2304 if not local_path.endswith('.h'):
2305 continue
2306 for line_number, line in f.ChangedContents():
2307 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2308 problems.append(
2309 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2310
2311 if problems:
2312 return [output_api.PresubmitPromptWarning(
2313 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2314 else:
2315 return []
2316
[email protected]b00342e7f2013-03-26 16:21:542317
mostynbb639aca52015-01-07 20:31:232318def _CheckForWindowsLineEndings(input_api, output_api):
2319 """Check source code and known ascii text files for Windows style line
2320 endings.
2321 """
earthdok1b5e0ee2015-03-10 15:19:102322 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232323
2324 file_inclusion_pattern = (
2325 known_text_files,
2326 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2327 )
2328
2329 filter = lambda f: input_api.FilterSourceFile(
2330 f, white_list=file_inclusion_pattern, black_list=None)
2331 files = [f.LocalPath() for f in
2332 input_api.AffectedSourceFiles(filter)]
2333
2334 problems = []
2335
2336 for file in files:
2337 fp = open(file, 'r')
2338 for line in fp:
2339 if line.endswith('\r\n'):
2340 problems.append(file)
2341 break
2342 fp.close()
2343
2344 if problems:
2345 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2346 'these files to contain Windows style line endings?\n' +
2347 '\n'.join(problems))]
2348
2349 return []
2350
2351
pastarmovj89f7ee12016-09-20 14:58:132352def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2353 lint_filters=None, verbose_level=None):
2354 """Checks that all source files use SYSLOG properly."""
2355 syslog_files = []
2356 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562357 for line_number, line in f.ChangedContents():
2358 if 'SYSLOG' in line:
2359 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2360
pastarmovj89f7ee12016-09-20 14:58:132361 if syslog_files:
2362 return [output_api.PresubmitPromptWarning(
2363 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2364 ' calls.\nFiles to check:\n', items=syslog_files)]
2365 return []
2366
2367
[email protected]1f7b4172010-01-28 01:17:342368def CheckChangeOnUpload(input_api, output_api):
2369 results = []
2370 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472371 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282372 results.extend(
jam93a6ee792017-02-08 23:59:222373 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192374 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222375 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132376 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162377 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542378 return results
[email protected]ca8d19842009-02-19 16:33:122379
2380
[email protected]1bfb8322014-04-23 01:02:412381def GetTryServerMasterForBot(bot):
2382 """Returns the Try Server master for the given bot.
2383
[email protected]0bb112362014-07-26 04:38:322384 It tries to guess the master from the bot name, but may still fail
2385 and return None. There is no longer a default master.
2386 """
2387 # Potentially ambiguous bot names are listed explicitly.
2388 master_map = {
tandriie5587792016-07-14 00:34:502389 'chromium_presubmit': 'master.tryserver.chromium.linux',
2390 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412391 }
[email protected]0bb112362014-07-26 04:38:322392 master = master_map.get(bot)
2393 if not master:
wnwen4fbaab82016-05-25 12:54:362394 if 'android' in bot:
tandriie5587792016-07-14 00:34:502395 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362396 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502397 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322398 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502399 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322400 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502401 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322402 return master
[email protected]1bfb8322014-04-23 01:02:412403
2404
Paweł Hajdan, Jr55083782014-12-19 20:32:562405def GetDefaultTryConfigs(bots):
2406 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012407 """
2408
Paweł Hajdan, Jr55083782014-12-19 20:32:562409 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412410
2411 # Build up the mapping from tryserver master to bot/test.
2412 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562413 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412414 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2415 return out
[email protected]38c6a512013-12-18 23:48:012416
2417
[email protected]ca8d19842009-02-19 16:33:122418def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542419 results = []
[email protected]1f7b4172010-01-28 01:17:342420 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542421 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272422 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342423 input_api,
2424 output_api,
[email protected]2fdd1f362013-01-16 03:56:032425 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272426
jam93a6ee792017-02-08 23:59:222427 results.extend(
2428 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542429 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2430 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412431 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2432 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542433 return results