blob: 6cd1984828593170131e10ac744869a4e07bccfb [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
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +000012import sys
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020013from collections import defaultdict
Oleh Prypin2f33a562017-10-04 20:17:54 +020014from contextlib import contextmanager
kjellander@webrtc.org85759802013-10-22 16:47:40 +000015
oprypin2aa463f2017-03-23 03:17:02 -070016# Files and directories that are *skipped* by cpplint in the presubmit script.
17CPPLINT_BLACKLIST = [
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018 'api/video_codecs/video_decoder.h',
19 'common_types.cc',
20 'common_types.h',
21 'examples/objc',
Steve Antone78bcb92017-10-31 09:53:08 -070022 'media/base/streamparams.h',
23 'media/base/videocommon.h',
24 'media/engine/fakewebrtcdeviceinfo.h',
25 'media/sctp/sctptransport.cc',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026 'modules/audio_coding',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027 'modules/audio_device',
28 'modules/audio_processing',
29 'modules/desktop_capture',
30 'modules/include/module_common_types.h',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031 'modules/utility',
32 'modules/video_capture',
Steve Anton6c38cc72017-11-29 10:25:58 -080033 'p2p/base/pseudotcp.cc',
34 'p2p/base/pseudotcp.h',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035 'rtc_base',
36 'sdk/android/src/jni',
37 'sdk/objc',
38 'system_wrappers',
39 'test',
Henrik Kjellander90fd7d82017-05-09 08:30:10 +020040 'tools_webrtc',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041 'voice_engine',
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 = (
Karl Wibergef52d8b82017-10-25 13:20:03 +020066 'api', # All subdirectories of api/ are included as well.
Mirko Bonadeia4eeeff2018-01-11 13:16:52 +010067 'media/base',
68 'media/engine',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020069 'modules/audio_device/include',
70 'pc',
kjellanderdd705472016-06-09 11:17:27 -070071)
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020072
kjellanderdd705472016-06-09 11:17:27 -070073# These directories should not be used but are maintained only to avoid breaking
74# some legacy downstream code.
75LEGACY_API_DIRS = (
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020076 'common_audio/include',
77 'modules/audio_coding/include',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020078 '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',
kjellander53047c92015-12-02 23:56:14 -080093)
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020094
Karl Wibergd4f01c12017-11-10 10:55:45 +010095# NOTE: The set of directories in API_DIRS should be the same as those
96# listed in the table in native-api.md.
kjellanderdd705472016-06-09 11:17:27 -070097API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-02 23:56:14 -080098
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020099# TARGET_RE matches a GN target, and extracts the target name and the contents.
100TARGET_RE = re.compile(r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {'
101 r'(?P<target_contents>.*?)'
102 r'(?P=indent)}',
103 re.MULTILINE | re.DOTALL)
104
105# SOURCES_RE matches a block of sources inside a GN target.
106SOURCES_RE = re.compile(r'sources \+?= \[(?P<sources>.*?)\]',
107 re.MULTILINE | re.DOTALL)
108
109# FILE_PATH_RE matchies a file path.
110FILE_PATH_RE = re.compile(r'"(?P<file_path>(\w|\/)+)(?P<extension>\.\w+)"')
111
kjellander53047c92015-12-02 23:56:14 -0800112
Oleh Prypin2f33a562017-10-04 20:17:54 +0200113@contextmanager
114def _AddToPath(*paths):
115 original_sys_path = sys.path
116 sys.path.extend(paths)
117 try:
118 yield
119 finally:
120 # Restore sys.path to what it was before.
121 sys.path = original_sys_path
ehmaldonado4fb97462017-01-30 05:27:22 -0800122
123
charujain9893e252017-09-14 13:33:22 +0200124def VerifyNativeApiHeadersListIsValid(input_api, output_api):
kjellander53047c92015-12-02 23:56:14 -0800125 """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 11:17:27 -0700129 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-02 23:56:14 -0800130 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
Artem Titove92675b2018-05-22 10:21:27 +0200141
kjellanderc88b5d52017-04-05 06:42:43 -0700142API_CHANGE_MSG = """
kwibergeb133022016-04-07 07:41:48 -0700143You seem to be changing native API header files. Please make sure that you:
oprypin375b9ac2017-02-13 04:13:23 -0800144 1. Make compatible changes that don't break existing clients. Usually
145 this is done by keeping the existing method signatures unchanged.
146 2. Mark the old stuff as deprecated (see RTC_DEPRECATED macro).
kwibergeb133022016-04-07 07:41:48 -0700147 3. Create a timeline and plan for when the deprecated stuff will be
148 removed. (The amount of time we give users to change their code
149 should be informed by how much work it is for them. If they just
150 need to replace one name with another or something equally
151 simple, 1-2 weeks might be good; if they need to do serious work,
152 up to 3 months may be called for.)
153 4. Update/inform existing downstream code owners to stop using the
154 deprecated stuff. (Send announcements to
155 discuss-webrtc@googlegroups.com and webrtc-users@google.com.)
156 5. Remove the deprecated stuff, once the agreed-upon amount of time
157 has passed.
158Related files:
159"""
kjellander53047c92015-12-02 23:56:14 -0800160
Artem Titove92675b2018-05-22 10:21:27 +0200161
charujain9893e252017-09-14 13:33:22 +0200162def CheckNativeApiHeaderChanges(input_api, output_api):
kjellander53047c92015-12-02 23:56:14 -0800163 """Checks to remind proper changing of native APIs."""
164 files = []
Karl Wiberg6bfac032017-10-27 15:14:20 +0200165 source_file_filter = lambda x: input_api.FilterSourceFile(
166 x, white_list=[r'.+\.(gn|gni|h)$'])
167 for f in input_api.AffectedSourceFiles(source_file_filter):
168 for path in API_DIRS:
169 dn = os.path.dirname(f.LocalPath())
170 if path == 'api':
171 # Special case: Subdirectories included.
172 if dn == 'api' or dn.startswith('api/'):
173 files.append(f)
174 else:
175 # Normal case: Subdirectories not included.
176 if dn == path:
177 files.append(f)
kjellander53047c92015-12-02 23:56:14 -0800178
179 if files:
kjellanderc88b5d52017-04-05 06:42:43 -0700180 return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
kjellander53047c92015-12-02 23:56:14 -0800181 return []
182
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100183
Artem Titova04d1402018-05-11 11:23:00 +0200184def CheckNoIOStreamInHeaders(input_api, output_api,
185 source_file_filter):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000186 """Checks to make sure no .h files include <iostream>."""
187 files = []
188 pattern = input_api.re.compile(r'^#include\s*<iostream>',
189 input_api.re.MULTILINE)
Artem Titova04d1402018-05-11 11:23:00 +0200190 file_filter = lambda x: (input_api.FilterSourceFile(x)
191 and source_file_filter(x))
192 for f in input_api.AffectedSourceFiles(file_filter):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000193 if not f.LocalPath().endswith('.h'):
194 continue
195 contents = input_api.ReadFile(f)
196 if pattern.search(contents):
197 files.append(f)
198
199 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200200 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000201 'Do not #include <iostream> in header files, since it inserts static ' +
202 'initialization into every file including the header. Instead, ' +
203 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200204 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000205 return []
206
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000207
Artem Titova04d1402018-05-11 11:23:00 +0200208def CheckNoPragmaOnce(input_api, output_api,
209 source_file_filter):
kjellander6aeef742017-02-20 01:13:18 -0800210 """Make sure that banned functions are not used."""
211 files = []
212 pattern = input_api.re.compile(r'^#pragma\s+once',
213 input_api.re.MULTILINE)
Artem Titova04d1402018-05-11 11:23:00 +0200214 file_filter = lambda x: (input_api.FilterSourceFile(x)
215 and source_file_filter(x))
216 for f in input_api.AffectedSourceFiles(file_filter):
kjellander6aeef742017-02-20 01:13:18 -0800217 if not f.LocalPath().endswith('.h'):
218 continue
219 contents = input_api.ReadFile(f)
220 if pattern.search(contents):
221 files.append(f)
222
223 if files:
224 return [output_api.PresubmitError(
225 'Do not use #pragma once in header files.\n'
226 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
227 files)]
228 return []
229
230
Artem Titova04d1402018-05-11 11:23:00 +0200231def CheckNoFRIEND_TEST(input_api, output_api, # pylint: disable=invalid-name
232 source_file_filter):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000233 """Make sure that gtest's FRIEND_TEST() macro is not used, the
234 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
235 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
236 problems = []
237
Artem Titova04d1402018-05-11 11:23:00 +0200238 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h'))
239 and source_file_filter(f))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000240 for f in input_api.AffectedFiles(file_filter=file_filter):
241 for line_num, line in f.ChangedContents():
242 if 'FRIEND_TEST(' in line:
243 problems.append(' %s:%d' % (f.LocalPath(), line_num))
244
245 if not problems:
246 return []
247 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
248 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
249 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
250
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000251
charujain9893e252017-09-14 13:33:22 +0200252def IsLintBlacklisted(blacklist_paths, file_path):
oprypin2aa463f2017-03-23 03:17:02 -0700253 """ Checks if a file is blacklisted for lint check."""
254 for path in blacklist_paths:
255 if file_path == path or os.path.dirname(file_path).startswith(path):
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100256 return True
257 return False
258
259
charujain9893e252017-09-14 13:33:22 +0200260def CheckApprovedFilesLintClean(input_api, output_api,
Artem Titova04d1402018-05-11 11:23:00 +0200261 source_file_filter=None):
oprypin2aa463f2017-03-23 03:17:02 -0700262 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
charujain9893e252017-09-14 13:33:22 +0200263 This check is based on CheckChangeLintsClean in
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000264 depot_tools/presubmit_canned_checks.py but has less filters and only checks
265 added files."""
266 result = []
267
268 # Initialize cpplint.
269 import cpplint
270 # Access to a protected member _XX of a client class
271 # pylint: disable=W0212
272 cpplint._cpplint_state.ResetErrorCounts()
273
jbauchc4e3ead2016-02-19 00:25:55 -0800274 lint_filters = cpplint._Filters()
275 lint_filters.extend(BLACKLIST_LINT_FILTERS)
276 cpplint._SetFilters(','.join(lint_filters))
277
oprypin2aa463f2017-03-23 03:17:02 -0700278 # Create a platform independent blacklist for cpplint.
279 blacklist_paths = [input_api.os_path.join(*path.split('/'))
280 for path in CPPLINT_BLACKLIST]
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100281
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000282 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 03:17:02 -0700283 # default when running cpplint.py from command line. To make it possible to
284 # work with not-yet-converted code, we're only applying it to new (or
285 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000286 verbosity_level = 1
287 files = []
288 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200289 # Note that moved/renamed files also count as added.
charujain9893e252017-09-14 13:33:22 +0200290 if f.Action() == 'A' or not IsLintBlacklisted(blacklist_paths,
Artem Titove92675b2018-05-22 10:21:27 +0200291 f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000292 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000293
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000294 for file_name in files:
295 cpplint.ProcessFile(file_name, verbosity_level)
296
297 if cpplint._cpplint_state.error_count > 0:
298 if input_api.is_committing:
oprypin8e58d652017-03-21 07:52:41 -0700299 res_type = output_api.PresubmitError
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000300 else:
301 res_type = output_api.PresubmitPromptWarning
302 result = [res_type('Changelist failed cpplint.py check.')]
303
304 return result
305
Artem Titove92675b2018-05-22 10:21:27 +0200306
charujain9893e252017-09-14 13:33:22 +0200307def CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700308 # Disallow referencing source files with paths above the GN file location.
309 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
310 re.MULTILINE | re.DOTALL)
311 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
312 violating_gn_files = set()
313 violating_source_entries = []
314 for gn_file in gn_files:
315 contents = input_api.ReadFile(gn_file)
316 for source_block_match in source_pattern.finditer(contents):
317 # Find all source list entries starting with ../ in the source block
318 # (exclude overrides entries).
319 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
320 source_file = file_list_match.group(1)
321 if 'overrides/' not in source_file:
322 violating_source_entries.append(source_file)
323 violating_gn_files.add(gn_file)
324 if violating_gn_files:
325 return [output_api.PresubmitError(
326 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100327 'allowed. Please introduce new GN targets in the proper location '
328 'instead.\n'
ehmaldonado5b1ba082016-09-02 05:51:08 -0700329 'Invalid source entries:\n'
330 '%s\n'
331 'Violating GN files:' % '\n'.join(violating_source_entries),
332 items=violating_gn_files)]
333 return []
334
Artem Titove92675b2018-05-22 10:21:27 +0200335
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200336def CheckNoMixingSources(input_api, gn_files, output_api):
337 """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target.
338
339 See bugs.webrtc.org/7743 for more context.
340 """
Artem Titove92675b2018-05-22 10:21:27 +0200341
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200342 def _MoreThanOneSourceUsed(*sources_lists):
343 sources_used = 0
344 for source_list in sources_lists:
345 if len(source_list):
346 sources_used += 1
347 return sources_used > 1
348
349 errors = defaultdict(lambda: [])
kjellander7439f972016-12-05 22:47:46 -0800350 for gn_file in gn_files:
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200351 gn_file_content = input_api.ReadFile(gn_file)
352 for target_match in TARGET_RE.finditer(gn_file_content):
353 # list_of_sources is a list of tuples of the form
354 # (c_files, cc_files, objc_files) that keeps track of all the sources
355 # defined in a target. A GN target can have more that on definition of
356 # sources (since it supports if/else statements).
357 # E.g.:
358 # rtc_static_library("foo") {
359 # if (is_win) {
360 # sources = [ "foo.cc" ]
361 # } else {
362 # sources = [ "foo.mm" ]
363 # }
364 # }
365 # This is allowed and the presubmit check should support this case.
366 list_of_sources = []
kjellander7439f972016-12-05 22:47:46 -0800367 c_files = []
368 cc_files = []
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200369 objc_files = []
370 target_name = target_match.group('target_name')
371 target_contents = target_match.group('target_contents')
372 for sources_match in SOURCES_RE.finditer(target_contents):
373 if '+=' not in sources_match.group(0):
374 if c_files or cc_files or objc_files:
375 list_of_sources.append((c_files, cc_files, objc_files))
376 c_files = []
377 cc_files = []
378 objc_files = []
379 for file_match in FILE_PATH_RE.finditer(sources_match.group(1)):
380 file_path = file_match.group('file_path')
381 extension = file_match.group('extension')
382 if extension == '.c':
383 c_files.append(file_path + extension)
384 if extension == '.cc':
385 cc_files.append(file_path + extension)
386 if extension in ['.m', '.mm']:
387 objc_files.append(file_path + extension)
388 list_of_sources.append((c_files, cc_files, objc_files))
389 for c_files_list, cc_files_list, objc_files_list in list_of_sources:
390 if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list):
391 all_sources = sorted(c_files_list + cc_files_list + objc_files_list)
392 errors[gn_file.LocalPath()].append((target_name, all_sources))
393 if errors:
kjellander7439f972016-12-05 22:47:46 -0800394 return [output_api.PresubmitError(
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200395 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n'
396 'Please create a separate target for each collection of sources.\n'
kjellander7439f972016-12-05 22:47:46 -0800397 'Mixed sources: \n'
398 '%s\n'
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200399 'Violating GN files:\n%s\n' % (json.dumps(errors, indent=2),
400 '\n'.join(errors.keys())))]
kjellander7439f972016-12-05 22:47:46 -0800401 return []
402
Artem Titove92675b2018-05-22 10:21:27 +0200403
charujain9893e252017-09-14 13:33:22 +0200404def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
ehmaldonado4fb97462017-01-30 05:27:22 -0800405 cwd = input_api.PresubmitLocalPath()
Oleh Prypin2f33a562017-10-04 20:17:54 +0200406 with _AddToPath(input_api.os_path.join(
407 cwd, 'tools_webrtc', 'presubmit_checks_lib')):
408 from check_package_boundaries import CheckPackageBoundaries
409 build_files = [os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files]
410 errors = CheckPackageBoundaries(cwd, build_files)[:5]
411 if errors:
ehmaldonado4fb97462017-01-30 05:27:22 -0800412 return [output_api.PresubmitError(
Oleh Prypin2f33a562017-10-04 20:17:54 +0200413 'There are package boundary violations in the following GN files:',
414 long_text='\n\n'.join(str(err) for err in errors))]
ehmaldonado4fb97462017-01-30 05:27:22 -0800415 return []
416
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100417
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200418def _ReportFileAndLine(filename, line_num):
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100419 """Default error formatter for _FindNewViolationsOfRule."""
420 return '%s (line %s)' % (filename, line_num)
421
422
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200423def CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, output_api,
424 error_formatter=_ReportFileAndLine):
425 """Make sure that warning suppression flags are not added wihtout a reason."""
426 msg = ('Usage of //build/config/clang:extra_warnings is discouraged '
427 'in WebRTC.\n'
428 'If you are not adding this code (e.g. you are just moving '
429 'existing code) or you want to add an exception,\n'
430 'you can add a comment on the line that causes the problem:\n\n'
431 '"-Wno-odr" # no-presubmit-check TODO(bugs.webrtc.org/BUG_ID)\n'
432 '\n'
433 'Affected files:\n')
434 errors = [] # 2-element tuples with (file, line number)
435 clang_warn_re = input_api.re.compile(r'//build/config/clang:extra_warnings')
436 no_presubmit_re = input_api.re.compile(
437 r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)')
438 for f in gn_files:
439 for line_num, line in f.ChangedContents():
440 if clang_warn_re.search(line) and not no_presubmit_re.search(line):
441 errors.append(error_formatter(f.LocalPath(), line_num))
442 if errors:
443 return [output_api.PresubmitError(msg, errors)]
444 return []
445
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100446def CheckNoStreamUsageIsAdded(input_api, output_api,
Artem Titov739351d2018-05-11 12:21:36 +0200447 source_file_filter,
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200448 error_formatter=_ReportFileAndLine):
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100449 """Make sure that no more dependencies on stringstream are added."""
450 error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
451 'deprecated.\n'
452 'This includes the following types:\n'
453 'std::istringstream, std::ostringstream, std::wistringstream, '
454 'std::wostringstream,\n'
455 'std::wstringstream, std::ostream, std::wostream, std::istream,'
456 'std::wistream,\n'
457 'std::iostream, std::wiostream.\n'
458 'If you are not adding this code (e.g. you are just moving '
459 'existing code),\n'
460 'you can add a comment on the line that causes the problem:\n\n'
461 '#include <sstream> // no-presubmit-check TODO(webrtc:8982)\n'
462 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n'
463 '\n'
Karl Wibergebd01e82018-03-14 15:08:39 +0100464 'If you are adding new code, consider using '
465 'rtc::SimpleStringBuilder\n'
466 '(in rtc_base/strings/string_builder.h).\n'
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100467 'Affected files:\n')
468 errors = [] # 2-element tuples with (file, line number)
469 include_re = input_api.re.compile(r'#include <(i|o|s)stream>')
470 usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream')
471 no_presubmit_re = input_api.re.compile(
Jonas Olsson74395342018-04-03 12:22:07 +0200472 r'// no-presubmit-check TODO\(webrtc:8982\)')
Artem Titova04d1402018-05-11 11:23:00 +0200473 file_filter = lambda x: (input_api.FilterSourceFile(x)
474 and source_file_filter(x))
475 for f in input_api.AffectedSourceFiles(file_filter):
Mirko Bonadeid2c83322018-03-19 10:31:47 +0000476 if f.LocalPath() == 'PRESUBMIT.py':
477 continue
478 for line_num, line in f.ChangedContents():
479 if ((include_re.search(line) or usage_re.search(line))
480 and not no_presubmit_re.search(line)):
481 errors.append(error_formatter(f.LocalPath(), line_num))
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100482 if errors:
483 return [output_api.PresubmitError(error_msg, errors)]
484 return []
485
Artem Titove92675b2018-05-22 10:21:27 +0200486
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200487def CheckPublicDepsIsNotUsed(gn_files, input_api, output_api):
488 """Checks that public_deps is not used without a good reason."""
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100489 result = []
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200490 no_presubmit_check_re = input_api.re.compile(
491 r'# no-presubmit-check TODO\(webrtc:8603\)')
492 error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files '
493 'because it doesn\'t map well to downstream build systems.\n'
494 'Used in: %s (line %d).\n'
495 'If you are not adding this code (e.g. you are just moving '
496 'existing code) or you have a good reason, you can add a '
497 'comment on the line that causes the problem:\n\n'
498 'public_deps = [ # no-presubmit-check TODO(webrtc:8603)\n')
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100499 for affected_file in gn_files:
500 for (line_number, affected_line) in affected_file.ChangedContents():
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200501 if ('public_deps' in affected_line
502 and not no_presubmit_check_re.search(affected_line)):
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100503 result.append(
504 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
505 line_number)))
506 return result
507
Artem Titove92675b2018-05-22 10:21:27 +0200508
Patrik Höglund6f491062018-01-11 12:04:23 +0100509def CheckCheckIncludesIsNotUsed(gn_files, output_api):
510 result = []
511 error_msg = ('check_includes overrides are not allowed since it can cause '
512 'incorrect dependencies to form. It effectively means that your '
513 'module can include any .h file without depending on its '
514 'corresponding target. There are some exceptional cases when '
515 'this is allowed: if so, get approval from a .gn owner in the'
516 'root OWNERS file.\n'
517 'Used in: %s (line %d).')
518 for affected_file in gn_files:
519 for (line_number, affected_line) in affected_file.ChangedContents():
520 if 'check_includes' in affected_line:
521 result.append(
522 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
523 line_number)))
524 return result
525
Artem Titove92675b2018-05-22 10:21:27 +0200526
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200527def CheckGnChanges(input_api, output_api):
Artem Titova04d1402018-05-11 11:23:00 +0200528 file_filter = lambda x: (input_api.FilterSourceFile(
Oleh Prypinafe01652017-10-04 15:56:08 +0200529 x, white_list=(r'.+\.(gn|gni)$',),
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200530 black_list=(r'.*/presubmit_checks_lib/testdata/.*',)))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700531
532 gn_files = []
Artem Titova04d1402018-05-11 11:23:00 +0200533 for f in input_api.AffectedSourceFiles(file_filter):
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200534 gn_files.append(f)
ehmaldonado5b1ba082016-09-02 05:51:08 -0700535
536 result = []
537 if gn_files:
charujain9893e252017-09-14 13:33:22 +0200538 result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api))
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200539 result.extend(CheckNoMixingSources(input_api, gn_files, output_api))
540 result.extend(CheckNoPackageBoundaryViolations(input_api, gn_files,
541 output_api))
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200542 result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, output_api))
Patrik Höglund6f491062018-01-11 12:04:23 +0100543 result.extend(CheckCheckIncludesIsNotUsed(gn_files, output_api))
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200544 result.extend(CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api,
545 output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700546 return result
547
Artem Titove92675b2018-05-22 10:21:27 +0200548
Oleh Prypin920b6532017-10-05 11:28:51 +0200549def CheckGnGen(input_api, output_api):
550 """Runs `gn gen --check` with default args to detect mismatches between
551 #includes and dependencies in the BUILD.gn files, as well as general build
552 errors.
553 """
554 with _AddToPath(input_api.os_path.join(
555 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
556 from gn_check import RunGnCheck
557 errors = RunGnCheck(input_api.PresubmitLocalPath())[:5]
558 if errors:
559 return [output_api.PresubmitPromptWarning(
560 'Some #includes do not match the build dependency graph. Please run:\n'
561 ' gn gen --check <out_dir>',
562 long_text='\n\n'.join(errors))]
563 return []
564
Artem Titove92675b2018-05-22 10:21:27 +0200565
Artem Titova04d1402018-05-11 11:23:00 +0200566def CheckUnwantedDependencies(input_api, output_api, source_file_filter):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000567 """Runs checkdeps on #include statements added in this
568 change. Breaking - rules is an error, breaking ! rules is a
569 warning.
570 """
571 # Copied from Chromium's src/PRESUBMIT.py.
572
573 # We need to wait until we have an input_api object and use this
574 # roundabout construct to import checkdeps because this file is
575 # eval-ed and thus doesn't have __file__.
Oleh Prypin2f33a562017-10-04 20:17:54 +0200576 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
577 'buildtools', 'checkdeps')
578 if not os.path.exists(checkdeps_path):
579 return [output_api.PresubmitError(
580 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
581 'download all the DEPS entries?' % checkdeps_path)]
582 with _AddToPath(checkdeps_path):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000583 import checkdeps
584 from cpp_checker import CppChecker
585 from rules import Rule
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000586
587 added_includes = []
Artem Titova04d1402018-05-11 11:23:00 +0200588 for f in input_api.AffectedFiles(file_filter=source_file_filter):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000589 if not CppChecker.IsCppFile(f.LocalPath()):
590 continue
591
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200592 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000593 added_includes.append([f.LocalPath(), changed_lines])
594
595 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
596
597 error_descriptions = []
598 warning_descriptions = []
599 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
600 added_includes):
601 description_with_path = '%s\n %s' % (path, rule_description)
602 if rule_type == Rule.DISALLOW:
603 error_descriptions.append(description_with_path)
604 else:
605 warning_descriptions.append(description_with_path)
606
607 results = []
608 if error_descriptions:
609 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 03:47:05 -0700610 'You added one or more #includes that violate checkdeps rules.\n'
611 'Check that the DEPS files in these locations contain valid rules.\n'
612 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
613 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000614 error_descriptions))
615 if warning_descriptions:
616 results.append(output_api.PresubmitPromptOrNotify(
617 'You added one or more #includes of files that are temporarily\n'
618 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 03:47:05 -0700619 '#include? See relevant DEPS file(s) for details and contacts.\n'
620 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
621 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000622 warning_descriptions))
623 return results
624
Artem Titove92675b2018-05-22 10:21:27 +0200625
charujain9893e252017-09-14 13:33:22 +0200626def CheckCommitMessageBugEntry(input_api, output_api):
627 """Check that bug entries are well-formed in commit message."""
628 bogus_bug_msg = (
Mirko Bonadei61880182017-10-12 15:12:35 +0200629 'Bogus Bug entry: %s. Please specify the issue tracker prefix and the '
charujain9893e252017-09-14 13:33:22 +0200630 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.')
631 results = []
Mirko Bonadei61880182017-10-12 15:12:35 +0200632 for bug in input_api.change.BugsFromDescription():
charujain9893e252017-09-14 13:33:22 +0200633 bug = bug.strip()
634 if bug.lower() == 'none':
635 continue
charujain81a58c72017-09-25 13:25:45 +0200636 if 'b/' not in bug and ':' not in bug:
charujain9893e252017-09-14 13:33:22 +0200637 try:
638 if int(bug) > 100000:
639 # Rough indicator for current chromium bugs.
640 prefix_guess = 'chromium'
641 else:
642 prefix_guess = 'webrtc'
Mirko Bonadei61880182017-10-12 15:12:35 +0200643 results.append('Bug entry requires issue tracker prefix, e.g. %s:%s' %
charujain9893e252017-09-14 13:33:22 +0200644 (prefix_guess, bug))
645 except ValueError:
646 results.append(bogus_bug_msg % bug)
charujain81a58c72017-09-25 13:25:45 +0200647 elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)):
charujain9893e252017-09-14 13:33:22 +0200648 results.append(bogus_bug_msg % bug)
649 return [output_api.PresubmitError(r) for r in results]
650
Artem Titove92675b2018-05-22 10:21:27 +0200651
charujain9893e252017-09-14 13:33:22 +0200652def CheckChangeHasBugField(input_api, output_api):
Mirko Bonadei61880182017-10-12 15:12:35 +0200653 """Requires that the changelist is associated with a bug.
kjellanderd1e26a92016-09-19 08:11:16 -0700654
655 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
Mirko Bonadei61880182017-10-12 15:12:35 +0200656 since it fails the presubmit if the bug field is missing or doesn't contain
kjellanderd1e26a92016-09-19 08:11:16 -0700657 a bug reference.
Mirko Bonadei61880182017-10-12 15:12:35 +0200658
659 This supports both 'BUG=' and 'Bug:' since we are in the process of migrating
660 to Gerrit and it encourages the usage of 'Bug:'.
kjellanderd1e26a92016-09-19 08:11:16 -0700661 """
Mirko Bonadei61880182017-10-12 15:12:35 +0200662 if input_api.change.BugsFromDescription():
kjellanderd1e26a92016-09-19 08:11:16 -0700663 return []
664 else:
665 return [output_api.PresubmitError(
Mirko Bonadei61880182017-10-12 15:12:35 +0200666 'The "Bug: [bug number]" footer is mandatory. Please create a bug and '
kjellanderd1e26a92016-09-19 08:11:16 -0700667 'reference it using either of:\n'
Mirko Bonadei61880182017-10-12 15:12:35 +0200668 ' * https://bugs.webrtc.org - reference it using Bug: webrtc:XXXX\n'
669 ' * https://crbug.com - reference it using Bug: chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000670
Artem Titove92675b2018-05-22 10:21:27 +0200671
Artem Titova04d1402018-05-11 11:23:00 +0200672def CheckJSONParseErrors(input_api, output_api, source_file_filter):
kjellander569cf942016-02-11 05:02:59 -0800673 """Check that JSON files do not contain syntax errors."""
674
675 def FilterFile(affected_file):
Artem Titova04d1402018-05-11 11:23:00 +0200676 return (input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
677 and source_file_filter(affected_file))
kjellander569cf942016-02-11 05:02:59 -0800678
679 def GetJSONParseError(input_api, filename):
680 try:
681 contents = input_api.ReadFile(filename)
682 input_api.json.loads(contents)
683 except ValueError as e:
684 return e
685 return None
686
687 results = []
688 for affected_file in input_api.AffectedFiles(
689 file_filter=FilterFile, include_deletes=False):
690 parse_error = GetJSONParseError(input_api,
691 affected_file.AbsoluteLocalPath())
692 if parse_error:
693 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
Artem Titove92675b2018-05-22 10:21:27 +0200694 (affected_file.LocalPath(),
695 parse_error)))
kjellander569cf942016-02-11 05:02:59 -0800696 return results
697
698
charujain9893e252017-09-14 13:33:22 +0200699def RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 06:42:43 -0700700 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200701 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
702
703 test_directories = [
Edward Lemur6d01f6d2017-09-14 17:02:01 +0200704 input_api.PresubmitLocalPath(),
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200705 Join('rtc_tools', 'py_event_log_analyzer'),
706 Join('rtc_tools'),
707 Join('audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 05:27:22 -0800708 ] + [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200709 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 05:27:22 -0800710 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200711 ]
712
713 tests = []
714 for directory in test_directories:
715 tests.extend(
716 input_api.canned_checks.GetUnitTestsInDirectory(
717 input_api,
718 output_api,
719 directory,
720 whitelist=[r'.+_test\.py$']))
721 return input_api.RunTests(tests, parallel=True)
722
723
Artem Titova04d1402018-05-11 11:23:00 +0200724def CheckUsageOfGoogleProtobufNamespace(input_api, output_api,
725 source_file_filter):
mbonadei38415b22017-04-07 05:38:01 -0700726 """Checks that the namespace google::protobuf has not been used."""
727 files = []
728 pattern = input_api.re.compile(r'google::protobuf')
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200729 proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h')
Artem Titova04d1402018-05-11 11:23:00 +0200730 file_filter = lambda x: (input_api.FilterSourceFile(x)
731 and source_file_filter(x))
732 for f in input_api.AffectedSourceFiles(file_filter):
mbonadei38415b22017-04-07 05:38:01 -0700733 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
734 continue
735 contents = input_api.ReadFile(f)
736 if pattern.search(contents):
737 files.append(f)
738
739 if files:
740 return [output_api.PresubmitError(
741 'Please avoid to use namespace `google::protobuf` directly.\n'
742 'Add a using directive in `%s` and include that header instead.'
743 % proto_utils_path, files)]
744 return []
745
746
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200747def _LicenseHeader(input_api):
748 """Returns the license header regexp."""
749 # Accept any year number from 2003 to the current year
750 current_year = int(input_api.time.strftime('%Y'))
751 allowed_years = (str(s) for s in reversed(xrange(2003, current_year + 1)))
752 years_re = '(' + '|'.join(allowed_years) + ')'
753 license_header = (
754 r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
755 r'All [Rr]ights [Rr]eserved\.\n'
756 r'.*?\n'
757 r'.*? Use of this source code is governed by a BSD-style license\n'
758 r'.*? that can be found in the LICENSE file in the root of the source\n'
759 r'.*? tree\. An additional intellectual property rights grant can be '
760 r'found\n'
761 r'.*? in the file PATENTS\. All contributing project authors may\n'
762 r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
763 ) % {
764 'year': years_re,
765 }
766 return license_header
767
768
charujain9893e252017-09-14 13:33:22 +0200769def CommonChecks(input_api, output_api):
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000770 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000771 results = []
tkchin42f580e2015-11-26 23:18:23 -0800772 # Filter out files that are in objc or ios dirs from being cpplint-ed since
773 # they do not follow C++ lint rules.
774 black_list = input_api.DEFAULT_BLACK_LIST + (
775 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000776 r".*objc\.[hcm]+$",
tkchin42f580e2015-11-26 23:18:23 -0800777 )
778 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
charujain9893e252017-09-14 13:33:22 +0200779 results.extend(CheckApprovedFilesLintClean(
tkchin42f580e2015-11-26 23:18:23 -0800780 input_api, output_api, source_file_filter))
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200781 results.extend(input_api.canned_checks.CheckLicense(
782 input_api, output_api, _LicenseHeader(input_api)))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000783 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100784 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200785 r'^build[\\\/].*\.py$',
786 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-12 22:43:38 -0700787 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 12:01:17 +0100788 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200789 r'^out.*[\\\/].*\.py$',
790 r'^testing[\\\/].*\.py$',
791 r'^third_party[\\\/].*\.py$',
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100792 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 12:21:39 -0800793 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200794 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
795 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200796 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200797 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800798
nisse3d21e232016-09-02 03:07:06 -0700799 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200800 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
801 # we need to have different license checks in talk/ and webrtc/ directories.
802 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200803
tkchin3cd9a302016-06-08 12:40:28 -0700804 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
805 # ObjC subdirectories ObjC headers.
806 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100807 # Skip long-lines check for DEPS and GN files.
808 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
Artem Titova04d1402018-05-11 11:23:00 +0200809 # Also we will skip most checks for third_party directory.
Artem Titov42f0d782018-06-27 13:23:17 +0200810 third_party_filter_list = (r'^third_party[\\\/].+',)
tkchin3cd9a302016-06-08 12:40:28 -0700811 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
Artem Titova04d1402018-05-11 11:23:00 +0200812 black_list=build_file_filter_list + objc_filter_list +
813 third_party_filter_list)
tkchin3cd9a302016-06-08 12:40:28 -0700814 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
815 white_list=objc_filter_list)
Artem Titove92675b2018-05-22 10:21:27 +0200816 non_third_party_sources = lambda x: input_api.FilterSourceFile(x,
817 black_list=third_party_filter_list)
818
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000819 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700820 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
821 results.extend(input_api.canned_checks.CheckLongLines(
822 input_api, output_api, maxlen=100,
823 source_file_filter=hundred_char_sources))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000824 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
Artem Titova04d1402018-05-11 11:23:00 +0200825 input_api, output_api, source_file_filter=non_third_party_sources))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000826 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
Artem Titova04d1402018-05-11 11:23:00 +0200827 input_api, output_api, source_file_filter=non_third_party_sources))
kjellandere5dc62a2016-12-14 00:16:21 -0800828 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
829 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000830 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
Artem Titova04d1402018-05-11 11:23:00 +0200831 input_api, output_api, source_file_filter=non_third_party_sources))
Yves Gerey87a93532018-06-20 15:51:49 +0200832 results.extend(input_api.canned_checks.CheckPatchFormatted(
833 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200834 results.extend(CheckNativeApiHeaderChanges(input_api, output_api))
Artem Titova04d1402018-05-11 11:23:00 +0200835 results.extend(CheckNoIOStreamInHeaders(
836 input_api, output_api, source_file_filter=non_third_party_sources))
837 results.extend(CheckNoPragmaOnce(
838 input_api, output_api, source_file_filter=non_third_party_sources))
839 results.extend(CheckNoFRIEND_TEST(
840 input_api, output_api, source_file_filter=non_third_party_sources))
Mirko Bonadeif0e0d752018-07-04 08:48:18 +0200841 results.extend(CheckGnChanges(input_api, output_api))
Artem Titova04d1402018-05-11 11:23:00 +0200842 results.extend(CheckUnwantedDependencies(
843 input_api, output_api, source_file_filter=non_third_party_sources))
844 results.extend(CheckJSONParseErrors(
845 input_api, output_api, source_file_filter=non_third_party_sources))
charujain9893e252017-09-14 13:33:22 +0200846 results.extend(RunPythonTests(input_api, output_api))
Artem Titova04d1402018-05-11 11:23:00 +0200847 results.extend(CheckUsageOfGoogleProtobufNamespace(
848 input_api, output_api, source_file_filter=non_third_party_sources))
849 results.extend(CheckOrphanHeaders(
850 input_api, output_api, source_file_filter=non_third_party_sources))
851 results.extend(CheckNewlineAtTheEndOfProtoFiles(
852 input_api, output_api, source_file_filter=non_third_party_sources))
853 results.extend(CheckNoStreamUsageIsAdded(
Artem Titov739351d2018-05-11 12:21:36 +0200854 input_api, output_api, non_third_party_sources))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000855 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000856
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000857
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000858def CheckChangeOnUpload(input_api, output_api):
859 results = []
charujain9893e252017-09-14 13:33:22 +0200860 results.extend(CommonChecks(input_api, output_api))
Oleh Prypin920b6532017-10-05 11:28:51 +0200861 results.extend(CheckGnGen(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200862 results.extend(
863 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000864 return results
865
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000866
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000867def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000868 results = []
charujain9893e252017-09-14 13:33:22 +0200869 results.extend(CommonChecks(input_api, output_api))
870 results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
Artem Titov42f0d782018-06-27 13:23:17 +0200871 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000872 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
873 input_api, output_api))
874 results.extend(input_api.canned_checks.CheckChangeHasDescription(
875 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200876 results.extend(CheckChangeHasBugField(input_api, output_api))
877 results.extend(CheckCommitMessageBugEntry(input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000878 results.extend(input_api.canned_checks.CheckTreeIsOpen(
879 input_api, output_api,
880 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000881 return results
mbonadei74973ed2017-05-09 07:58:05 -0700882
883
Artem Titova04d1402018-05-11 11:23:00 +0200884def CheckOrphanHeaders(input_api, output_api, source_file_filter):
mbonadei74973ed2017-05-09 07:58:05 -0700885 # We need to wait until we have an input_api object and use this
886 # roundabout construct to import prebubmit_checks_lib because this file is
887 # eval-ed and thus doesn't have __file__.
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100888 error_msg = """{} should be listed in {}."""
mbonadei74973ed2017-05-09 07:58:05 -0700889 results = []
Patrik Höglund7e60de22018-01-09 14:22:00 +0100890 orphan_blacklist = [
891 os.path.join('tools_webrtc', 'ios', 'SDK'),
892 ]
Oleh Prypin2f33a562017-10-04 20:17:54 +0200893 with _AddToPath(input_api.os_path.join(
894 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
mbonadei74973ed2017-05-09 07:58:05 -0700895 from check_orphan_headers import GetBuildGnPathFromFilePath
896 from check_orphan_headers import IsHeaderInBuildGn
mbonadei74973ed2017-05-09 07:58:05 -0700897
Artem Titova04d1402018-05-11 11:23:00 +0200898 file_filter = lambda x: input_api.FilterSourceFile(
899 x, black_list=orphan_blacklist) and source_file_filter(x)
900 for f in input_api.AffectedSourceFiles(file_filter):
Patrik Höglund7e60de22018-01-09 14:22:00 +0100901 if f.LocalPath().endswith('.h'):
mbonadei74973ed2017-05-09 07:58:05 -0700902 file_path = os.path.abspath(f.LocalPath())
903 root_dir = os.getcwd()
904 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
905 root_dir)
906 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
907 if not in_build_gn:
908 results.append(output_api.PresubmitError(error_msg.format(
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100909 f.LocalPath(), os.path.relpath(gn_file_path))))
mbonadei74973ed2017-05-09 07:58:05 -0700910 return results
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200911
912
Artem Titove92675b2018-05-22 10:21:27 +0200913def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api, source_file_filter):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200914 """Checks that all .proto files are terminated with a newline."""
915 error_msg = 'File {} must end with exactly one newline.'
916 results = []
Artem Titova04d1402018-05-11 11:23:00 +0200917 file_filter = lambda x: input_api.FilterSourceFile(
918 x, white_list=(r'.+\.proto$',)) and source_file_filter(x)
919 for f in input_api.AffectedSourceFiles(file_filter):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200920 file_path = f.LocalPath()
921 with open(file_path) as f:
922 lines = f.readlines()
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200923 if len(lines) > 0 and not lines[-1].endswith('\n'):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200924 results.append(output_api.PresubmitError(error_msg.format(file_path)))
925 return results