blob: d29c4c41a04a14266ccb564b86eca9884c0d80d7 [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',
20 'webrtc/api/video_codecs/video_encoder.h',
oprypin2aa463f2017-03-23 03:17:02 -070021 'webrtc/examples/objc',
22 'webrtc/media',
23 'webrtc/modules/audio_coding',
24 'webrtc/modules/audio_conference_mixer',
25 'webrtc/modules/audio_device',
26 'webrtc/modules/audio_processing',
27 'webrtc/modules/desktop_capture',
28 'webrtc/modules/include/module_common_types.h',
29 'webrtc/modules/media_file',
30 'webrtc/modules/utility',
31 'webrtc/modules/video_capture',
32 'webrtc/p2p',
33 'webrtc/pc',
Henrik Kjellanderc0362762017-06-29 08:03:04 +020034 'webrtc/rtc_base',
oprypin2aa463f2017-03-23 03:17:02 -070035 'webrtc/sdk/android/src/jni',
36 'webrtc/sdk/objc',
37 'webrtc/system_wrappers',
38 'webrtc/test',
39 'webrtc/voice_engine',
oprypin2aa463f2017-03-23 03:17:02 -070040 'webrtc/common_types.h',
41 'webrtc/common_types.cc',
oprypin2aa463f2017-03-23 03:17:02 -070042 'webrtc/video_send_stream.h',
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +010043]
44
jbauchc4e3ead2016-02-19 00:25:55 -080045# These filters will always be removed, even if the caller specifies a filter
46# set, as they are problematic or broken in some way.
47#
48# Justifications for each filter:
49# - build/c++11 : Rvalue ref checks are unreliable (false positives),
50# include file and feature blacklists are
51# google3-specific.
kjellandere5a87a52016-04-27 02:32:12 -070052# - whitespace/operators: Same as above (doesn't seem sufficient to eliminate
53# all move-related errors).
jbauchc4e3ead2016-02-19 00:25:55 -080054BLACKLIST_LINT_FILTERS = [
55 '-build/c++11',
kjellandere5a87a52016-04-27 02:32:12 -070056 '-whitespace/operators',
jbauchc4e3ead2016-02-19 00:25:55 -080057]
58
kjellanderfd595232015-12-04 02:44:09 -080059# List of directories of "supported" native APIs. That means changes to headers
60# will be done in a compatible way following this scheme:
61# 1. Non-breaking changes are made.
62# 2. The old APIs as marked as deprecated (with comments).
63# 3. Deprecation is announced to discuss-webrtc@googlegroups.com and
64# webrtc-users@google.com (internal list).
65# 4. (later) The deprecated APIs are removed.
kjellander53047c92015-12-02 23:56:14 -080066NATIVE_API_DIRS = (
kjellander53047c92015-12-02 23:56:14 -080067 'webrtc',
kjellanderdd705472016-06-09 11:17:27 -070068 'webrtc/api',
69 'webrtc/media',
kjellander53047c92015-12-02 23:56:14 -080070 'webrtc/modules/audio_device/include',
kjellanderdd705472016-06-09 11:17:27 -070071 'webrtc/pc',
72)
73# These directories should not be used but are maintained only to avoid breaking
74# some legacy downstream code.
75LEGACY_API_DIRS = (
kjellanderdd705472016-06-09 11:17:27 -070076 'webrtc/common_audio/include',
77 'webrtc/modules/audio_coding/include',
78 'webrtc/modules/audio_conference_mixer/include',
kjellander53047c92015-12-02 23:56:14 -080079 'webrtc/modules/audio_processing/include',
80 'webrtc/modules/bitrate_controller/include',
Stefan Holmer80e12072016-02-23 13:30:42 +010081 'webrtc/modules/congestion_controller/include',
kjellander53047c92015-12-02 23:56:14 -080082 'webrtc/modules/include',
83 'webrtc/modules/remote_bitrate_estimator/include',
84 'webrtc/modules/rtp_rtcp/include',
kjellanderdd705472016-06-09 11:17:27 -070085 'webrtc/modules/rtp_rtcp/source',
kjellander53047c92015-12-02 23:56:14 -080086 'webrtc/modules/utility/include',
87 'webrtc/modules/video_coding/codecs/h264/include',
88 'webrtc/modules/video_coding/codecs/i420/include',
89 'webrtc/modules/video_coding/codecs/vp8/include',
90 'webrtc/modules/video_coding/codecs/vp9/include',
91 'webrtc/modules/video_coding/include',
ehmaldonadof6a861a2017-07-19 10:40:47 -070092 'webrtc/rtc_base',
kjellanderdd705472016-06-09 11:17:27 -070093 'webrtc/system_wrappers/include',
kjellander53047c92015-12-02 23:56:14 -080094 'webrtc/voice_engine/include',
95)
kjellanderdd705472016-06-09 11:17:27 -070096API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-02 23:56:14 -080097
98
ehmaldonado4fb97462017-01-30 05:27:22 -080099def _RunCommand(command, cwd):
100 """Runs a command and returns the output from that command."""
101 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
102 cwd=cwd)
103 stdout = p.stdout.read()
104 stderr = p.stderr.read()
105 p.wait()
106 p.stdout.close()
107 p.stderr.close()
108 return p.returncode, stdout, stderr
109
110
kjellander53047c92015-12-02 23:56:14 -0800111def _VerifyNativeApiHeadersListIsValid(input_api, output_api):
112 """Ensures the list of native API header directories is up to date."""
113 non_existing_paths = []
114 native_api_full_paths = [
115 input_api.os_path.join(input_api.PresubmitLocalPath(),
kjellanderdd705472016-06-09 11:17:27 -0700116 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-02 23:56:14 -0800117 for path in native_api_full_paths:
118 if not os.path.isdir(path):
119 non_existing_paths.append(path)
120 if non_existing_paths:
121 return [output_api.PresubmitError(
122 'Directories to native API headers have changed which has made the '
123 'list in PRESUBMIT.py outdated.\nPlease update it to the current '
124 'location of our native APIs.',
125 non_existing_paths)]
126 return []
127
kjellanderc88b5d52017-04-05 06:42:43 -0700128API_CHANGE_MSG = """
kwibergeb133022016-04-07 07:41:48 -0700129You seem to be changing native API header files. Please make sure that you:
oprypin375b9ac2017-02-13 04:13:23 -0800130 1. Make compatible changes that don't break existing clients. Usually
131 this is done by keeping the existing method signatures unchanged.
132 2. Mark the old stuff as deprecated (see RTC_DEPRECATED macro).
kwibergeb133022016-04-07 07:41:48 -0700133 3. Create a timeline and plan for when the deprecated stuff will be
134 removed. (The amount of time we give users to change their code
135 should be informed by how much work it is for them. If they just
136 need to replace one name with another or something equally
137 simple, 1-2 weeks might be good; if they need to do serious work,
138 up to 3 months may be called for.)
139 4. Update/inform existing downstream code owners to stop using the
140 deprecated stuff. (Send announcements to
141 discuss-webrtc@googlegroups.com and webrtc-users@google.com.)
142 5. Remove the deprecated stuff, once the agreed-upon amount of time
143 has passed.
144Related files:
145"""
kjellander53047c92015-12-02 23:56:14 -0800146
147def _CheckNativeApiHeaderChanges(input_api, output_api):
148 """Checks to remind proper changing of native APIs."""
149 files = []
150 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
151 if f.LocalPath().endswith('.h'):
kjellanderdd705472016-06-09 11:17:27 -0700152 for path in API_DIRS:
kjellander53047c92015-12-02 23:56:14 -0800153 if os.path.dirname(f.LocalPath()) == path:
154 files.append(f)
155
156 if files:
kjellanderc88b5d52017-04-05 06:42:43 -0700157 return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
kjellander53047c92015-12-02 23:56:14 -0800158 return []
159
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100160
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000161def _CheckNoIOStreamInHeaders(input_api, output_api):
162 """Checks to make sure no .h files include <iostream>."""
163 files = []
164 pattern = input_api.re.compile(r'^#include\s*<iostream>',
165 input_api.re.MULTILINE)
166 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
167 if not f.LocalPath().endswith('.h'):
168 continue
169 contents = input_api.ReadFile(f)
170 if pattern.search(contents):
171 files.append(f)
172
173 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200174 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000175 'Do not #include <iostream> in header files, since it inserts static ' +
176 'initialization into every file including the header. Instead, ' +
177 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200178 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000179 return []
180
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000181
kjellander6aeef742017-02-20 01:13:18 -0800182def _CheckNoPragmaOnce(input_api, output_api):
183 """Make sure that banned functions are not used."""
184 files = []
185 pattern = input_api.re.compile(r'^#pragma\s+once',
186 input_api.re.MULTILINE)
187 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
188 if not f.LocalPath().endswith('.h'):
189 continue
190 contents = input_api.ReadFile(f)
191 if pattern.search(contents):
192 files.append(f)
193
194 if files:
195 return [output_api.PresubmitError(
196 'Do not use #pragma once in header files.\n'
197 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
198 files)]
199 return []
200
201
kjellanderc88b5d52017-04-05 06:42:43 -0700202def _CheckNoFRIEND_TEST(input_api, output_api): # pylint: disable=invalid-name
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000203 """Make sure that gtest's FRIEND_TEST() macro is not used, the
204 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
205 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
206 problems = []
207
208 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
209 for f in input_api.AffectedFiles(file_filter=file_filter):
210 for line_num, line in f.ChangedContents():
211 if 'FRIEND_TEST(' in line:
212 problems.append(' %s:%d' % (f.LocalPath(), line_num))
213
214 if not problems:
215 return []
216 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
217 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
218 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
219
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000220
oprypin2aa463f2017-03-23 03:17:02 -0700221def _IsLintBlacklisted(blacklist_paths, file_path):
222 """ Checks if a file is blacklisted for lint check."""
223 for path in blacklist_paths:
224 if file_path == path or os.path.dirname(file_path).startswith(path):
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100225 return True
226 return False
227
228
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000229def _CheckApprovedFilesLintClean(input_api, output_api,
230 source_file_filter=None):
oprypin2aa463f2017-03-23 03:17:02 -0700231 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000232 This check is based on _CheckChangeLintsClean in
233 depot_tools/presubmit_canned_checks.py but has less filters and only checks
234 added files."""
235 result = []
236
237 # Initialize cpplint.
238 import cpplint
239 # Access to a protected member _XX of a client class
240 # pylint: disable=W0212
241 cpplint._cpplint_state.ResetErrorCounts()
242
jbauchc4e3ead2016-02-19 00:25:55 -0800243 lint_filters = cpplint._Filters()
244 lint_filters.extend(BLACKLIST_LINT_FILTERS)
245 cpplint._SetFilters(','.join(lint_filters))
246
oprypin2aa463f2017-03-23 03:17:02 -0700247 # Create a platform independent blacklist for cpplint.
248 blacklist_paths = [input_api.os_path.join(*path.split('/'))
249 for path in CPPLINT_BLACKLIST]
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100250
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000251 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 03:17:02 -0700252 # default when running cpplint.py from command line. To make it possible to
253 # work with not-yet-converted code, we're only applying it to new (or
254 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000255 verbosity_level = 1
256 files = []
257 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200258 # Note that moved/renamed files also count as added.
oprypin2aa463f2017-03-23 03:17:02 -0700259 if f.Action() == 'A' or not _IsLintBlacklisted(blacklist_paths,
260 f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000261 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000262
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000263 for file_name in files:
264 cpplint.ProcessFile(file_name, verbosity_level)
265
266 if cpplint._cpplint_state.error_count > 0:
267 if input_api.is_committing:
oprypin8e58d652017-03-21 07:52:41 -0700268 res_type = output_api.PresubmitError
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000269 else:
270 res_type = output_api.PresubmitPromptWarning
271 result = [res_type('Changelist failed cpplint.py check.')]
272
273 return result
274
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100275def _CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700276 # Disallow referencing source files with paths above the GN file location.
277 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
278 re.MULTILINE | re.DOTALL)
279 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
280 violating_gn_files = set()
281 violating_source_entries = []
282 for gn_file in gn_files:
283 contents = input_api.ReadFile(gn_file)
284 for source_block_match in source_pattern.finditer(contents):
285 # Find all source list entries starting with ../ in the source block
286 # (exclude overrides entries).
287 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
288 source_file = file_list_match.group(1)
289 if 'overrides/' not in source_file:
290 violating_source_entries.append(source_file)
291 violating_gn_files.add(gn_file)
292 if violating_gn_files:
293 return [output_api.PresubmitError(
294 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100295 'allowed. Please introduce new GN targets in the proper location '
296 'instead.\n'
ehmaldonado5b1ba082016-09-02 05:51:08 -0700297 'Invalid source entries:\n'
298 '%s\n'
299 'Violating GN files:' % '\n'.join(violating_source_entries),
300 items=violating_gn_files)]
301 return []
302
kjellander7439f972016-12-05 22:47:46 -0800303def _CheckNoMixingCAndCCSources(input_api, gn_files, output_api):
304 # Disallow mixing .c and .cc source files in the same target.
305 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
306 re.MULTILINE | re.DOTALL)
307 file_pattern = input_api.re.compile(r'"(.*)"')
308 violating_gn_files = dict()
309 for gn_file in gn_files:
310 contents = input_api.ReadFile(gn_file)
311 for source_block_match in source_pattern.finditer(contents):
312 c_files = []
313 cc_files = []
314 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
315 source_file = file_list_match.group(1)
316 if source_file.endswith('.c'):
317 c_files.append(source_file)
318 if source_file.endswith('.cc'):
319 cc_files.append(source_file)
320 if c_files and cc_files:
321 violating_gn_files[gn_file.LocalPath()] = sorted(c_files + cc_files)
322 if violating_gn_files:
323 return [output_api.PresubmitError(
324 'GN targets cannot mix .cc and .c source files. Please create a '
325 'separate target for each collection of sources.\n'
326 'Mixed sources: \n'
327 '%s\n'
328 'Violating GN files:' % json.dumps(violating_gn_files, indent=2),
329 items=violating_gn_files.keys())]
330 return []
331
ehmaldonado4fb97462017-01-30 05:27:22 -0800332def _CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
333 cwd = input_api.PresubmitLocalPath()
mbonadeiab587dc2017-05-12 04:13:31 -0700334 script_path = os.path.join('tools_webrtc', 'presubmit_checks_lib',
335 'check_package_boundaries.py')
ehmaldonado4fb97462017-01-30 05:27:22 -0800336 webrtc_path = os.path.join('webrtc')
337 command = [sys.executable, script_path, webrtc_path]
338 command += [gn_file.LocalPath() for gn_file in gn_files]
339 returncode, _, stderr = _RunCommand(command, cwd)
340 if returncode:
341 return [output_api.PresubmitError(
342 'There are package boundary violations in the following GN files:\n\n'
343 '%s' % stderr)]
344 return []
345
ehmaldonado5b1ba082016-09-02 05:51:08 -0700346def _CheckGnChanges(input_api, output_api):
347 source_file_filter = lambda x: input_api.FilterSourceFile(
348 x, white_list=(r'.+\.(gn|gni)$',))
349
350 gn_files = []
351 for f in input_api.AffectedSourceFiles(source_file_filter):
352 if f.LocalPath().startswith('webrtc'):
353 gn_files.append(f)
354
355 result = []
356 if gn_files:
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100357 result.extend(_CheckNoSourcesAbove(input_api, gn_files, output_api))
kjellander7439f972016-12-05 22:47:46 -0800358 result.extend(_CheckNoMixingCAndCCSources(input_api, gn_files, output_api))
ehmaldonado4fb97462017-01-30 05:27:22 -0800359 result.extend(_CheckNoPackageBoundaryViolations(
360 input_api, gn_files, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700361 return result
362
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000363def _CheckUnwantedDependencies(input_api, output_api):
364 """Runs checkdeps on #include statements added in this
365 change. Breaking - rules is an error, breaking ! rules is a
366 warning.
367 """
368 # Copied from Chromium's src/PRESUBMIT.py.
369
370 # We need to wait until we have an input_api object and use this
371 # roundabout construct to import checkdeps because this file is
372 # eval-ed and thus doesn't have __file__.
373 original_sys_path = sys.path
374 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000375 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
376 'buildtools', 'checkdeps')
377 if not os.path.exists(checkdeps_path):
378 return [output_api.PresubmitError(
379 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
380 'download Chromium and setup the symlinks?' % checkdeps_path)]
381 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000382 import checkdeps
383 from cpp_checker import CppChecker
384 from rules import Rule
385 finally:
386 # Restore sys.path to what it was before.
387 sys.path = original_sys_path
388
389 added_includes = []
390 for f in input_api.AffectedFiles():
391 if not CppChecker.IsCppFile(f.LocalPath()):
392 continue
393
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200394 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000395 added_includes.append([f.LocalPath(), changed_lines])
396
397 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
398
399 error_descriptions = []
400 warning_descriptions = []
401 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
402 added_includes):
403 description_with_path = '%s\n %s' % (path, rule_description)
404 if rule_type == Rule.DISALLOW:
405 error_descriptions.append(description_with_path)
406 else:
407 warning_descriptions.append(description_with_path)
408
409 results = []
410 if error_descriptions:
411 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 03:47:05 -0700412 'You added one or more #includes that violate checkdeps rules.\n'
413 'Check that the DEPS files in these locations contain valid rules.\n'
414 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
415 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000416 error_descriptions))
417 if warning_descriptions:
418 results.append(output_api.PresubmitPromptOrNotify(
419 'You added one or more #includes of files that are temporarily\n'
420 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 03:47:05 -0700421 '#include? See relevant DEPS file(s) for details and contacts.\n'
422 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
423 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000424 warning_descriptions))
425 return results
426
kjellanderd1e26a92016-09-19 08:11:16 -0700427def _CheckChangeHasBugField(input_api, output_api):
428 """Requires that the changelist have a BUG= field.
429
430 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
431 since it fails the presubmit if the BUG= field is missing or doesn't contain
432 a bug reference.
433 """
434 if input_api.change.BUG:
435 return []
436 else:
437 return [output_api.PresubmitError(
438 'The BUG=[bug number] field is mandatory. Please create a bug and '
439 'reference it using either of:\n'
440 ' * https://bugs.webrtc.org - reference it using BUG=webrtc:XXXX\n'
441 ' * https://crbug.com - reference it using BUG=chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000442
kjellander569cf942016-02-11 05:02:59 -0800443def _CheckJSONParseErrors(input_api, output_api):
444 """Check that JSON files do not contain syntax errors."""
445
446 def FilterFile(affected_file):
447 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
448
449 def GetJSONParseError(input_api, filename):
450 try:
451 contents = input_api.ReadFile(filename)
452 input_api.json.loads(contents)
453 except ValueError as e:
454 return e
455 return None
456
457 results = []
458 for affected_file in input_api.AffectedFiles(
459 file_filter=FilterFile, include_deletes=False):
460 parse_error = GetJSONParseError(input_api,
461 affected_file.AbsoluteLocalPath())
462 if parse_error:
463 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
464 (affected_file.LocalPath(), parse_error)))
465 return results
466
467
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200468def _RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 06:42:43 -0700469 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200470 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
471
472 test_directories = [
kjellander41bafb22017-06-30 04:14:54 -0700473 Join('webrtc', 'rtc_tools', 'py_event_log_analyzer'),
474 Join('webrtc', 'rtc_tools'),
oprypinabd101b2017-04-06 23:21:30 -0700475 Join('webrtc', 'audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 05:27:22 -0800476 ] + [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200477 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 05:27:22 -0800478 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200479 ]
480
481 tests = []
482 for directory in test_directories:
483 tests.extend(
484 input_api.canned_checks.GetUnitTestsInDirectory(
485 input_api,
486 output_api,
487 directory,
488 whitelist=[r'.+_test\.py$']))
489 return input_api.RunTests(tests, parallel=True)
490
491
mbonadei38415b22017-04-07 05:38:01 -0700492def _CheckUsageOfGoogleProtobufNamespace(input_api, output_api):
493 """Checks that the namespace google::protobuf has not been used."""
494 files = []
495 pattern = input_api.re.compile(r'google::protobuf')
496 proto_utils_path = os.path.join('webrtc', 'base', 'protobuf_utils.h')
497 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
498 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
499 continue
500 contents = input_api.ReadFile(f)
501 if pattern.search(contents):
502 files.append(f)
503
504 if files:
505 return [output_api.PresubmitError(
506 'Please avoid to use namespace `google::protobuf` directly.\n'
507 'Add a using directive in `%s` and include that header instead.'
508 % proto_utils_path, files)]
509 return []
510
511
ehmaldonadoea0e0842017-07-10 06:44:09 -0700512def _CheckNoChangesToWebRTCBase(input_api, output_api):
513 """Checks that no changes refer to webrtc/base."""
514 problems = []
515
516 for f in input_api.AffectedFiles():
517 if os.path.join('webrtc', 'base') in f.LocalPath():
518 problems.append(' ' + f.LocalPath())
519 continue
520 for line_num, line in f.ChangedContents():
521 if 'webrtc/base' in line:
522 problems.append(' %s: %s' % (f.LocalPath(), line_num))
523
ehmaldonadofe533552017-07-10 07:04:10 -0700524 if problems:
525 return [output_api.PresubmitPromptWarning(
526 'webrtc/base is being moved to webrtc/rtc_base (See '
527 'bugs.webrtc.org/7634). Please refer to webrtc/rtc_base instead in the '
528 'following files:\n' + '\n'.join(problems))]
529 return []
ehmaldonadoea0e0842017-07-10 06:44:09 -0700530
531
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000532def _CommonChecks(input_api, output_api):
533 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000534 results = []
tkchin42f580e2015-11-26 23:18:23 -0800535 # Filter out files that are in objc or ios dirs from being cpplint-ed since
536 # they do not follow C++ lint rules.
537 black_list = input_api.DEFAULT_BLACK_LIST + (
538 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000539 r".*objc\.[hcm]+$",
hjon65ae2d82016-08-02 23:55:44 -0700540 r"webrtc\/build\/ios\/SDK\/.*",
tkchin42f580e2015-11-26 23:18:23 -0800541 )
542 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
543 results.extend(_CheckApprovedFilesLintClean(
544 input_api, output_api, source_file_filter))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000545 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100546 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200547 r'^build[\\\/].*\.py$',
548 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-12 22:43:38 -0700549 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 12:01:17 +0100550 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200551 r'^out.*[\\\/].*\.py$',
552 r'^testing[\\\/].*\.py$',
553 r'^third_party[\\\/].*\.py$',
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100554 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 12:21:39 -0800555 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200556 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
557 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200558 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200559 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800560
nisse3d21e232016-09-02 03:07:06 -0700561 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200562 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
563 # we need to have different license checks in talk/ and webrtc/ directories.
564 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200565
tkchin3cd9a302016-06-08 12:40:28 -0700566 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
567 # ObjC subdirectories ObjC headers.
568 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100569 # Skip long-lines check for DEPS and GN files.
570 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
tkchin3cd9a302016-06-08 12:40:28 -0700571 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))
kjellandere5dc62a2016-12-14 00:16:21 -0800585 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
586 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000587 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
588 input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800589 results.extend(_CheckNativeApiHeaderChanges(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000590 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
kjellander6aeef742017-02-20 01:13:18 -0800591 results.extend(_CheckNoPragmaOnce(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000592 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700593 results.extend(_CheckGnChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000594 results.extend(_CheckUnwantedDependencies(input_api, output_api))
kjellander569cf942016-02-11 05:02:59 -0800595 results.extend(_CheckJSONParseErrors(input_api, output_api))
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200596 results.extend(_RunPythonTests(input_api, output_api))
mbonadei38415b22017-04-07 05:38:01 -0700597 results.extend(_CheckUsageOfGoogleProtobufNamespace(input_api, output_api))
mbonadei26c26342017-05-12 02:06:16 -0700598 results.extend(_CheckOrphanHeaders(input_api, output_api))
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200599 results.extend(_CheckNewLineAtTheEndOfProtoFiles(input_api, output_api))
ehmaldonadoea0e0842017-07-10 06:44:09 -0700600 results.extend(_CheckNoChangesToWebRTCBase(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000601 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000602
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000603
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000604def CheckChangeOnUpload(input_api, output_api):
605 results = []
606 results.extend(_CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200607 results.extend(
608 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000609 return results
610
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000611
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000612def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000613 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000614 results.extend(_CommonChecks(input_api, output_api))
kjellander53047c92015-12-02 23:56:14 -0800615 results.extend(_VerifyNativeApiHeadersListIsValid(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000616 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000617 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
618 input_api, output_api))
619 results.extend(input_api.canned_checks.CheckChangeHasDescription(
620 input_api, output_api))
kjellanderd1e26a92016-09-19 08:11:16 -0700621 results.extend(_CheckChangeHasBugField(input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000622 results.extend(input_api.canned_checks.CheckTreeIsOpen(
623 input_api, output_api,
624 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000625 return results
mbonadei74973ed2017-05-09 07:58:05 -0700626
627
628def _CheckOrphanHeaders(input_api, output_api):
629 # We need to wait until we have an input_api object and use this
630 # roundabout construct to import prebubmit_checks_lib because this file is
631 # eval-ed and thus doesn't have __file__.
632 error_msg = """Header file {} is not listed in any GN target.
633 Please create a target or add it to an existing one in {}"""
634 results = []
635 original_sys_path = sys.path
636 try:
637 sys.path = sys.path + [input_api.os_path.join(
638 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')]
639 from check_orphan_headers import GetBuildGnPathFromFilePath
640 from check_orphan_headers import IsHeaderInBuildGn
641 finally:
642 # Restore sys.path to what it was before.
643 sys.path = original_sys_path
644
645 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
mbonadeia644ad32017-05-10 05:21:55 -0700646 if f.LocalPath().endswith('.h') and f.Action() == 'A':
mbonadei74973ed2017-05-09 07:58:05 -0700647 file_path = os.path.abspath(f.LocalPath())
648 root_dir = os.getcwd()
649 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
650 root_dir)
651 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
652 if not in_build_gn:
653 results.append(output_api.PresubmitError(error_msg.format(
654 file_path, gn_file_path)))
655 return results
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200656
657
658def _CheckNewLineAtTheEndOfProtoFiles(input_api, output_api):
659 """Checks that all .proto files are terminated with a newline."""
660 error_msg = 'File {} must end with exactly one newline.'
661 results = []
662 source_file_filter = lambda x: input_api.FilterSourceFile(
663 x, white_list=(r'.+\.proto$',))
664 for f in input_api.AffectedSourceFiles(source_file_filter):
665 file_path = f.LocalPath()
666 with open(file_path) as f:
667 lines = f.readlines()
668 if lines[-1] != '\n' or lines[-2] == '\n':
669 results.append(output_api.PresubmitError(error_msg.format(file_path)))
670 return results