blob: 8619ac5b70a85de70f71b5c27a8b7c1aaf82ef96 [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
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000451
kjellander569cf942016-02-11 05:02:59 -0800452def _CheckJSONParseErrors(input_api, output_api):
453 """Check that JSON files do not contain syntax errors."""
454
455 def FilterFile(affected_file):
456 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
457
458 def GetJSONParseError(input_api, filename):
459 try:
460 contents = input_api.ReadFile(filename)
461 input_api.json.loads(contents)
462 except ValueError as e:
463 return e
464 return None
465
466 results = []
467 for affected_file in input_api.AffectedFiles(
468 file_filter=FilterFile, include_deletes=False):
469 parse_error = GetJSONParseError(input_api,
470 affected_file.AbsoluteLocalPath())
471 if parse_error:
472 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
473 (affected_file.LocalPath(), parse_error)))
474 return results
475
476
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200477def _RunPythonTests(input_api, output_api):
478 def join(*args):
479 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
480
481 test_directories = [
482 join('tools', 'autoroller', 'unittests'),
aleloi7ebbf902016-06-20 07:39:15 -0700483 join('webrtc', 'tools', 'py_event_log_analyzer'),
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200484 ]
485
486 tests = []
487 for directory in test_directories:
488 tests.extend(
489 input_api.canned_checks.GetUnitTestsInDirectory(
490 input_api,
491 output_api,
492 directory,
493 whitelist=[r'.+_test\.py$']))
494 return input_api.RunTests(tests, parallel=True)
495
496
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000497def _CommonChecks(input_api, output_api):
498 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000499 results = []
tkchin42f580e2015-11-26 23:18:23 -0800500 # Filter out files that are in objc or ios dirs from being cpplint-ed since
501 # they do not follow C++ lint rules.
502 black_list = input_api.DEFAULT_BLACK_LIST + (
503 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000504 r".*objc\.[hcm]+$",
hjon65ae2d82016-08-02 23:55:44 -0700505 r"webrtc\/build\/ios\/SDK\/.*",
tkchin42f580e2015-11-26 23:18:23 -0800506 )
507 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
508 results.extend(_CheckApprovedFilesLintClean(
509 input_api, output_api, source_file_filter))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000510 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
511 black_list=(r'^.*gviz_api\.py$',
512 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000513 # Embedded shell-script fakes out pylint.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200514 r'^build[\\\/].*\.py$',
515 r'^buildtools[\\\/].*\.py$',
516 r'^chromium[\\\/].*\.py$',
kjellanderd620f822016-04-04 06:07:08 -0700517 r'^mojo.*[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200518 r'^out.*[\\\/].*\.py$',
519 r'^testing[\\\/].*\.py$',
520 r'^third_party[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200521 r'^tools[\\\/]clang[\\\/].*\.py$',
522 r'^tools[\\\/]generate_library_loader[\\\/].*\.py$',
kjellanderd620f822016-04-04 06:07:08 -0700523 r'^tools[\\\/]generate_stubs[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200524 r'^tools[\\\/]gn[\\\/].*\.py$',
525 r'^tools[\\\/]gyp[\\\/].*\.py$',
Henrik Kjellanderd6d27e72015-09-25 22:19:11 +0200526 r'^tools[\\\/]isolate_driver.py$',
kjellanderd620f822016-04-04 06:07:08 -0700527 r'^tools[\\\/]mb[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200528 r'^tools[\\\/]protoc_wrapper[\\\/].*\.py$',
529 r'^tools[\\\/]python[\\\/].*\.py$',
530 r'^tools[\\\/]python_charts[\\\/]data[\\\/].*\.py$',
531 r'^tools[\\\/]refactoring[\\\/].*\.py$',
532 r'^tools[\\\/]swarming_client[\\\/].*\.py$',
533 r'^tools[\\\/]vim[\\\/].*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000534 # TODO(phoglund): should arguably be checked.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200535 r'^tools[\\\/]valgrind-webrtc[\\\/].*\.py$',
536 r'^tools[\\\/]valgrind[\\\/].*\.py$',
537 r'^tools[\\\/]win[\\\/].*\.py$',
538 r'^xcodebuild.*[\\\/].*\.py$',),
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000539 disabled_warnings=['F0401', # Failed to import x
540 'E0611', # No package y in x
541 'W0232', # Class has no __init__ method
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200542 ],
543 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800544
nisse3d21e232016-09-02 03:07:06 -0700545 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200546 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
547 # we need to have different license checks in talk/ and webrtc/ directories.
548 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200549
tkchin3cd9a302016-06-08 12:40:28 -0700550 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
551 # ObjC subdirectories ObjC headers.
552 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellander63224672015-09-08 08:03:56 +0200553 # Skip long-lines check for DEPS, GN and GYP files.
tkchin3cd9a302016-06-08 12:40:28 -0700554 build_file_filter_list = (r'.+\.gyp$', r'.+\.gypi$', r'.+\.gn$', r'.+\.gni$',
555 'DEPS')
556 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
557 black_list=build_file_filter_list + objc_filter_list)
558 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
559 white_list=objc_filter_list)
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000560 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700561 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
562 results.extend(input_api.canned_checks.CheckLongLines(
563 input_api, output_api, maxlen=100,
564 source_file_filter=hundred_char_sources))
565
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000566 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
567 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000568 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
569 input_api, output_api))
570 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
571 input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800572 results.extend(_CheckNativeApiHeaderChanges(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000573 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
574 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000575 results.extend(_CheckGypChanges(input_api, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700576 results.extend(_CheckGnChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000577 results.extend(_CheckUnwantedDependencies(input_api, output_api))
kjellander569cf942016-02-11 05:02:59 -0800578 results.extend(_CheckJSONParseErrors(input_api, output_api))
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200579 results.extend(_RunPythonTests(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000580 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000581
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000582
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000583def CheckChangeOnUpload(input_api, output_api):
584 results = []
585 results.extend(_CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200586 results.extend(
587 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000588 return results
589
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000590
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000591def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000592 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000593 results.extend(_CommonChecks(input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800594 results.extend(_VerifyNativeApiHeadersListIsValid(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000595 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000596 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
597 input_api, output_api))
598 results.extend(input_api.canned_checks.CheckChangeHasDescription(
599 input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000600 results.extend(input_api.canned_checks.CheckChangeHasBugField(
601 input_api, output_api))
602 results.extend(input_api.canned_checks.CheckChangeHasTestField(
603 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000604 results.extend(input_api.canned_checks.CheckTreeIsOpen(
605 input_api, output_api,
606 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000607 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000608
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000609
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000610# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000611def GetPreferredTryMasters(project, change):
kjellander986ee082015-06-16 04:32:13 -0700612 cq_config_path = os.path.join(
tandrii04465d22015-06-20 04:00:49 -0700613 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
kjellander986ee082015-06-16 04:32:13 -0700614 # commit_queue.py below is a script in depot_tools directory, which has a
615 # 'builders' command to retrieve a list of CQ builders from the CQ config.
616 is_win = platform.system() == 'Windows'
617 masters = json.loads(subprocess.check_output(
618 ['commit_queue', 'builders', cq_config_path], shell=is_win))
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000619
kjellander986ee082015-06-16 04:32:13 -0700620 try_config = {}
621 for master in masters:
622 try_config.setdefault(master, {})
623 for builder in masters[master]:
624 if 'presubmit' in builder:
625 # Do not trigger presubmit builders, since they're likely to fail
626 # (e.g. OWNERS checks before finished code review), and we're running
627 # local presubmit anyway.
628 pass
629 else:
630 try_config[master][builder] = ['defaulttests']
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000631
kjellander986ee082015-06-16 04:32:13 -0700632 return try_config