Thanks to visit codestin.com
Credit goes to webrtc.googlesource.com

blob: 88e4fb8db10841d6cc5bcb5a76886e7fb36858ba [file] [log] [blame]
[email protected]2442de12012-01-23 17:45:411# 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.
[email protected]da159d62011-05-30 11:51:348
kjellander7439f972016-12-06 06:47:469import json
[email protected]aefe61a2014-12-08 13:00:3010import os
[email protected]85759802013-10-22 16:47:4011import re
ehmaldonado4fb97462017-01-30 13:27:2212import subprocess
[email protected]3bd41562014-09-01 11:06:3713import sys
Mirko Bonadei4dc4e252017-09-19 11:49:1614from collections import defaultdict
[email protected]85759802013-10-22 16:47:4015
16
oprypin2aa463f2017-03-23 10:17:0217# Files and directories that are *skipped* by cpplint in the presubmit script.
18CPPLINT_BLACKLIST = [
Mirko Bonadei92ea95e2017-09-15 04:47:3119 'api/video_codecs/video_decoder.h',
20 'common_types.cc',
21 'common_types.h',
22 'examples/objc',
23 'media',
24 'modules/audio_coding',
25 'modules/audio_conference_mixer',
26 'modules/audio_device',
27 'modules/audio_processing',
28 'modules/desktop_capture',
29 'modules/include/module_common_types.h',
30 'modules/media_file',
31 'modules/utility',
32 'modules/video_capture',
33 'p2p',
34 'pc',
35 'rtc_base',
36 'sdk/android/src/jni',
37 'sdk/objc',
38 'system_wrappers',
39 'test',
Henrik Kjellander90fd7d82017-05-09 06:30:1040 'tools_webrtc',
Mirko Bonadei92ea95e2017-09-15 04:47:3141 'voice_engine',
[email protected]0fcaf992015-11-26 14:24:5242]
43
jbauchc4e3ead2016-02-19 08:25:5544# 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 09:32:1251# - whitespace/operators: Same as above (doesn't seem sufficient to eliminate
52# all move-related errors).
jbauchc4e3ead2016-02-19 08:25:5553BLACKLIST_LINT_FILTERS = [
54 '-build/c++11',
kjellandere5a87a52016-04-27 09:32:1255 '-whitespace/operators',
jbauchc4e3ead2016-02-19 08:25:5556]
57
kjellanderfd595232015-12-04 10:44:0958# 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 [email protected] and
63# [email protected] (internal list).
64# 4. (later) The deprecated APIs are removed.
kjellander53047c92015-12-03 07:56:1465NATIVE_API_DIRS = (
Mirko Bonadei92ea95e2017-09-15 04:47:3166 'api',
67 'media',
68 'modules/audio_device/include',
69 'pc',
kjellanderdd705472016-06-09 18:17:2770)
Mirko Bonadei4dc4e252017-09-19 11:49:1671
kjellanderdd705472016-06-09 18:17:2772# These directories should not be used but are maintained only to avoid breaking
73# some legacy downstream code.
74LEGACY_API_DIRS = (
Mirko Bonadei92ea95e2017-09-15 04:47:3175 'common_audio/include',
76 'modules/audio_coding/include',
77 'modules/audio_conference_mixer/include',
78 'modules/audio_processing/include',
79 'modules/bitrate_controller/include',
80 'modules/congestion_controller/include',
81 'modules/include',
82 'modules/remote_bitrate_estimator/include',
83 'modules/rtp_rtcp/include',
84 'modules/rtp_rtcp/source',
85 'modules/utility/include',
86 'modules/video_coding/codecs/h264/include',
87 'modules/video_coding/codecs/i420/include',
88 'modules/video_coding/codecs/vp8/include',
89 'modules/video_coding/codecs/vp9/include',
90 'modules/video_coding/include',
91 'rtc_base',
92 'system_wrappers/include',
93 'voice_engine/include',
kjellander53047c92015-12-03 07:56:1494)
Mirko Bonadei4dc4e252017-09-19 11:49:1695
kjellanderdd705472016-06-09 18:17:2796API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-03 07:56:1497
Mirko Bonadei4dc4e252017-09-19 11:49:1698# TARGET_RE matches a GN target, and extracts the target name and the contents.
99TARGET_RE = re.compile(r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {'
100 r'(?P<target_contents>.*?)'
101 r'(?P=indent)}',
102 re.MULTILINE | re.DOTALL)
103
104# SOURCES_RE matches a block of sources inside a GN target.
105SOURCES_RE = re.compile(r'sources \+?= \[(?P<sources>.*?)\]',
106 re.MULTILINE | re.DOTALL)
107
108# FILE_PATH_RE matchies a file path.
109FILE_PATH_RE = re.compile(r'"(?P<file_path>(\w|\/)+)(?P<extension>\.\w+)"')
110
kjellander53047c92015-12-03 07:56:14111
ehmaldonado4fb97462017-01-30 13:27:22112def _RunCommand(command, cwd):
113 """Runs a command and returns the output from that command."""
114 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
115 cwd=cwd)
116 stdout = p.stdout.read()
117 stderr = p.stderr.read()
118 p.wait()
119 p.stdout.close()
120 p.stderr.close()
121 return p.returncode, stdout, stderr
122
123
charujain9893e252017-09-14 11:33:22124def VerifyNativeApiHeadersListIsValid(input_api, output_api):
kjellander53047c92015-12-03 07:56:14125 """Ensures the list of native API header directories is up to date."""
126 non_existing_paths = []
127 native_api_full_paths = [
128 input_api.os_path.join(input_api.PresubmitLocalPath(),
kjellanderdd705472016-06-09 18:17:27129 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-03 07:56:14130 for path in native_api_full_paths:
131 if not os.path.isdir(path):
132 non_existing_paths.append(path)
133 if non_existing_paths:
134 return [output_api.PresubmitError(
135 'Directories to native API headers have changed which has made the '
136 'list in PRESUBMIT.py outdated.\nPlease update it to the current '
137 'location of our native APIs.',
138 non_existing_paths)]
139 return []
140
kjellanderc88b5d52017-04-05 13:42:43141API_CHANGE_MSG = """
kwibergeb133022016-04-07 14:41:48142You seem to be changing native API header files. Please make sure that you:
oprypin375b9ac2017-02-13 12:13:23143 1. Make compatible changes that don't break existing clients. Usually
144 this is done by keeping the existing method signatures unchanged.
145 2. Mark the old stuff as deprecated (see RTC_DEPRECATED macro).
kwibergeb133022016-04-07 14:41:48146 3. Create a timeline and plan for when the deprecated stuff will be
147 removed. (The amount of time we give users to change their code
148 should be informed by how much work it is for them. If they just
149 need to replace one name with another or something equally
150 simple, 1-2 weeks might be good; if they need to do serious work,
151 up to 3 months may be called for.)
152 4. Update/inform existing downstream code owners to stop using the
153 deprecated stuff. (Send announcements to
154 [email protected] and [email protected].)
155 5. Remove the deprecated stuff, once the agreed-upon amount of time
156 has passed.
157Related files:
158"""
kjellander53047c92015-12-03 07:56:14159
charujain9893e252017-09-14 11:33:22160def CheckNativeApiHeaderChanges(input_api, output_api):
kjellander53047c92015-12-03 07:56:14161 """Checks to remind proper changing of native APIs."""
162 files = []
163 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
164 if f.LocalPath().endswith('.h'):
kjellanderdd705472016-06-09 18:17:27165 for path in API_DIRS:
kjellander53047c92015-12-03 07:56:14166 if os.path.dirname(f.LocalPath()) == path:
167 files.append(f)
168
169 if files:
kjellanderc88b5d52017-04-05 13:42:43170 return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
kjellander53047c92015-12-03 07:56:14171 return []
172
[email protected]0fcaf992015-11-26 14:24:52173
charujain9893e252017-09-14 11:33:22174def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]51198f12012-02-21 17:53:46175 """Checks to make sure no .h files include <iostream>."""
176 files = []
177 pattern = input_api.re.compile(r'^#include\s*<iostream>',
178 input_api.re.MULTILINE)
179 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
180 if not f.LocalPath().endswith('.h'):
181 continue
182 contents = input_api.ReadFile(f)
183 if pattern.search(contents):
184 files.append(f)
185
186 if len(files):
Henrik Kjellander57e5fd22015-05-25 10:55:39187 return [output_api.PresubmitError(
[email protected]51198f12012-02-21 17:53:46188 'Do not #include <iostream> in header files, since it inserts static ' +
189 'initialization into every file including the header. Instead, ' +
190 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 10:55:39191 files)]
[email protected]51198f12012-02-21 17:53:46192 return []
193
[email protected]e4158642014-08-06 09:11:18194
charujain9893e252017-09-14 11:33:22195def CheckNoPragmaOnce(input_api, output_api):
kjellander6aeef742017-02-20 09:13:18196 """Make sure that banned functions are not used."""
197 files = []
198 pattern = input_api.re.compile(r'^#pragma\s+once',
199 input_api.re.MULTILINE)
200 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
201 if not f.LocalPath().endswith('.h'):
202 continue
203 contents = input_api.ReadFile(f)
204 if pattern.search(contents):
205 files.append(f)
206
207 if files:
208 return [output_api.PresubmitError(
209 'Do not use #pragma once in header files.\n'
210 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
211 files)]
212 return []
213
214
charujain9893e252017-09-14 11:33:22215def CheckNoFRIEND_TEST(input_api, output_api): # pylint: disable=invalid-name
[email protected]51198f12012-02-21 17:53:46216 """Make sure that gtest's FRIEND_TEST() macro is not used, the
217 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
218 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
219 problems = []
220
221 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
222 for f in input_api.AffectedFiles(file_filter=file_filter):
223 for line_num, line in f.ChangedContents():
224 if 'FRIEND_TEST(' in line:
225 problems.append(' %s:%d' % (f.LocalPath(), line_num))
226
227 if not problems:
228 return []
229 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
230 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
231 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
232
[email protected]e4158642014-08-06 09:11:18233
charujain9893e252017-09-14 11:33:22234def IsLintBlacklisted(blacklist_paths, file_path):
oprypin2aa463f2017-03-23 10:17:02235 """ Checks if a file is blacklisted for lint check."""
236 for path in blacklist_paths:
237 if file_path == path or os.path.dirname(file_path).startswith(path):
[email protected]0fcaf992015-11-26 14:24:52238 return True
239 return False
240
241
charujain9893e252017-09-14 11:33:22242def CheckApprovedFilesLintClean(input_api, output_api,
[email protected]2a452092012-07-01 05:55:23243 source_file_filter=None):
oprypin2aa463f2017-03-23 10:17:02244 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
charujain9893e252017-09-14 11:33:22245 This check is based on CheckChangeLintsClean in
[email protected]51198f12012-02-21 17:53:46246 depot_tools/presubmit_canned_checks.py but has less filters and only checks
247 added files."""
248 result = []
249
250 # Initialize cpplint.
251 import cpplint
252 # Access to a protected member _XX of a client class
253 # pylint: disable=W0212
254 cpplint._cpplint_state.ResetErrorCounts()
255
jbauchc4e3ead2016-02-19 08:25:55256 lint_filters = cpplint._Filters()
257 lint_filters.extend(BLACKLIST_LINT_FILTERS)
258 cpplint._SetFilters(','.join(lint_filters))
259
oprypin2aa463f2017-03-23 10:17:02260 # Create a platform independent blacklist for cpplint.
261 blacklist_paths = [input_api.os_path.join(*path.split('/'))
262 for path in CPPLINT_BLACKLIST]
[email protected]0fcaf992015-11-26 14:24:52263
[email protected]51198f12012-02-21 17:53:46264 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 10:17:02265 # default when running cpplint.py from command line. To make it possible to
266 # work with not-yet-converted code, we're only applying it to new (or
267 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
[email protected]51198f12012-02-21 17:53:46268 verbosity_level = 1
269 files = []
270 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 10:55:39271 # Note that moved/renamed files also count as added.
charujain9893e252017-09-14 11:33:22272 if f.Action() == 'A' or not IsLintBlacklisted(blacklist_paths,
oprypin2aa463f2017-03-23 10:17:02273 f.LocalPath()):
[email protected]51198f12012-02-21 17:53:46274 files.append(f.AbsoluteLocalPath())
[email protected]2a452092012-07-01 05:55:23275
[email protected]51198f12012-02-21 17:53:46276 for file_name in files:
277 cpplint.ProcessFile(file_name, verbosity_level)
278
279 if cpplint._cpplint_state.error_count > 0:
280 if input_api.is_committing:
oprypin8e58d652017-03-21 14:52:41281 res_type = output_api.PresubmitError
[email protected]51198f12012-02-21 17:53:46282 else:
283 res_type = output_api.PresubmitPromptWarning
284 result = [res_type('Changelist failed cpplint.py check.')]
285
286 return result
287
charujain9893e252017-09-14 11:33:22288def CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 12:51:08289 # Disallow referencing source files with paths above the GN file location.
290 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
291 re.MULTILINE | re.DOTALL)
292 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
293 violating_gn_files = set()
294 violating_source_entries = []
295 for gn_file in gn_files:
296 contents = input_api.ReadFile(gn_file)
297 for source_block_match in source_pattern.finditer(contents):
298 # Find all source list entries starting with ../ in the source block
299 # (exclude overrides entries).
300 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
301 source_file = file_list_match.group(1)
302 if 'overrides/' not in source_file:
303 violating_source_entries.append(source_file)
304 violating_gn_files.add(gn_file)
305 if violating_gn_files:
306 return [output_api.PresubmitError(
307 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 19:11:29308 'allowed. Please introduce new GN targets in the proper location '
309 'instead.\n'
ehmaldonado5b1ba082016-09-02 12:51:08310 'Invalid source entries:\n'
311 '%s\n'
312 'Violating GN files:' % '\n'.join(violating_source_entries),
313 items=violating_gn_files)]
314 return []
315
Mirko Bonadei4dc4e252017-09-19 11:49:16316def CheckNoMixingSources(input_api, gn_files, output_api):
317 """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target.
318
319 See bugs.webrtc.org/7743 for more context.
320 """
321 def _MoreThanOneSourceUsed(*sources_lists):
322 sources_used = 0
323 for source_list in sources_lists:
324 if len(source_list):
325 sources_used += 1
326 return sources_used > 1
327
328 errors = defaultdict(lambda: [])
kjellander7439f972016-12-06 06:47:46329 for gn_file in gn_files:
Mirko Bonadei4dc4e252017-09-19 11:49:16330 gn_file_content = input_api.ReadFile(gn_file)
331 for target_match in TARGET_RE.finditer(gn_file_content):
332 # list_of_sources is a list of tuples of the form
333 # (c_files, cc_files, objc_files) that keeps track of all the sources
334 # defined in a target. A GN target can have more that on definition of
335 # sources (since it supports if/else statements).
336 # E.g.:
337 # rtc_static_library("foo") {
338 # if (is_win) {
339 # sources = [ "foo.cc" ]
340 # } else {
341 # sources = [ "foo.mm" ]
342 # }
343 # }
344 # This is allowed and the presubmit check should support this case.
345 list_of_sources = []
kjellander7439f972016-12-06 06:47:46346 c_files = []
347 cc_files = []
Mirko Bonadei4dc4e252017-09-19 11:49:16348 objc_files = []
349 target_name = target_match.group('target_name')
350 target_contents = target_match.group('target_contents')
351 for sources_match in SOURCES_RE.finditer(target_contents):
352 if '+=' not in sources_match.group(0):
353 if c_files or cc_files or objc_files:
354 list_of_sources.append((c_files, cc_files, objc_files))
355 c_files = []
356 cc_files = []
357 objc_files = []
358 for file_match in FILE_PATH_RE.finditer(sources_match.group(1)):
359 file_path = file_match.group('file_path')
360 extension = file_match.group('extension')
361 if extension == '.c':
362 c_files.append(file_path + extension)
363 if extension == '.cc':
364 cc_files.append(file_path + extension)
365 if extension in ['.m', '.mm']:
366 objc_files.append(file_path + extension)
367 list_of_sources.append((c_files, cc_files, objc_files))
368 for c_files_list, cc_files_list, objc_files_list in list_of_sources:
369 if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list):
370 all_sources = sorted(c_files_list + cc_files_list + objc_files_list)
371 errors[gn_file.LocalPath()].append((target_name, all_sources))
372 if errors:
kjellander7439f972016-12-06 06:47:46373 return [output_api.PresubmitError(
Mirko Bonadei4dc4e252017-09-19 11:49:16374 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n'
375 'Please create a separate target for each collection of sources.\n'
kjellander7439f972016-12-06 06:47:46376 'Mixed sources: \n'
377 '%s\n'
Mirko Bonadei4dc4e252017-09-19 11:49:16378 'Violating GN files:\n%s\n' % (json.dumps(errors, indent=2),
379 '\n'.join(errors.keys())))]
kjellander7439f972016-12-06 06:47:46380 return []
381
charujain9893e252017-09-14 11:33:22382def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
ehmaldonado4fb97462017-01-30 13:27:22383 cwd = input_api.PresubmitLocalPath()
mbonadeiab587dc2017-05-12 11:13:31384 script_path = os.path.join('tools_webrtc', 'presubmit_checks_lib',
385 'check_package_boundaries.py')
Mirko Bonadei92ea95e2017-09-15 04:47:31386 command = [sys.executable, script_path]
ehmaldonado4fb97462017-01-30 13:27:22387 command += [gn_file.LocalPath() for gn_file in gn_files]
388 returncode, _, stderr = _RunCommand(command, cwd)
389 if returncode:
390 return [output_api.PresubmitError(
391 'There are package boundary violations in the following GN files:\n\n'
392 '%s' % stderr)]
393 return []
394
charujain9893e252017-09-14 11:33:22395def CheckGnChanges(input_api, output_api):
ehmaldonado5b1ba082016-09-02 12:51:08396 source_file_filter = lambda x: input_api.FilterSourceFile(
397 x, white_list=(r'.+\.(gn|gni)$',))
398
399 gn_files = []
400 for f in input_api.AffectedSourceFiles(source_file_filter):
Mirko Bonadei92ea95e2017-09-15 04:47:31401 gn_files.append(f)
ehmaldonado5b1ba082016-09-02 12:51:08402
403 result = []
404 if gn_files:
charujain9893e252017-09-14 11:33:22405 result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api))
Mirko Bonadei4dc4e252017-09-19 11:49:16406 result.extend(CheckNoMixingSources(input_api, gn_files, output_api))
407 result.extend(CheckNoPackageBoundaryViolations(input_api, gn_files,
408 output_api))
ehmaldonado5b1ba082016-09-02 12:51:08409 return result
410
charujain9893e252017-09-14 11:33:22411def CheckUnwantedDependencies(input_api, output_api):
[email protected]3bd41562014-09-01 11:06:37412 """Runs checkdeps on #include statements added in this
413 change. Breaking - rules is an error, breaking ! rules is a
414 warning.
415 """
416 # Copied from Chromium's src/PRESUBMIT.py.
417
418 # We need to wait until we have an input_api object and use this
419 # roundabout construct to import checkdeps because this file is
420 # eval-ed and thus doesn't have __file__.
421 original_sys_path = sys.path
422 try:
[email protected]aefe61a2014-12-08 13:00:30423 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
424 'buildtools', 'checkdeps')
425 if not os.path.exists(checkdeps_path):
426 return [output_api.PresubmitError(
427 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
428 'download Chromium and setup the symlinks?' % checkdeps_path)]
429 sys.path.append(checkdeps_path)
[email protected]3bd41562014-09-01 11:06:37430 import checkdeps
431 from cpp_checker import CppChecker
432 from rules import Rule
433 finally:
434 # Restore sys.path to what it was before.
435 sys.path = original_sys_path
436
437 added_includes = []
438 for f in input_api.AffectedFiles():
439 if not CppChecker.IsCppFile(f.LocalPath()):
440 continue
441
Henrik Kjellander57e5fd22015-05-25 10:55:39442 changed_lines = [line for _, line in f.ChangedContents()]
[email protected]3bd41562014-09-01 11:06:37443 added_includes.append([f.LocalPath(), changed_lines])
444
445 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
446
447 error_descriptions = []
448 warning_descriptions = []
449 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
450 added_includes):
451 description_with_path = '%s\n %s' % (path, rule_description)
452 if rule_type == Rule.DISALLOW:
453 error_descriptions.append(description_with_path)
454 else:
455 warning_descriptions.append(description_with_path)
456
457 results = []
458 if error_descriptions:
459 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 10:47:05460 'You added one or more #includes that violate checkdeps rules.\n'
461 'Check that the DEPS files in these locations contain valid rules.\n'
462 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
463 'more details about checkdeps.',
[email protected]3bd41562014-09-01 11:06:37464 error_descriptions))
465 if warning_descriptions:
466 results.append(output_api.PresubmitPromptOrNotify(
467 'You added one or more #includes of files that are temporarily\n'
468 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 10:47:05469 '#include? See relevant DEPS file(s) for details and contacts.\n'
470 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
471 'more details about checkdeps.',
[email protected]3bd41562014-09-01 11:06:37472 warning_descriptions))
473 return results
474
charujain9893e252017-09-14 11:33:22475def CheckCommitMessageBugEntry(input_api, output_api):
476 """Check that bug entries are well-formed in commit message."""
477 bogus_bug_msg = (
478 'Bogus BUG entry: %s. Please specify the issue tracker prefix and the '
479 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.')
480 results = []
481 for bug in (input_api.change.BUG or '').split(','):
482 bug = bug.strip()
483 if bug.lower() == 'none':
484 continue
485 if ':' not in bug:
486 try:
487 if int(bug) > 100000:
488 # Rough indicator for current chromium bugs.
489 prefix_guess = 'chromium'
490 else:
491 prefix_guess = 'webrtc'
492 results.append('BUG entry requires issue tracker prefix, e.g. %s:%s' %
493 (prefix_guess, bug))
494 except ValueError:
495 results.append(bogus_bug_msg % bug)
496 elif not re.match(r'\w+:\d+', bug):
497 results.append(bogus_bug_msg % bug)
498 return [output_api.PresubmitError(r) for r in results]
499
500def CheckChangeHasBugField(input_api, output_api):
kjellanderd1e26a92016-09-19 15:11:16501 """Requires that the changelist have a BUG= field.
502
503 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
504 since it fails the presubmit if the BUG= field is missing or doesn't contain
505 a bug reference.
506 """
507 if input_api.change.BUG:
508 return []
509 else:
510 return [output_api.PresubmitError(
511 'The BUG=[bug number] field is mandatory. Please create a bug and '
512 'reference it using either of:\n'
513 ' * https://bugs.webrtc.org - reference it using BUG=webrtc:XXXX\n'
514 ' * https://crbug.com - reference it using BUG=chromium:XXXXXX')]
[email protected]e4158642014-08-06 09:11:18515
charujain9893e252017-09-14 11:33:22516def CheckJSONParseErrors(input_api, output_api):
kjellander569cf942016-02-11 13:02:59517 """Check that JSON files do not contain syntax errors."""
518
519 def FilterFile(affected_file):
520 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
521
522 def GetJSONParseError(input_api, filename):
523 try:
524 contents = input_api.ReadFile(filename)
525 input_api.json.loads(contents)
526 except ValueError as e:
527 return e
528 return None
529
530 results = []
531 for affected_file in input_api.AffectedFiles(
532 file_filter=FilterFile, include_deletes=False):
533 parse_error = GetJSONParseError(input_api,
534 affected_file.AbsoluteLocalPath())
535 if parse_error:
536 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
537 (affected_file.LocalPath(), parse_error)))
538 return results
539
540
charujain9893e252017-09-14 11:33:22541def RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 13:42:43542 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 17:52:05543 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
544
545 test_directories = [
Edward Lemur6d01f6d2017-09-14 15:02:01546 input_api.PresubmitLocalPath(),
Mirko Bonadei92ea95e2017-09-15 04:47:31547 Join('rtc_tools', 'py_event_log_analyzer'),
548 Join('rtc_tools'),
549 Join('audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 13:27:22550 ] + [
Henrik Kjellander90fd7d82017-05-09 06:30:10551 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 13:27:22552 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 17:52:05553 ]
554
555 tests = []
556 for directory in test_directories:
557 tests.extend(
558 input_api.canned_checks.GetUnitTestsInDirectory(
559 input_api,
560 output_api,
561 directory,
562 whitelist=[r'.+_test\.py$']))
563 return input_api.RunTests(tests, parallel=True)
564
565
charujain9893e252017-09-14 11:33:22566def CheckUsageOfGoogleProtobufNamespace(input_api, output_api):
mbonadei38415b22017-04-07 12:38:01567 """Checks that the namespace google::protobuf has not been used."""
568 files = []
569 pattern = input_api.re.compile(r'google::protobuf')
Mirko Bonadei92ea95e2017-09-15 04:47:31570 proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h')
mbonadei38415b22017-04-07 12:38:01571 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
572 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
573 continue
574 contents = input_api.ReadFile(f)
575 if pattern.search(contents):
576 files.append(f)
577
578 if files:
579 return [output_api.PresubmitError(
580 'Please avoid to use namespace `google::protobuf` directly.\n'
581 'Add a using directive in `%s` and include that header instead.'
582 % proto_utils_path, files)]
583 return []
584
585
Mirko Bonadei92ea95e2017-09-15 04:47:31586def _LicenseHeader(input_api):
587 """Returns the license header regexp."""
588 # Accept any year number from 2003 to the current year
589 current_year = int(input_api.time.strftime('%Y'))
590 allowed_years = (str(s) for s in reversed(xrange(2003, current_year + 1)))
591 years_re = '(' + '|'.join(allowed_years) + ')'
592 license_header = (
593 r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
594 r'All [Rr]ights [Rr]eserved\.\n'
595 r'.*?\n'
596 r'.*? Use of this source code is governed by a BSD-style license\n'
597 r'.*? that can be found in the LICENSE file in the root of the source\n'
598 r'.*? tree\. An additional intellectual property rights grant can be '
599 r'found\n'
600 r'.*? in the file PATENTS\. All contributing project authors may\n'
601 r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
602 ) % {
603 'year': years_re,
604 }
605 return license_header
606
607
charujain9893e252017-09-14 11:33:22608def CommonChecks(input_api, output_api):
[email protected]53df1362012-01-26 21:24:23609 """Checks common to both upload and commit."""
[email protected]da159d62011-05-30 11:51:34610 results = []
tkchin42f580e2015-11-27 07:18:23611 # Filter out files that are in objc or ios dirs from being cpplint-ed since
612 # they do not follow C++ lint rules.
613 black_list = input_api.DEFAULT_BLACK_LIST + (
614 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05615 r".*objc\.[hcm]+$",
tkchin42f580e2015-11-27 07:18:23616 )
617 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
charujain9893e252017-09-14 11:33:22618 results.extend(CheckApprovedFilesLintClean(
tkchin42f580e2015-11-27 07:18:23619 input_api, output_api, source_file_filter))
Mirko Bonadei92ea95e2017-09-15 04:47:31620 results.extend(input_api.canned_checks.CheckLicense(
621 input_api, output_api, _LicenseHeader(input_api)))
[email protected]5d3713932013-03-07 09:59:43622 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
[email protected]177567c2016-12-22 09:40:28623 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 11:10:04624 r'^build[\\\/].*\.py$',
625 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-13 05:43:38626 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 11:01:17627 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 11:10:04628 r'^out.*[\\\/].*\.py$',
629 r'^testing[\\\/].*\.py$',
630 r'^third_party[\\\/].*\.py$',
[email protected]177567c2016-12-22 09:40:28631 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 20:21:39632 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 06:30:10633 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
634 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 11:10:04635 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 10:55:39636 pylintrc='pylintrc'))
kjellander569cf942016-02-11 13:02:59637
nisse3d21e232016-09-02 10:07:06638 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 10:55:39639 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
640 # we need to have different license checks in talk/ and webrtc/ directories.
641 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 06:03:56642
tkchin3cd9a302016-06-08 19:40:28643 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
644 # ObjC subdirectories ObjC headers.
645 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellanderb4af3d62016-11-16 19:11:29646 # Skip long-lines check for DEPS and GN files.
647 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
tkchin3cd9a302016-06-08 19:40:28648 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
649 black_list=build_file_filter_list + objc_filter_list)
650 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
651 white_list=objc_filter_list)
[email protected]2442de12012-01-23 17:45:41652 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 19:40:28653 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
654 results.extend(input_api.canned_checks.CheckLongLines(
655 input_api, output_api, maxlen=100,
656 source_file_filter=hundred_char_sources))
657
[email protected]2442de12012-01-23 17:45:41658 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
659 input_api, output_api))
[email protected]53df1362012-01-26 21:24:23660 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
661 input_api, output_api))
kjellandere5dc62a2016-12-14 08:16:21662 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
663 input_api, output_api))
[email protected]53df1362012-01-26 21:24:23664 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
665 input_api, output_api))
charujain9893e252017-09-14 11:33:22666 results.extend(CheckNativeApiHeaderChanges(input_api, output_api))
667 results.extend(CheckNoIOStreamInHeaders(input_api, output_api))
668 results.extend(CheckNoPragmaOnce(input_api, output_api))
669 results.extend(CheckNoFRIEND_TEST(input_api, output_api))
670 results.extend(CheckGnChanges(input_api, output_api))
671 results.extend(CheckUnwantedDependencies(input_api, output_api))
672 results.extend(CheckJSONParseErrors(input_api, output_api))
673 results.extend(RunPythonTests(input_api, output_api))
674 results.extend(CheckUsageOfGoogleProtobufNamespace(input_api, output_api))
Mirko Bonadei866d3372017-09-15 10:35:26675 results.extend(CheckOrphanHeaders(input_api, output_api))
Mirko Bonadeia730c1c2017-09-18 09:33:13676 results.extend(CheckNewlineAtTheEndOfProtoFiles(input_api, output_api))
[email protected]53df1362012-01-26 21:24:23677 return results
[email protected]2442de12012-01-23 17:45:41678
[email protected]e4158642014-08-06 09:11:18679
[email protected]53df1362012-01-26 21:24:23680def CheckChangeOnUpload(input_api, output_api):
681 results = []
charujain9893e252017-09-14 11:33:22682 results.extend(CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 10:55:39683 results.extend(
684 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
[email protected]da159d62011-05-30 11:51:34685 return results
686
[email protected]e4158642014-08-06 09:11:18687
[email protected]2442de12012-01-23 17:45:41688def CheckChangeOnCommit(input_api, output_api):
[email protected]1198db92011-06-09 07:07:24689 results = []
charujain9893e252017-09-14 11:33:22690 results.extend(CommonChecks(input_api, output_api))
691 results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
[email protected]1198db92011-06-09 07:07:24692 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
[email protected]53df1362012-01-26 21:24:23693 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
694 input_api, output_api))
695 results.extend(input_api.canned_checks.CheckChangeHasDescription(
696 input_api, output_api))
charujain9893e252017-09-14 11:33:22697 results.extend(CheckChangeHasBugField(input_api, output_api))
698 results.extend(CheckCommitMessageBugEntry(input_api, output_api))
[email protected]12cb88c2014-02-13 11:53:43699 results.extend(input_api.canned_checks.CheckTreeIsOpen(
700 input_api, output_api,
701 json_url='http://webrtc-status.appspot.com/current?format=json'))
[email protected]1198db92011-06-09 07:07:24702 return results
mbonadei74973ed2017-05-09 14:58:05703
704
charujain9893e252017-09-14 11:33:22705def CheckOrphanHeaders(input_api, output_api):
mbonadei74973ed2017-05-09 14:58:05706 # We need to wait until we have an input_api object and use this
707 # roundabout construct to import prebubmit_checks_lib because this file is
708 # eval-ed and thus doesn't have __file__.
709 error_msg = """Header file {} is not listed in any GN target.
710 Please create a target or add it to an existing one in {}"""
711 results = []
712 original_sys_path = sys.path
713 try:
714 sys.path = sys.path + [input_api.os_path.join(
715 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')]
716 from check_orphan_headers import GetBuildGnPathFromFilePath
717 from check_orphan_headers import IsHeaderInBuildGn
718 finally:
719 # Restore sys.path to what it was before.
720 sys.path = original_sys_path
721
722 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
mbonadeia644ad32017-05-10 12:21:55723 if f.LocalPath().endswith('.h') and f.Action() == 'A':
mbonadei74973ed2017-05-09 14:58:05724 file_path = os.path.abspath(f.LocalPath())
725 root_dir = os.getcwd()
726 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
727 root_dir)
728 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
729 if not in_build_gn:
730 results.append(output_api.PresubmitError(error_msg.format(
731 file_path, gn_file_path)))
732 return results
Mirko Bonadei960fd5b2017-06-29 12:59:36733
734
Mirko Bonadeia730c1c2017-09-18 09:33:13735def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api):
Mirko Bonadei960fd5b2017-06-29 12:59:36736 """Checks that all .proto files are terminated with a newline."""
737 error_msg = 'File {} must end with exactly one newline.'
738 results = []
739 source_file_filter = lambda x: input_api.FilterSourceFile(
740 x, white_list=(r'.+\.proto$',))
741 for f in input_api.AffectedSourceFiles(source_file_filter):
742 file_path = f.LocalPath()
743 with open(file_path) as f:
744 lines = f.readlines()
Mirko Bonadeia730c1c2017-09-18 09:33:13745 if len(lines) > 0 and not lines[-1].endswith('\n'):
Mirko Bonadei960fd5b2017-06-29 12:59:36746 results.append(output_api.PresubmitError(error_msg.format(file_path)))
747 return results