blob: da193b4867c4afdfdec0465e440b8be0e09f68c5 [file] [log] [blame]
andrew@webrtc.org2442de12012-01-23 17:45:41 +00001# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
2#
3# Use of this source code is governed by a BSD-style license
4# that can be found in the LICENSE file in the root of the source
5# tree. An additional intellectual property rights grant can be found
6# in the file PATENTS. All contributing project authors may
7# be found in the AUTHORS file in the root of the source tree.
niklase@google.comda159d62011-05-30 11:51:34 +00008
kjellander986ee082015-06-16 04:32:13 -07009import json
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +000010import os
kjellander986ee082015-06-16 04:32:13 -070011import platform
kjellander@webrtc.org85759802013-10-22 16:47:40 +000012import re
kjellander986ee082015-06-16 04:32:13 -070013import subprocess
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +000014import sys
kjellander@webrtc.org85759802013-10-22 16:47:40 +000015
16
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +010017# Directories that will be scanned by cpplint by the presubmit script.
18CPPLINT_DIRS = [
Fredrik Solenbergea073732015-12-01 11:26:34 +010019 'webrtc/audio',
20 'webrtc/call',
jbauch0f2e9392015-12-10 03:11:42 -080021 'webrtc/common_video',
jbauch70625e52015-12-09 14:18:14 -080022 'webrtc/examples',
aleloidf9e4d92016-08-08 10:26:09 -070023 'webrtc/modules/audio_mixer',
jbauchf91e6d02016-01-24 23:05:21 -080024 'webrtc/modules/bitrate_controller',
Stefan Holmer80e12072016-02-23 13:30:42 +010025 'webrtc/modules/congestion_controller',
jbauchd2a22962016-02-08 23:18:25 -080026 'webrtc/modules/pacing',
terelius8f09f172015-12-15 00:51:54 -080027 'webrtc/modules/remote_bitrate_estimator',
danilchap377b5e62015-12-15 04:33:44 -080028 'webrtc/modules/rtp_rtcp',
philipel5908c712015-12-21 08:23:20 -080029 'webrtc/modules/video_coding',
mflodman88eeac42015-12-08 09:21:28 +010030 'webrtc/modules/video_processing',
jbauch0f2e9392015-12-10 03:11:42 -080031 'webrtc/tools',
mflodmand1590b22015-12-09 07:07:59 -080032 'webrtc/video',
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +010033]
34
jbauchc4e3ead2016-02-19 00:25:55 -080035# These filters will always be removed, even if the caller specifies a filter
36# set, as they are problematic or broken in some way.
37#
38# Justifications for each filter:
39# - build/c++11 : Rvalue ref checks are unreliable (false positives),
40# include file and feature blacklists are
41# google3-specific.
kjellandere5a87a52016-04-27 02:32:12 -070042# - whitespace/operators: Same as above (doesn't seem sufficient to eliminate
43# all move-related errors).
jbauchc4e3ead2016-02-19 00:25:55 -080044BLACKLIST_LINT_FILTERS = [
45 '-build/c++11',
kjellandere5a87a52016-04-27 02:32:12 -070046 '-whitespace/operators',
jbauchc4e3ead2016-02-19 00:25:55 -080047]
48
kjellanderfd595232015-12-04 02:44:09 -080049# List of directories of "supported" native APIs. That means changes to headers
50# will be done in a compatible way following this scheme:
51# 1. Non-breaking changes are made.
52# 2. The old APIs as marked as deprecated (with comments).
53# 3. Deprecation is announced to discuss-webrtc@googlegroups.com and
54# webrtc-users@google.com (internal list).
55# 4. (later) The deprecated APIs are removed.
kjellander53047c92015-12-02 23:56:14 -080056NATIVE_API_DIRS = (
kjellander53047c92015-12-02 23:56:14 -080057 'webrtc',
kjellanderdd705472016-06-09 11:17:27 -070058 'webrtc/api',
59 'webrtc/media',
kjellander53047c92015-12-02 23:56:14 -080060 'webrtc/modules/audio_device/include',
kjellanderdd705472016-06-09 11:17:27 -070061 'webrtc/pc',
62)
63# These directories should not be used but are maintained only to avoid breaking
64# some legacy downstream code.
65LEGACY_API_DIRS = (
kjellanderdd705472016-06-09 11:17:27 -070066 'webrtc/base',
67 'webrtc/common_audio/include',
68 'webrtc/modules/audio_coding/include',
69 'webrtc/modules/audio_conference_mixer/include',
kjellander53047c92015-12-02 23:56:14 -080070 'webrtc/modules/audio_processing/include',
71 'webrtc/modules/bitrate_controller/include',
Stefan Holmer80e12072016-02-23 13:30:42 +010072 'webrtc/modules/congestion_controller/include',
kjellander53047c92015-12-02 23:56:14 -080073 'webrtc/modules/include',
74 'webrtc/modules/remote_bitrate_estimator/include',
75 'webrtc/modules/rtp_rtcp/include',
kjellanderdd705472016-06-09 11:17:27 -070076 'webrtc/modules/rtp_rtcp/source',
kjellander53047c92015-12-02 23:56:14 -080077 'webrtc/modules/utility/include',
78 'webrtc/modules/video_coding/codecs/h264/include',
79 'webrtc/modules/video_coding/codecs/i420/include',
80 'webrtc/modules/video_coding/codecs/vp8/include',
81 'webrtc/modules/video_coding/codecs/vp9/include',
82 'webrtc/modules/video_coding/include',
kjellanderdd705472016-06-09 11:17:27 -070083 'webrtc/system_wrappers/include',
kjellander53047c92015-12-02 23:56:14 -080084 'webrtc/voice_engine/include',
85)
kjellanderdd705472016-06-09 11:17:27 -070086API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-02 23:56:14 -080087
88
89def _VerifyNativeApiHeadersListIsValid(input_api, output_api):
90 """Ensures the list of native API header directories is up to date."""
91 non_existing_paths = []
92 native_api_full_paths = [
93 input_api.os_path.join(input_api.PresubmitLocalPath(),
kjellanderdd705472016-06-09 11:17:27 -070094 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-02 23:56:14 -080095 for path in native_api_full_paths:
96 if not os.path.isdir(path):
97 non_existing_paths.append(path)
98 if non_existing_paths:
99 return [output_api.PresubmitError(
100 'Directories to native API headers have changed which has made the '
101 'list in PRESUBMIT.py outdated.\nPlease update it to the current '
102 'location of our native APIs.',
103 non_existing_paths)]
104 return []
105
kwibergeb133022016-04-07 07:41:48 -0700106api_change_msg = """
107You seem to be changing native API header files. Please make sure that you:
108 1. Make compatible changes that don't break existing clients.
109 2. Mark the old stuff as deprecated.
110 3. Create a timeline and plan for when the deprecated stuff will be
111 removed. (The amount of time we give users to change their code
112 should be informed by how much work it is for them. If they just
113 need to replace one name with another or something equally
114 simple, 1-2 weeks might be good; if they need to do serious work,
115 up to 3 months may be called for.)
116 4. Update/inform existing downstream code owners to stop using the
117 deprecated stuff. (Send announcements to
118 discuss-webrtc@googlegroups.com and webrtc-users@google.com.)
119 5. Remove the deprecated stuff, once the agreed-upon amount of time
120 has passed.
121Related files:
122"""
kjellander53047c92015-12-02 23:56:14 -0800123
124def _CheckNativeApiHeaderChanges(input_api, output_api):
125 """Checks to remind proper changing of native APIs."""
126 files = []
127 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
128 if f.LocalPath().endswith('.h'):
kjellanderdd705472016-06-09 11:17:27 -0700129 for path in API_DIRS:
kjellander53047c92015-12-02 23:56:14 -0800130 if os.path.dirname(f.LocalPath()) == path:
131 files.append(f)
132
133 if files:
kwibergeb133022016-04-07 07:41:48 -0700134 return [output_api.PresubmitNotifyResult(api_change_msg, files)]
kjellander53047c92015-12-02 23:56:14 -0800135 return []
136
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100137
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000138def _CheckNoIOStreamInHeaders(input_api, output_api):
139 """Checks to make sure no .h files include <iostream>."""
140 files = []
141 pattern = input_api.re.compile(r'^#include\s*<iostream>',
142 input_api.re.MULTILINE)
143 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
144 if not f.LocalPath().endswith('.h'):
145 continue
146 contents = input_api.ReadFile(f)
147 if pattern.search(contents):
148 files.append(f)
149
150 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200151 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000152 'Do not #include <iostream> in header files, since it inserts static ' +
153 'initialization into every file including the header. Instead, ' +
154 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200155 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000156 return []
157
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000158
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000159def _CheckNoFRIEND_TEST(input_api, output_api):
160 """Make sure that gtest's FRIEND_TEST() macro is not used, the
161 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
162 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
163 problems = []
164
165 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
166 for f in input_api.AffectedFiles(file_filter=file_filter):
167 for line_num, line in f.ChangedContents():
168 if 'FRIEND_TEST(' in line:
169 problems.append(' %s:%d' % (f.LocalPath(), line_num))
170
171 if not problems:
172 return []
173 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
174 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
175 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
176
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000177
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100178def _IsLintWhitelisted(whitelist_dirs, file_path):
179 """ Checks if a file is whitelisted for lint check."""
180 for path in whitelist_dirs:
181 if os.path.dirname(file_path).startswith(path):
182 return True
183 return False
184
185
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000186def _CheckApprovedFilesLintClean(input_api, output_api,
187 source_file_filter=None):
188 """Checks that all new or whitelisted .cc and .h files pass cpplint.py.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000189 This check is based on _CheckChangeLintsClean in
190 depot_tools/presubmit_canned_checks.py but has less filters and only checks
191 added files."""
192 result = []
193
194 # Initialize cpplint.
195 import cpplint
196 # Access to a protected member _XX of a client class
197 # pylint: disable=W0212
198 cpplint._cpplint_state.ResetErrorCounts()
199
jbauchc4e3ead2016-02-19 00:25:55 -0800200 lint_filters = cpplint._Filters()
201 lint_filters.extend(BLACKLIST_LINT_FILTERS)
202 cpplint._SetFilters(','.join(lint_filters))
203
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100204 # Create a platform independent whitelist for the CPPLINT_DIRS.
205 whitelist_dirs = [input_api.os_path.join(*path.split('/'))
206 for path in CPPLINT_DIRS]
207
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000208 # Use the strictest verbosity level for cpplint.py (level 1) which is the
209 # default when running cpplint.py from command line.
210 # To make it possible to work with not-yet-converted code, we're only applying
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000211 # it to new (or moved/renamed) files and files listed in LINT_FOLDERS.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000212 verbosity_level = 1
213 files = []
214 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200215 # Note that moved/renamed files also count as added.
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100216 if f.Action() == 'A' or _IsLintWhitelisted(whitelist_dirs, f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000217 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000218
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000219 for file_name in files:
220 cpplint.ProcessFile(file_name, verbosity_level)
221
222 if cpplint._cpplint_state.error_count > 0:
223 if input_api.is_committing:
224 # TODO(kjellander): Change back to PresubmitError below when we're
225 # confident with the lint settings.
226 res_type = output_api.PresubmitPromptWarning
227 else:
228 res_type = output_api.PresubmitPromptWarning
229 result = [res_type('Changelist failed cpplint.py check.')]
230
231 return result
232
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000233def _CheckNoRtcBaseDeps(input_api, gyp_files, output_api):
234 pattern = input_api.re.compile(r"base.gyp:rtc_base\s*'")
235 violating_files = []
236 for f in gyp_files:
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000237 gyp_exceptions = (
maxmorinec623742016-09-15 05:11:55 -0700238 'audio_device.gypi',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000239 'base_tests.gyp',
240 'desktop_capture.gypi',
kjellander@webrtc.orge7237282015-02-26 11:12:17 +0000241 'p2p.gyp',
tkchin9eeb6242016-04-27 01:54:20 -0700242 'sdk.gyp',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000243 'webrtc_test_common.gyp',
244 'webrtc_tests.gypi',
245 )
246 if f.LocalPath().endswith(gyp_exceptions):
247 continue
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000248 contents = input_api.ReadFile(f)
249 if pattern.search(contents):
250 violating_files.append(f)
251 if violating_files:
252 return [output_api.PresubmitError(
253 'Depending on rtc_base is not allowed. Change your dependency to '
254 'rtc_base_approved and possibly sanitize and move the desired source '
255 'file(s) to rtc_base_approved.\nChanged GYP files:',
256 items=violating_files)]
257 return []
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000258
ehmaldonado5b1ba082016-09-02 05:51:08 -0700259def _CheckNoRtcBaseDepsGn(input_api, gn_files, output_api):
260 pattern = input_api.re.compile(r'base:rtc_base\s*"')
261 violating_files = []
262 for f in gn_files:
263 gn_exceptions = (
maxmorinec623742016-09-15 05:11:55 -0700264 os.path.join('audio_device', 'BUILD.gn'),
ehmaldonado5b1ba082016-09-02 05:51:08 -0700265 os.path.join('base_tests', 'BUILD.gn'),
266 os.path.join('desktop_capture', 'BUILD.gn'),
267 os.path.join('p2p', 'BUILD.gn'),
268 os.path.join('sdk', 'BUILD.gn'),
269 os.path.join('webrtc_test_common', 'BUILD.gn'),
270 os.path.join('webrtc_tests', 'BUILD.gn'),
271
272 # TODO(ehmaldonado): Clean up references to rtc_base in these files.
273 # See https://bugs.chromium.org/p/webrtc/issues/detail?id=3806
274 os.path.join('webrtc', 'BUILD.gn'),
275 os.path.join('xmllite', 'BUILD.gn'),
276 os.path.join('xmpp', 'BUILD.gn'),
277 os.path.join('modules', 'BUILD.gn'),
278 os.path.join('audio_device', 'BUILD.gn'),
279 os.path.join('pc', 'BUILD.gn'),
280 )
281 if f.LocalPath().endswith(gn_exceptions):
282 continue
283 contents = input_api.ReadFile(f)
284 if pattern.search(contents):
285 violating_files.append(f)
286 if violating_files:
287 return [output_api.PresubmitError(
288 'Depending on rtc_base is not allowed. Change your dependency to '
289 'rtc_base_approved and possibly sanitize and move the desired source '
290 'file(s) to rtc_base_approved.\nChanged GN files:',
291 items=violating_files)]
292 return []
293
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000294def _CheckNoSourcesAboveGyp(input_api, gyp_files, output_api):
295 # Disallow referencing source files with paths above the GYP file location.
kjellander@webrtc.org74290b92016-06-15 17:19:06 +0200296 source_pattern = input_api.re.compile(r'\'sources\'.*?\[(.*?)\]',
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000297 re.MULTILINE | re.DOTALL)
kjellander@webrtc.orga33f05e2015-01-29 14:29:45 +0000298 file_pattern = input_api.re.compile(r"'((\.\./.*?)|(<\(webrtc_root\).*?))'")
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000299 violating_gyp_files = set()
300 violating_source_entries = []
301 for gyp_file in gyp_files:
kjellanderc61635c2016-02-02 02:30:07 -0800302 if 'supplement.gypi' in gyp_file.LocalPath():
303 # Exclude supplement.gypi from this check, as the LSan and TSan
304 # suppression files are located in a different location.
305 continue
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000306 contents = input_api.ReadFile(gyp_file)
307 for source_block_match in source_pattern.finditer(contents):
kjellander@webrtc.orgc98f6f32015-03-04 07:08:11 +0000308 # Find all source list entries starting with ../ in the source block
309 # (exclude overrides entries).
kjellander@webrtc.org74290b92016-06-15 17:19:06 +0200310 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
311 source_file = file_list_match.group(1)
kjellander@webrtc.orgc98f6f32015-03-04 07:08:11 +0000312 if 'overrides/' not in source_file:
313 violating_source_entries.append(source_file)
314 violating_gyp_files.add(gyp_file)
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000315 if violating_gyp_files:
316 return [output_api.PresubmitError(
317 'Referencing source files above the directory of the GYP file is not '
318 'allowed. Please introduce new GYP targets and/or GYP files in the '
319 'proper location instead.\n'
320 'Invalid source entries:\n'
321 '%s\n'
322 'Violating GYP files:' % '\n'.join(violating_source_entries),
323 items=violating_gyp_files)]
324 return []
325
ehmaldonado5b1ba082016-09-02 05:51:08 -0700326def _CheckNoSourcesAboveGn(input_api, gn_files, output_api):
327 # Disallow referencing source files with paths above the GN file location.
328 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
329 re.MULTILINE | re.DOTALL)
330 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
331 violating_gn_files = set()
332 violating_source_entries = []
333 for gn_file in gn_files:
334 contents = input_api.ReadFile(gn_file)
335 for source_block_match in source_pattern.finditer(contents):
336 # Find all source list entries starting with ../ in the source block
337 # (exclude overrides entries).
338 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
339 source_file = file_list_match.group(1)
340 if 'overrides/' not in source_file:
341 violating_source_entries.append(source_file)
342 violating_gn_files.add(gn_file)
343 if violating_gn_files:
344 return [output_api.PresubmitError(
345 'Referencing source files above the directory of the GN file is not '
346 'allowed. Please introduce new GYP targets and/or GN files in the '
347 'proper location instead.\n'
348 'Invalid source entries:\n'
349 '%s\n'
350 'Violating GN files:' % '\n'.join(violating_source_entries),
351 items=violating_gn_files)]
352 return []
353
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000354def _CheckGypChanges(input_api, output_api):
355 source_file_filter = lambda x: input_api.FilterSourceFile(
356 x, white_list=(r'.+\.(gyp|gypi)$',))
357
358 gyp_files = []
359 for f in input_api.AffectedSourceFiles(source_file_filter):
kjellander@webrtc.org3398a4a2014-11-24 10:05:37 +0000360 if f.LocalPath().startswith('webrtc'):
361 gyp_files.append(f)
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000362
363 result = []
364 if gyp_files:
365 result.append(output_api.PresubmitNotifyResult(
366 'As you\'re changing GYP files: please make sure corresponding '
367 'BUILD.gn files are also updated.\nChanged GYP files:',
368 items=gyp_files))
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000369 result.extend(_CheckNoRtcBaseDeps(input_api, gyp_files, output_api))
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000370 result.extend(_CheckNoSourcesAboveGyp(input_api, gyp_files, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000371 return result
372
ehmaldonado5b1ba082016-09-02 05:51:08 -0700373def _CheckGnChanges(input_api, output_api):
374 source_file_filter = lambda x: input_api.FilterSourceFile(
375 x, white_list=(r'.+\.(gn|gni)$',))
376
377 gn_files = []
378 for f in input_api.AffectedSourceFiles(source_file_filter):
379 if f.LocalPath().startswith('webrtc'):
380 gn_files.append(f)
381
382 result = []
383 if gn_files:
384 result.append(output_api.PresubmitNotifyResult(
385 'As you\'re changing GN files: please make sure corresponding GYP'
386 'files are also updated.\nChanged GN files:',
387 items=gn_files))
388 result.extend(_CheckNoRtcBaseDepsGn(input_api, gn_files, output_api))
389 result.extend(_CheckNoSourcesAboveGn(input_api, gn_files, output_api))
390 return result
391
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000392def _CheckUnwantedDependencies(input_api, output_api):
393 """Runs checkdeps on #include statements added in this
394 change. Breaking - rules is an error, breaking ! rules is a
395 warning.
396 """
397 # Copied from Chromium's src/PRESUBMIT.py.
398
399 # We need to wait until we have an input_api object and use this
400 # roundabout construct to import checkdeps because this file is
401 # eval-ed and thus doesn't have __file__.
402 original_sys_path = sys.path
403 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000404 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
405 'buildtools', 'checkdeps')
406 if not os.path.exists(checkdeps_path):
407 return [output_api.PresubmitError(
408 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
409 'download Chromium and setup the symlinks?' % checkdeps_path)]
410 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000411 import checkdeps
412 from cpp_checker import CppChecker
413 from rules import Rule
414 finally:
415 # Restore sys.path to what it was before.
416 sys.path = original_sys_path
417
418 added_includes = []
419 for f in input_api.AffectedFiles():
420 if not CppChecker.IsCppFile(f.LocalPath()):
421 continue
422
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200423 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000424 added_includes.append([f.LocalPath(), changed_lines])
425
426 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
427
428 error_descriptions = []
429 warning_descriptions = []
430 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
431 added_includes):
432 description_with_path = '%s\n %s' % (path, rule_description)
433 if rule_type == Rule.DISALLOW:
434 error_descriptions.append(description_with_path)
435 else:
436 warning_descriptions.append(description_with_path)
437
438 results = []
439 if error_descriptions:
440 results.append(output_api.PresubmitError(
441 'You added one or more #includes that violate checkdeps rules.',
442 error_descriptions))
443 if warning_descriptions:
444 results.append(output_api.PresubmitPromptOrNotify(
445 'You added one or more #includes of files that are temporarily\n'
446 'allowed but being removed. Can you avoid introducing the\n'
447 '#include? See relevant DEPS file(s) for details and contacts.',
448 warning_descriptions))
449 return results
450
kjellanderd1e26a92016-09-19 08:11:16 -0700451def _CheckChangeHasBugField(input_api, output_api):
452 """Requires that the changelist have a BUG= field.
453
454 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
455 since it fails the presubmit if the BUG= field is missing or doesn't contain
456 a bug reference.
457 """
458 if input_api.change.BUG:
459 return []
460 else:
461 return [output_api.PresubmitError(
462 'The BUG=[bug number] field is mandatory. Please create a bug and '
463 'reference it using either of:\n'
464 ' * https://bugs.webrtc.org - reference it using BUG=webrtc:XXXX\n'
465 ' * https://crbug.com - reference it using BUG=chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000466
kjellander569cf942016-02-11 05:02:59 -0800467def _CheckJSONParseErrors(input_api, output_api):
468 """Check that JSON files do not contain syntax errors."""
469
470 def FilterFile(affected_file):
471 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
472
473 def GetJSONParseError(input_api, filename):
474 try:
475 contents = input_api.ReadFile(filename)
476 input_api.json.loads(contents)
477 except ValueError as e:
478 return e
479 return None
480
481 results = []
482 for affected_file in input_api.AffectedFiles(
483 file_filter=FilterFile, include_deletes=False):
484 parse_error = GetJSONParseError(input_api,
485 affected_file.AbsoluteLocalPath())
486 if parse_error:
487 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
488 (affected_file.LocalPath(), parse_error)))
489 return results
490
491
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200492def _RunPythonTests(input_api, output_api):
493 def join(*args):
494 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
495
496 test_directories = [
497 join('tools', 'autoroller', 'unittests'),
aleloi7ebbf902016-06-20 07:39:15 -0700498 join('webrtc', 'tools', 'py_event_log_analyzer'),
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200499 ]
500
501 tests = []
502 for directory in test_directories:
503 tests.extend(
504 input_api.canned_checks.GetUnitTestsInDirectory(
505 input_api,
506 output_api,
507 directory,
508 whitelist=[r'.+_test\.py$']))
509 return input_api.RunTests(tests, parallel=True)
510
511
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000512def _CommonChecks(input_api, output_api):
513 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000514 results = []
tkchin42f580e2015-11-26 23:18:23 -0800515 # Filter out files that are in objc or ios dirs from being cpplint-ed since
516 # they do not follow C++ lint rules.
517 black_list = input_api.DEFAULT_BLACK_LIST + (
518 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000519 r".*objc\.[hcm]+$",
hjon65ae2d82016-08-02 23:55:44 -0700520 r"webrtc\/build\/ios\/SDK\/.*",
tkchin42f580e2015-11-26 23:18:23 -0800521 )
522 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
523 results.extend(_CheckApprovedFilesLintClean(
524 input_api, output_api, source_file_filter))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000525 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
526 black_list=(r'^.*gviz_api\.py$',
527 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000528 # Embedded shell-script fakes out pylint.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200529 r'^build[\\\/].*\.py$',
530 r'^buildtools[\\\/].*\.py$',
531 r'^chromium[\\\/].*\.py$',
kjellanderd620f822016-04-04 06:07:08 -0700532 r'^mojo.*[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200533 r'^out.*[\\\/].*\.py$',
534 r'^testing[\\\/].*\.py$',
535 r'^third_party[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200536 r'^tools[\\\/]clang[\\\/].*\.py$',
537 r'^tools[\\\/]generate_library_loader[\\\/].*\.py$',
kjellanderd620f822016-04-04 06:07:08 -0700538 r'^tools[\\\/]generate_stubs[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200539 r'^tools[\\\/]gn[\\\/].*\.py$',
540 r'^tools[\\\/]gyp[\\\/].*\.py$',
Henrik Kjellanderd6d27e72015-09-25 22:19:11 +0200541 r'^tools[\\\/]isolate_driver.py$',
kjellanderd620f822016-04-04 06:07:08 -0700542 r'^tools[\\\/]mb[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200543 r'^tools[\\\/]protoc_wrapper[\\\/].*\.py$',
544 r'^tools[\\\/]python[\\\/].*\.py$',
545 r'^tools[\\\/]python_charts[\\\/]data[\\\/].*\.py$',
546 r'^tools[\\\/]refactoring[\\\/].*\.py$',
547 r'^tools[\\\/]swarming_client[\\\/].*\.py$',
548 r'^tools[\\\/]vim[\\\/].*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000549 # TODO(phoglund): should arguably be checked.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200550 r'^tools[\\\/]valgrind-webrtc[\\\/].*\.py$',
551 r'^tools[\\\/]valgrind[\\\/].*\.py$',
552 r'^tools[\\\/]win[\\\/].*\.py$',
553 r'^xcodebuild.*[\\\/].*\.py$',),
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000554 disabled_warnings=['F0401', # Failed to import x
555 'E0611', # No package y in x
556 'W0232', # Class has no __init__ method
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200557 ],
558 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800559
nisse3d21e232016-09-02 03:07:06 -0700560 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200561 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
562 # we need to have different license checks in talk/ and webrtc/ directories.
563 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200564
tkchin3cd9a302016-06-08 12:40:28 -0700565 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
566 # ObjC subdirectories ObjC headers.
567 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellander63224672015-09-08 08:03:56 +0200568 # Skip long-lines check for DEPS, GN and GYP files.
tkchin3cd9a302016-06-08 12:40:28 -0700569 build_file_filter_list = (r'.+\.gyp$', r'.+\.gypi$', r'.+\.gn$', r'.+\.gni$',
570 'DEPS')
571 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
572 black_list=build_file_filter_list + objc_filter_list)
573 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
574 white_list=objc_filter_list)
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000575 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700576 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
577 results.extend(input_api.canned_checks.CheckLongLines(
578 input_api, output_api, maxlen=100,
579 source_file_filter=hundred_char_sources))
580
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000581 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
582 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000583 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
584 input_api, output_api))
585 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
586 input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800587 results.extend(_CheckNativeApiHeaderChanges(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000588 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
589 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000590 results.extend(_CheckGypChanges(input_api, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700591 results.extend(_CheckGnChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000592 results.extend(_CheckUnwantedDependencies(input_api, output_api))
kjellander569cf942016-02-11 05:02:59 -0800593 results.extend(_CheckJSONParseErrors(input_api, output_api))
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200594 results.extend(_RunPythonTests(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000595 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000596
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000597
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000598def CheckChangeOnUpload(input_api, output_api):
599 results = []
600 results.extend(_CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200601 results.extend(
602 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000603 return results
604
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000605
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000606def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000607 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000608 results.extend(_CommonChecks(input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800609 results.extend(_VerifyNativeApiHeadersListIsValid(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000610 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000611 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
612 input_api, output_api))
613 results.extend(input_api.canned_checks.CheckChangeHasDescription(
614 input_api, output_api))
kjellanderd1e26a92016-09-19 08:11:16 -0700615 results.extend(_CheckChangeHasBugField(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000616 results.extend(input_api.canned_checks.CheckChangeHasTestField(
617 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000618 results.extend(input_api.canned_checks.CheckTreeIsOpen(
619 input_api, output_api,
620 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000621 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000622
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000623
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000624# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000625def GetPreferredTryMasters(project, change):
kjellander986ee082015-06-16 04:32:13 -0700626 cq_config_path = os.path.join(
tandrii04465d22015-06-20 04:00:49 -0700627 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
kjellander986ee082015-06-16 04:32:13 -0700628 # commit_queue.py below is a script in depot_tools directory, which has a
629 # 'builders' command to retrieve a list of CQ builders from the CQ config.
630 is_win = platform.system() == 'Windows'
631 masters = json.loads(subprocess.check_output(
632 ['commit_queue', 'builders', cq_config_path], shell=is_win))
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000633
kjellander986ee082015-06-16 04:32:13 -0700634 try_config = {}
635 for master in masters:
636 try_config.setdefault(master, {})
637 for builder in masters[master]:
638 if 'presubmit' in builder:
639 # Do not trigger presubmit builders, since they're likely to fail
640 # (e.g. OWNERS checks before finished code review), and we're running
641 # local presubmit anyway.
642 pass
643 else:
644 try_config[master][builder] = ['defaulttests']
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000645
kjellander986ee082015-06-16 04:32:13 -0700646 return try_config