blob: 497e182f4d1ffd3d5478ae9e699a715a1614d6cc [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
kjellander7439f972016-12-05 22:47:46 -08009import json
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +000010import os
kjellander@webrtc.org85759802013-10-22 16:47:40 +000011import re
ehmaldonado4fb97462017-01-30 05:27:22 -080012import subprocess
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +000013import sys
kjellander@webrtc.org85759802013-10-22 16:47:40 +000014
15
oprypin2aa463f2017-03-23 03:17:02 -070016# Files and directories that are *skipped* by cpplint in the presubmit script.
17CPPLINT_BLACKLIST = [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +020018 'tools_webrtc',
ilnikd60d06a2017-04-05 03:02:20 -070019 'webrtc/api/video_codecs/video_decoder.h',
oprypin2aa463f2017-03-23 03:17:02 -070020 'webrtc/examples/objc',
21 'webrtc/media',
22 'webrtc/modules/audio_coding',
23 'webrtc/modules/audio_conference_mixer',
24 'webrtc/modules/audio_device',
25 'webrtc/modules/audio_processing',
26 'webrtc/modules/desktop_capture',
27 'webrtc/modules/include/module_common_types.h',
28 'webrtc/modules/media_file',
29 'webrtc/modules/utility',
30 'webrtc/modules/video_capture',
31 'webrtc/p2p',
32 'webrtc/pc',
Henrik Kjellanderc0362762017-06-29 08:03:04 +020033 'webrtc/rtc_base',
oprypin2aa463f2017-03-23 03:17:02 -070034 'webrtc/sdk/android/src/jni',
35 'webrtc/sdk/objc',
36 'webrtc/system_wrappers',
37 'webrtc/test',
38 'webrtc/voice_engine',
oprypin2aa463f2017-03-23 03:17:02 -070039 'webrtc/common_types.h',
40 'webrtc/common_types.cc',
oprypin2aa463f2017-03-23 03:17:02 -070041 'webrtc/video_send_stream.h',
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +010042]
43
jbauchc4e3ead2016-02-19 00:25:55 -080044# These filters will always be removed, even if the caller specifies a filter
45# set, as they are problematic or broken in some way.
46#
47# Justifications for each filter:
48# - build/c++11 : Rvalue ref checks are unreliable (false positives),
49# include file and feature blacklists are
50# google3-specific.
kjellandere5a87a52016-04-27 02:32:12 -070051# - whitespace/operators: Same as above (doesn't seem sufficient to eliminate
52# all move-related errors).
jbauchc4e3ead2016-02-19 00:25:55 -080053BLACKLIST_LINT_FILTERS = [
54 '-build/c++11',
kjellandere5a87a52016-04-27 02:32:12 -070055 '-whitespace/operators',
jbauchc4e3ead2016-02-19 00:25:55 -080056]
57
kjellanderfd595232015-12-04 02:44:09 -080058# List of directories of "supported" native APIs. That means changes to headers
59# will be done in a compatible way following this scheme:
60# 1. Non-breaking changes are made.
61# 2. The old APIs as marked as deprecated (with comments).
62# 3. Deprecation is announced to discuss-webrtc@googlegroups.com and
63# webrtc-users@google.com (internal list).
64# 4. (later) The deprecated APIs are removed.
kjellander53047c92015-12-02 23:56:14 -080065NATIVE_API_DIRS = (
kjellander53047c92015-12-02 23:56:14 -080066 'webrtc',
kjellanderdd705472016-06-09 11:17:27 -070067 'webrtc/api',
68 'webrtc/media',
kjellander53047c92015-12-02 23:56:14 -080069 'webrtc/modules/audio_device/include',
kjellanderdd705472016-06-09 11:17:27 -070070 'webrtc/pc',
71)
72# These directories should not be used but are maintained only to avoid breaking
73# some legacy downstream code.
74LEGACY_API_DIRS = (
kjellanderdd705472016-06-09 11:17:27 -070075 'webrtc/common_audio/include',
76 'webrtc/modules/audio_coding/include',
77 'webrtc/modules/audio_conference_mixer/include',
kjellander53047c92015-12-02 23:56:14 -080078 'webrtc/modules/audio_processing/include',
79 'webrtc/modules/bitrate_controller/include',
Stefan Holmer80e12072016-02-23 13:30:42 +010080 'webrtc/modules/congestion_controller/include',
kjellander53047c92015-12-02 23:56:14 -080081 'webrtc/modules/include',
82 'webrtc/modules/remote_bitrate_estimator/include',
83 'webrtc/modules/rtp_rtcp/include',
kjellanderdd705472016-06-09 11:17:27 -070084 'webrtc/modules/rtp_rtcp/source',
kjellander53047c92015-12-02 23:56:14 -080085 'webrtc/modules/utility/include',
86 'webrtc/modules/video_coding/codecs/h264/include',
87 'webrtc/modules/video_coding/codecs/i420/include',
88 'webrtc/modules/video_coding/codecs/vp8/include',
89 'webrtc/modules/video_coding/codecs/vp9/include',
90 'webrtc/modules/video_coding/include',
ehmaldonadof6a861a2017-07-19 10:40:47 -070091 'webrtc/rtc_base',
kjellanderdd705472016-06-09 11:17:27 -070092 'webrtc/system_wrappers/include',
kjellander53047c92015-12-02 23:56:14 -080093 'webrtc/voice_engine/include',
94)
kjellanderdd705472016-06-09 11:17:27 -070095API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-02 23:56:14 -080096
97
ehmaldonado4fb97462017-01-30 05:27:22 -080098def _RunCommand(command, cwd):
99 """Runs a command and returns the output from that command."""
100 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
101 cwd=cwd)
102 stdout = p.stdout.read()
103 stderr = p.stderr.read()
104 p.wait()
105 p.stdout.close()
106 p.stderr.close()
107 return p.returncode, stdout, stderr
108
109
kjellander53047c92015-12-02 23:56:14 -0800110def _VerifyNativeApiHeadersListIsValid(input_api, output_api):
111 """Ensures the list of native API header directories is up to date."""
112 non_existing_paths = []
113 native_api_full_paths = [
114 input_api.os_path.join(input_api.PresubmitLocalPath(),
kjellanderdd705472016-06-09 11:17:27 -0700115 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-02 23:56:14 -0800116 for path in native_api_full_paths:
117 if not os.path.isdir(path):
118 non_existing_paths.append(path)
119 if non_existing_paths:
120 return [output_api.PresubmitError(
121 'Directories to native API headers have changed which has made the '
122 'list in PRESUBMIT.py outdated.\nPlease update it to the current '
123 'location of our native APIs.',
124 non_existing_paths)]
125 return []
126
kjellanderc88b5d52017-04-05 06:42:43 -0700127API_CHANGE_MSG = """
kwibergeb133022016-04-07 07:41:48 -0700128You seem to be changing native API header files. Please make sure that you:
oprypin375b9ac2017-02-13 04:13:23 -0800129 1. Make compatible changes that don't break existing clients. Usually
130 this is done by keeping the existing method signatures unchanged.
131 2. Mark the old stuff as deprecated (see RTC_DEPRECATED macro).
kwibergeb133022016-04-07 07:41:48 -0700132 3. Create a timeline and plan for when the deprecated stuff will be
133 removed. (The amount of time we give users to change their code
134 should be informed by how much work it is for them. If they just
135 need to replace one name with another or something equally
136 simple, 1-2 weeks might be good; if they need to do serious work,
137 up to 3 months may be called for.)
138 4. Update/inform existing downstream code owners to stop using the
139 deprecated stuff. (Send announcements to
140 discuss-webrtc@googlegroups.com and webrtc-users@google.com.)
141 5. Remove the deprecated stuff, once the agreed-upon amount of time
142 has passed.
143Related files:
144"""
kjellander53047c92015-12-02 23:56:14 -0800145
146def _CheckNativeApiHeaderChanges(input_api, output_api):
147 """Checks to remind proper changing of native APIs."""
148 files = []
149 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
150 if f.LocalPath().endswith('.h'):
kjellanderdd705472016-06-09 11:17:27 -0700151 for path in API_DIRS:
kjellander53047c92015-12-02 23:56:14 -0800152 if os.path.dirname(f.LocalPath()) == path:
153 files.append(f)
154
155 if files:
kjellanderc88b5d52017-04-05 06:42:43 -0700156 return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
kjellander53047c92015-12-02 23:56:14 -0800157 return []
158
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100159
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000160def _CheckNoIOStreamInHeaders(input_api, output_api):
161 """Checks to make sure no .h files include <iostream>."""
162 files = []
163 pattern = input_api.re.compile(r'^#include\s*<iostream>',
164 input_api.re.MULTILINE)
165 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
166 if not f.LocalPath().endswith('.h'):
167 continue
168 contents = input_api.ReadFile(f)
169 if pattern.search(contents):
170 files.append(f)
171
172 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200173 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000174 'Do not #include <iostream> in header files, since it inserts static ' +
175 'initialization into every file including the header. Instead, ' +
176 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200177 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000178 return []
179
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000180
kjellander6aeef742017-02-20 01:13:18 -0800181def _CheckNoPragmaOnce(input_api, output_api):
182 """Make sure that banned functions are not used."""
183 files = []
184 pattern = input_api.re.compile(r'^#pragma\s+once',
185 input_api.re.MULTILINE)
186 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
187 if not f.LocalPath().endswith('.h'):
188 continue
189 contents = input_api.ReadFile(f)
190 if pattern.search(contents):
191 files.append(f)
192
193 if files:
194 return [output_api.PresubmitError(
195 'Do not use #pragma once in header files.\n'
196 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
197 files)]
198 return []
199
200
kjellanderc88b5d52017-04-05 06:42:43 -0700201def _CheckNoFRIEND_TEST(input_api, output_api): # pylint: disable=invalid-name
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000202 """Make sure that gtest's FRIEND_TEST() macro is not used, the
203 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
204 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
205 problems = []
206
207 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
208 for f in input_api.AffectedFiles(file_filter=file_filter):
209 for line_num, line in f.ChangedContents():
210 if 'FRIEND_TEST(' in line:
211 problems.append(' %s:%d' % (f.LocalPath(), line_num))
212
213 if not problems:
214 return []
215 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
216 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
217 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
218
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000219
oprypin2aa463f2017-03-23 03:17:02 -0700220def _IsLintBlacklisted(blacklist_paths, file_path):
221 """ Checks if a file is blacklisted for lint check."""
222 for path in blacklist_paths:
223 if file_path == path or os.path.dirname(file_path).startswith(path):
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100224 return True
225 return False
226
227
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000228def _CheckApprovedFilesLintClean(input_api, output_api,
229 source_file_filter=None):
oprypin2aa463f2017-03-23 03:17:02 -0700230 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000231 This check is based on _CheckChangeLintsClean in
232 depot_tools/presubmit_canned_checks.py but has less filters and only checks
233 added files."""
234 result = []
235
236 # Initialize cpplint.
237 import cpplint
238 # Access to a protected member _XX of a client class
239 # pylint: disable=W0212
240 cpplint._cpplint_state.ResetErrorCounts()
241
jbauchc4e3ead2016-02-19 00:25:55 -0800242 lint_filters = cpplint._Filters()
243 lint_filters.extend(BLACKLIST_LINT_FILTERS)
244 cpplint._SetFilters(','.join(lint_filters))
245
oprypin2aa463f2017-03-23 03:17:02 -0700246 # Create a platform independent blacklist for cpplint.
247 blacklist_paths = [input_api.os_path.join(*path.split('/'))
248 for path in CPPLINT_BLACKLIST]
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100249
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000250 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 03:17:02 -0700251 # default when running cpplint.py from command line. To make it possible to
252 # work with not-yet-converted code, we're only applying it to new (or
253 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000254 verbosity_level = 1
255 files = []
256 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200257 # Note that moved/renamed files also count as added.
oprypin2aa463f2017-03-23 03:17:02 -0700258 if f.Action() == 'A' or not _IsLintBlacklisted(blacklist_paths,
259 f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000260 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000261
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000262 for file_name in files:
263 cpplint.ProcessFile(file_name, verbosity_level)
264
265 if cpplint._cpplint_state.error_count > 0:
266 if input_api.is_committing:
oprypin8e58d652017-03-21 07:52:41 -0700267 res_type = output_api.PresubmitError
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000268 else:
269 res_type = output_api.PresubmitPromptWarning
270 result = [res_type('Changelist failed cpplint.py check.')]
271
272 return result
273
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100274def _CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700275 # Disallow referencing source files with paths above the GN file location.
276 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
277 re.MULTILINE | re.DOTALL)
278 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
279 violating_gn_files = set()
280 violating_source_entries = []
281 for gn_file in gn_files:
282 contents = input_api.ReadFile(gn_file)
283 for source_block_match in source_pattern.finditer(contents):
284 # Find all source list entries starting with ../ in the source block
285 # (exclude overrides entries).
286 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
287 source_file = file_list_match.group(1)
288 if 'overrides/' not in source_file:
289 violating_source_entries.append(source_file)
290 violating_gn_files.add(gn_file)
291 if violating_gn_files:
292 return [output_api.PresubmitError(
293 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100294 'allowed. Please introduce new GN targets in the proper location '
295 'instead.\n'
ehmaldonado5b1ba082016-09-02 05:51:08 -0700296 'Invalid source entries:\n'
297 '%s\n'
298 'Violating GN files:' % '\n'.join(violating_source_entries),
299 items=violating_gn_files)]
300 return []
301
kjellander7439f972016-12-05 22:47:46 -0800302def _CheckNoMixingCAndCCSources(input_api, gn_files, output_api):
303 # Disallow mixing .c and .cc source files in the same target.
304 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
305 re.MULTILINE | re.DOTALL)
306 file_pattern = input_api.re.compile(r'"(.*)"')
307 violating_gn_files = dict()
308 for gn_file in gn_files:
309 contents = input_api.ReadFile(gn_file)
310 for source_block_match in source_pattern.finditer(contents):
311 c_files = []
312 cc_files = []
313 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
314 source_file = file_list_match.group(1)
315 if source_file.endswith('.c'):
316 c_files.append(source_file)
317 if source_file.endswith('.cc'):
318 cc_files.append(source_file)
319 if c_files and cc_files:
320 violating_gn_files[gn_file.LocalPath()] = sorted(c_files + cc_files)
321 if violating_gn_files:
322 return [output_api.PresubmitError(
323 'GN targets cannot mix .cc and .c source files. Please create a '
324 'separate target for each collection of sources.\n'
325 'Mixed sources: \n'
326 '%s\n'
327 'Violating GN files:' % json.dumps(violating_gn_files, indent=2),
328 items=violating_gn_files.keys())]
329 return []
330
ehmaldonado4fb97462017-01-30 05:27:22 -0800331def _CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
332 cwd = input_api.PresubmitLocalPath()
mbonadeiab587dc2017-05-12 04:13:31 -0700333 script_path = os.path.join('tools_webrtc', 'presubmit_checks_lib',
334 'check_package_boundaries.py')
ehmaldonado4fb97462017-01-30 05:27:22 -0800335 webrtc_path = os.path.join('webrtc')
336 command = [sys.executable, script_path, webrtc_path]
337 command += [gn_file.LocalPath() for gn_file in gn_files]
338 returncode, _, stderr = _RunCommand(command, cwd)
339 if returncode:
340 return [output_api.PresubmitError(
341 'There are package boundary violations in the following GN files:\n\n'
342 '%s' % stderr)]
343 return []
344
ehmaldonado5b1ba082016-09-02 05:51:08 -0700345def _CheckGnChanges(input_api, output_api):
346 source_file_filter = lambda x: input_api.FilterSourceFile(
347 x, white_list=(r'.+\.(gn|gni)$',))
348
349 gn_files = []
350 for f in input_api.AffectedSourceFiles(source_file_filter):
351 if f.LocalPath().startswith('webrtc'):
352 gn_files.append(f)
353
354 result = []
355 if gn_files:
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100356 result.extend(_CheckNoSourcesAbove(input_api, gn_files, output_api))
kjellander7439f972016-12-05 22:47:46 -0800357 result.extend(_CheckNoMixingCAndCCSources(input_api, gn_files, output_api))
ehmaldonado4fb97462017-01-30 05:27:22 -0800358 result.extend(_CheckNoPackageBoundaryViolations(
359 input_api, gn_files, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700360 return result
361
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000362def _CheckUnwantedDependencies(input_api, output_api):
363 """Runs checkdeps on #include statements added in this
364 change. Breaking - rules is an error, breaking ! rules is a
365 warning.
366 """
367 # Copied from Chromium's src/PRESUBMIT.py.
368
369 # We need to wait until we have an input_api object and use this
370 # roundabout construct to import checkdeps because this file is
371 # eval-ed and thus doesn't have __file__.
372 original_sys_path = sys.path
373 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000374 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
375 'buildtools', 'checkdeps')
376 if not os.path.exists(checkdeps_path):
377 return [output_api.PresubmitError(
378 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
379 'download Chromium and setup the symlinks?' % checkdeps_path)]
380 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000381 import checkdeps
382 from cpp_checker import CppChecker
383 from rules import Rule
384 finally:
385 # Restore sys.path to what it was before.
386 sys.path = original_sys_path
387
388 added_includes = []
389 for f in input_api.AffectedFiles():
390 if not CppChecker.IsCppFile(f.LocalPath()):
391 continue
392
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200393 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000394 added_includes.append([f.LocalPath(), changed_lines])
395
396 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
397
398 error_descriptions = []
399 warning_descriptions = []
400 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
401 added_includes):
402 description_with_path = '%s\n %s' % (path, rule_description)
403 if rule_type == Rule.DISALLOW:
404 error_descriptions.append(description_with_path)
405 else:
406 warning_descriptions.append(description_with_path)
407
408 results = []
409 if error_descriptions:
410 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 03:47:05 -0700411 'You added one or more #includes that violate checkdeps rules.\n'
412 'Check that the DEPS files in these locations contain valid rules.\n'
413 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
414 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000415 error_descriptions))
416 if warning_descriptions:
417 results.append(output_api.PresubmitPromptOrNotify(
418 'You added one or more #includes of files that are temporarily\n'
419 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 03:47:05 -0700420 '#include? See relevant DEPS file(s) for details and contacts.\n'
421 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
422 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000423 warning_descriptions))
424 return results
425
kjellanderd1e26a92016-09-19 08:11:16 -0700426def _CheckChangeHasBugField(input_api, output_api):
427 """Requires that the changelist have a BUG= field.
428
429 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
430 since it fails the presubmit if the BUG= field is missing or doesn't contain
431 a bug reference.
432 """
433 if input_api.change.BUG:
434 return []
435 else:
436 return [output_api.PresubmitError(
437 'The BUG=[bug number] field is mandatory. Please create a bug and '
438 'reference it using either of:\n'
439 ' * https://bugs.webrtc.org - reference it using BUG=webrtc:XXXX\n'
440 ' * https://crbug.com - reference it using BUG=chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000441
kjellander569cf942016-02-11 05:02:59 -0800442def _CheckJSONParseErrors(input_api, output_api):
443 """Check that JSON files do not contain syntax errors."""
444
445 def FilterFile(affected_file):
446 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
447
448 def GetJSONParseError(input_api, filename):
449 try:
450 contents = input_api.ReadFile(filename)
451 input_api.json.loads(contents)
452 except ValueError as e:
453 return e
454 return None
455
456 results = []
457 for affected_file in input_api.AffectedFiles(
458 file_filter=FilterFile, include_deletes=False):
459 parse_error = GetJSONParseError(input_api,
460 affected_file.AbsoluteLocalPath())
461 if parse_error:
462 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
463 (affected_file.LocalPath(), parse_error)))
464 return results
465
466
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200467def _RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 06:42:43 -0700468 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200469 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
470
471 test_directories = [
kjellander41bafb22017-06-30 04:14:54 -0700472 Join('webrtc', 'rtc_tools', 'py_event_log_analyzer'),
473 Join('webrtc', 'rtc_tools'),
oprypinabd101b2017-04-06 23:21:30 -0700474 Join('webrtc', 'audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 05:27:22 -0800475 ] + [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200476 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 05:27:22 -0800477 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200478 ]
479
480 tests = []
481 for directory in test_directories:
482 tests.extend(
483 input_api.canned_checks.GetUnitTestsInDirectory(
484 input_api,
485 output_api,
486 directory,
487 whitelist=[r'.+_test\.py$']))
488 return input_api.RunTests(tests, parallel=True)
489
490
mbonadei38415b22017-04-07 05:38:01 -0700491def _CheckUsageOfGoogleProtobufNamespace(input_api, output_api):
492 """Checks that the namespace google::protobuf has not been used."""
493 files = []
494 pattern = input_api.re.compile(r'google::protobuf')
495 proto_utils_path = os.path.join('webrtc', 'base', 'protobuf_utils.h')
496 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
497 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
498 continue
499 contents = input_api.ReadFile(f)
500 if pattern.search(contents):
501 files.append(f)
502
503 if files:
504 return [output_api.PresubmitError(
505 'Please avoid to use namespace `google::protobuf` directly.\n'
506 'Add a using directive in `%s` and include that header instead.'
507 % proto_utils_path, files)]
508 return []
509
510
ehmaldonadoea0e0842017-07-10 06:44:09 -0700511def _CheckNoChangesToWebRTCBase(input_api, output_api):
512 """Checks that no changes refer to webrtc/base."""
513 problems = []
514
515 for f in input_api.AffectedFiles():
516 if os.path.join('webrtc', 'base') in f.LocalPath():
517 problems.append(' ' + f.LocalPath())
518 continue
519 for line_num, line in f.ChangedContents():
520 if 'webrtc/base' in line:
521 problems.append(' %s: %s' % (f.LocalPath(), line_num))
522
ehmaldonadofe533552017-07-10 07:04:10 -0700523 if problems:
524 return [output_api.PresubmitPromptWarning(
525 'webrtc/base is being moved to webrtc/rtc_base (See '
526 'bugs.webrtc.org/7634). Please refer to webrtc/rtc_base instead in the '
527 'following files:\n' + '\n'.join(problems))]
528 return []
ehmaldonadoea0e0842017-07-10 06:44:09 -0700529
530
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000531def _CommonChecks(input_api, output_api):
532 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000533 results = []
tkchin42f580e2015-11-26 23:18:23 -0800534 # Filter out files that are in objc or ios dirs from being cpplint-ed since
535 # they do not follow C++ lint rules.
536 black_list = input_api.DEFAULT_BLACK_LIST + (
537 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000538 r".*objc\.[hcm]+$",
hjon65ae2d82016-08-02 23:55:44 -0700539 r"webrtc\/build\/ios\/SDK\/.*",
tkchin42f580e2015-11-26 23:18:23 -0800540 )
541 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
542 results.extend(_CheckApprovedFilesLintClean(
543 input_api, output_api, source_file_filter))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000544 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100545 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200546 r'^build[\\\/].*\.py$',
547 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-12 22:43:38 -0700548 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 12:01:17 +0100549 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200550 r'^out.*[\\\/].*\.py$',
551 r'^testing[\\\/].*\.py$',
552 r'^third_party[\\\/].*\.py$',
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100553 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 12:21:39 -0800554 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200555 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
556 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200557 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200558 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 Kjellanderb4af3d62016-11-16 20:11:29 +0100568 # Skip long-lines check for DEPS and GN files.
569 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
tkchin3cd9a302016-06-08 12:40:28 -0700570 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
571 black_list=build_file_filter_list + objc_filter_list)
572 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
573 white_list=objc_filter_list)
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000574 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700575 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
576 results.extend(input_api.canned_checks.CheckLongLines(
577 input_api, output_api, maxlen=100,
578 source_file_filter=hundred_char_sources))
579
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000580 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
581 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000582 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
583 input_api, output_api))
kjellandere5dc62a2016-12-14 00:16:21 -0800584 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
585 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000586 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
587 input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800588 results.extend(_CheckNativeApiHeaderChanges(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000589 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
kjellander6aeef742017-02-20 01:13:18 -0800590 results.extend(_CheckNoPragmaOnce(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000591 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700592 results.extend(_CheckGnChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000593 results.extend(_CheckUnwantedDependencies(input_api, output_api))
kjellander569cf942016-02-11 05:02:59 -0800594 results.extend(_CheckJSONParseErrors(input_api, output_api))
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200595 results.extend(_RunPythonTests(input_api, output_api))
mbonadei38415b22017-04-07 05:38:01 -0700596 results.extend(_CheckUsageOfGoogleProtobufNamespace(input_api, output_api))
mbonadei26c26342017-05-12 02:06:16 -0700597 results.extend(_CheckOrphanHeaders(input_api, output_api))
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200598 results.extend(_CheckNewLineAtTheEndOfProtoFiles(input_api, output_api))
ehmaldonadoea0e0842017-07-10 06:44:09 -0700599 results.extend(_CheckNoChangesToWebRTCBase(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000600 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000601
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000602
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000603def CheckChangeOnUpload(input_api, output_api):
604 results = []
605 results.extend(_CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200606 results.extend(
607 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000608 return results
609
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000610
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000611def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000612 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000613 results.extend(_CommonChecks(input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800614 results.extend(_VerifyNativeApiHeadersListIsValid(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000615 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000616 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
617 input_api, output_api))
618 results.extend(input_api.canned_checks.CheckChangeHasDescription(
619 input_api, output_api))
kjellanderd1e26a92016-09-19 08:11:16 -0700620 results.extend(_CheckChangeHasBugField(input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000621 results.extend(input_api.canned_checks.CheckTreeIsOpen(
622 input_api, output_api,
623 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000624 return results
mbonadei74973ed2017-05-09 07:58:05 -0700625
626
627def _CheckOrphanHeaders(input_api, output_api):
628 # We need to wait until we have an input_api object and use this
629 # roundabout construct to import prebubmit_checks_lib because this file is
630 # eval-ed and thus doesn't have __file__.
631 error_msg = """Header file {} is not listed in any GN target.
632 Please create a target or add it to an existing one in {}"""
633 results = []
634 original_sys_path = sys.path
635 try:
636 sys.path = sys.path + [input_api.os_path.join(
637 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')]
638 from check_orphan_headers import GetBuildGnPathFromFilePath
639 from check_orphan_headers import IsHeaderInBuildGn
640 finally:
641 # Restore sys.path to what it was before.
642 sys.path = original_sys_path
643
644 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
mbonadeia644ad32017-05-10 05:21:55 -0700645 if f.LocalPath().endswith('.h') and f.Action() == 'A':
mbonadei74973ed2017-05-09 07:58:05 -0700646 file_path = os.path.abspath(f.LocalPath())
647 root_dir = os.getcwd()
648 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
649 root_dir)
650 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
651 if not in_build_gn:
652 results.append(output_api.PresubmitError(error_msg.format(
653 file_path, gn_file_path)))
654 return results
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200655
656
657def _CheckNewLineAtTheEndOfProtoFiles(input_api, output_api):
658 """Checks that all .proto files are terminated with a newline."""
659 error_msg = 'File {} must end with exactly one newline.'
660 results = []
661 source_file_filter = lambda x: input_api.FilterSourceFile(
662 x, white_list=(r'.+\.proto$',))
663 for f in input_api.AffectedSourceFiles(source_file_filter):
664 file_path = f.LocalPath()
665 with open(file_path) as f:
666 lines = f.readlines()
667 if lines[-1] != '\n' or lines[-2] == '\n':
668 results.append(output_api.PresubmitError(error_msg.format(file_path)))
669 return results