blob: 0b7d19fef5a10e5bfa4cf32f6f0501a073b8209d [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',
Artem Titova04d1402018-05-11 11:23:00 +020042 'third_party',
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 = (
Karl Wibergef52d8b82017-10-25 13:20:03 +020067 'api', # All subdirectories of api/ are included as well.
Mirko Bonadeia4eeeff2018-01-11 13:16:52 +010068 'media/base',
69 'media/engine',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020070 'modules/audio_device/include',
71 'pc',
kjellanderdd705472016-06-09 11:17:27 -070072)
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020073
kjellanderdd705472016-06-09 11:17:27 -070074# These directories should not be used but are maintained only to avoid breaking
75# some legacy downstream code.
76LEGACY_API_DIRS = (
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020077 'common_audio/include',
78 'modules/audio_coding/include',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020079 'modules/audio_processing/include',
80 'modules/bitrate_controller/include',
81 'modules/congestion_controller/include',
82 'modules/include',
83 'modules/remote_bitrate_estimator/include',
84 'modules/rtp_rtcp/include',
85 'modules/rtp_rtcp/source',
86 'modules/utility/include',
87 'modules/video_coding/codecs/h264/include',
88 'modules/video_coding/codecs/i420/include',
89 'modules/video_coding/codecs/vp8/include',
90 'modules/video_coding/codecs/vp9/include',
91 'modules/video_coding/include',
92 'rtc_base',
93 'system_wrappers/include',
kjellander53047c92015-12-02 23:56:14 -080094)
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020095
Karl Wibergd4f01c12017-11-10 10:55:45 +010096# NOTE: The set of directories in API_DIRS should be the same as those
97# listed in the table in native-api.md.
kjellanderdd705472016-06-09 11:17:27 -070098API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-02 23:56:14 -080099
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200100# TARGET_RE matches a GN target, and extracts the target name and the contents.
101TARGET_RE = re.compile(r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {'
102 r'(?P<target_contents>.*?)'
103 r'(?P=indent)}',
104 re.MULTILINE | re.DOTALL)
105
106# SOURCES_RE matches a block of sources inside a GN target.
107SOURCES_RE = re.compile(r'sources \+?= \[(?P<sources>.*?)\]',
108 re.MULTILINE | re.DOTALL)
109
110# FILE_PATH_RE matchies a file path.
111FILE_PATH_RE = re.compile(r'"(?P<file_path>(\w|\/)+)(?P<extension>\.\w+)"')
112
kjellander53047c92015-12-02 23:56:14 -0800113
Oleh Prypin2f33a562017-10-04 20:17:54 +0200114@contextmanager
115def _AddToPath(*paths):
116 original_sys_path = sys.path
117 sys.path.extend(paths)
118 try:
119 yield
120 finally:
121 # Restore sys.path to what it was before.
122 sys.path = original_sys_path
ehmaldonado4fb97462017-01-30 05:27:22 -0800123
124
charujain9893e252017-09-14 13:33:22 +0200125def VerifyNativeApiHeadersListIsValid(input_api, output_api):
kjellander53047c92015-12-02 23:56:14 -0800126 """Ensures the list of native API header directories is up to date."""
127 non_existing_paths = []
128 native_api_full_paths = [
129 input_api.os_path.join(input_api.PresubmitLocalPath(),
kjellanderdd705472016-06-09 11:17:27 -0700130 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-02 23:56:14 -0800131 for path in native_api_full_paths:
132 if not os.path.isdir(path):
133 non_existing_paths.append(path)
134 if non_existing_paths:
135 return [output_api.PresubmitError(
136 'Directories to native API headers have changed which has made the '
137 'list in PRESUBMIT.py outdated.\nPlease update it to the current '
138 'location of our native APIs.',
139 non_existing_paths)]
140 return []
141
Artem Titove92675b2018-05-22 10:21:27 +0200142
kjellanderc88b5d52017-04-05 06:42:43 -0700143API_CHANGE_MSG = """
kwibergeb133022016-04-07 07:41:48 -0700144You seem to be changing native API header files. Please make sure that you:
oprypin375b9ac2017-02-13 04:13:23 -0800145 1. Make compatible changes that don't break existing clients. Usually
146 this is done by keeping the existing method signatures unchanged.
147 2. Mark the old stuff as deprecated (see RTC_DEPRECATED macro).
kwibergeb133022016-04-07 07:41:48 -0700148 3. Create a timeline and plan for when the deprecated stuff will be
149 removed. (The amount of time we give users to change their code
150 should be informed by how much work it is for them. If they just
151 need to replace one name with another or something equally
152 simple, 1-2 weeks might be good; if they need to do serious work,
153 up to 3 months may be called for.)
154 4. Update/inform existing downstream code owners to stop using the
155 deprecated stuff. (Send announcements to
156 discuss-webrtc@googlegroups.com and webrtc-users@google.com.)
157 5. Remove the deprecated stuff, once the agreed-upon amount of time
158 has passed.
159Related files:
160"""
kjellander53047c92015-12-02 23:56:14 -0800161
Artem Titove92675b2018-05-22 10:21:27 +0200162
charujain9893e252017-09-14 13:33:22 +0200163def CheckNativeApiHeaderChanges(input_api, output_api):
kjellander53047c92015-12-02 23:56:14 -0800164 """Checks to remind proper changing of native APIs."""
165 files = []
Karl Wiberg6bfac032017-10-27 15:14:20 +0200166 source_file_filter = lambda x: input_api.FilterSourceFile(
167 x, white_list=[r'.+\.(gn|gni|h)$'])
168 for f in input_api.AffectedSourceFiles(source_file_filter):
169 for path in API_DIRS:
170 dn = os.path.dirname(f.LocalPath())
171 if path == 'api':
172 # Special case: Subdirectories included.
173 if dn == 'api' or dn.startswith('api/'):
174 files.append(f)
175 else:
176 # Normal case: Subdirectories not included.
177 if dn == path:
178 files.append(f)
kjellander53047c92015-12-02 23:56:14 -0800179
180 if files:
kjellanderc88b5d52017-04-05 06:42:43 -0700181 return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
kjellander53047c92015-12-02 23:56:14 -0800182 return []
183
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100184
Artem Titova04d1402018-05-11 11:23:00 +0200185def CheckNoIOStreamInHeaders(input_api, output_api,
186 source_file_filter):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000187 """Checks to make sure no .h files include <iostream>."""
188 files = []
189 pattern = input_api.re.compile(r'^#include\s*<iostream>',
190 input_api.re.MULTILINE)
Artem Titova04d1402018-05-11 11:23:00 +0200191 file_filter = lambda x: (input_api.FilterSourceFile(x)
192 and source_file_filter(x))
193 for f in input_api.AffectedSourceFiles(file_filter):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000194 if not f.LocalPath().endswith('.h'):
195 continue
196 contents = input_api.ReadFile(f)
197 if pattern.search(contents):
198 files.append(f)
199
200 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200201 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000202 'Do not #include <iostream> in header files, since it inserts static ' +
203 'initialization into every file including the header. Instead, ' +
204 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200205 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000206 return []
207
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000208
Artem Titova04d1402018-05-11 11:23:00 +0200209def CheckNoPragmaOnce(input_api, output_api,
210 source_file_filter):
kjellander6aeef742017-02-20 01:13:18 -0800211 """Make sure that banned functions are not used."""
212 files = []
213 pattern = input_api.re.compile(r'^#pragma\s+once',
214 input_api.re.MULTILINE)
Artem Titova04d1402018-05-11 11:23:00 +0200215 file_filter = lambda x: (input_api.FilterSourceFile(x)
216 and source_file_filter(x))
217 for f in input_api.AffectedSourceFiles(file_filter):
kjellander6aeef742017-02-20 01:13:18 -0800218 if not f.LocalPath().endswith('.h'):
219 continue
220 contents = input_api.ReadFile(f)
221 if pattern.search(contents):
222 files.append(f)
223
224 if files:
225 return [output_api.PresubmitError(
226 'Do not use #pragma once in header files.\n'
227 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
228 files)]
229 return []
230
231
Artem Titova04d1402018-05-11 11:23:00 +0200232def CheckNoFRIEND_TEST(input_api, output_api, # pylint: disable=invalid-name
233 source_file_filter):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000234 """Make sure that gtest's FRIEND_TEST() macro is not used, the
235 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
236 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
237 problems = []
238
Artem Titova04d1402018-05-11 11:23:00 +0200239 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h'))
240 and source_file_filter(f))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000241 for f in input_api.AffectedFiles(file_filter=file_filter):
242 for line_num, line in f.ChangedContents():
243 if 'FRIEND_TEST(' in line:
244 problems.append(' %s:%d' % (f.LocalPath(), line_num))
245
246 if not problems:
247 return []
248 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
249 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
250 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
251
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000252
charujain9893e252017-09-14 13:33:22 +0200253def IsLintBlacklisted(blacklist_paths, file_path):
oprypin2aa463f2017-03-23 03:17:02 -0700254 """ Checks if a file is blacklisted for lint check."""
255 for path in blacklist_paths:
256 if file_path == path or os.path.dirname(file_path).startswith(path):
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100257 return True
258 return False
259
260
charujain9893e252017-09-14 13:33:22 +0200261def CheckApprovedFilesLintClean(input_api, output_api,
Artem Titova04d1402018-05-11 11:23:00 +0200262 source_file_filter=None):
oprypin2aa463f2017-03-23 03:17:02 -0700263 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
charujain9893e252017-09-14 13:33:22 +0200264 This check is based on CheckChangeLintsClean in
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000265 depot_tools/presubmit_canned_checks.py but has less filters and only checks
266 added files."""
267 result = []
268
269 # Initialize cpplint.
270 import cpplint
271 # Access to a protected member _XX of a client class
272 # pylint: disable=W0212
273 cpplint._cpplint_state.ResetErrorCounts()
274
jbauchc4e3ead2016-02-19 00:25:55 -0800275 lint_filters = cpplint._Filters()
276 lint_filters.extend(BLACKLIST_LINT_FILTERS)
277 cpplint._SetFilters(','.join(lint_filters))
278
oprypin2aa463f2017-03-23 03:17:02 -0700279 # Create a platform independent blacklist for cpplint.
280 blacklist_paths = [input_api.os_path.join(*path.split('/'))
281 for path in CPPLINT_BLACKLIST]
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100282
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000283 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 03:17:02 -0700284 # default when running cpplint.py from command line. To make it possible to
285 # work with not-yet-converted code, we're only applying it to new (or
286 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000287 verbosity_level = 1
288 files = []
289 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200290 # Note that moved/renamed files also count as added.
charujain9893e252017-09-14 13:33:22 +0200291 if f.Action() == 'A' or not IsLintBlacklisted(blacklist_paths,
Artem Titove92675b2018-05-22 10:21:27 +0200292 f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000293 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000294
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000295 for file_name in files:
296 cpplint.ProcessFile(file_name, verbosity_level)
297
298 if cpplint._cpplint_state.error_count > 0:
299 if input_api.is_committing:
oprypin8e58d652017-03-21 07:52:41 -0700300 res_type = output_api.PresubmitError
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000301 else:
302 res_type = output_api.PresubmitPromptWarning
303 result = [res_type('Changelist failed cpplint.py check.')]
304
305 return result
306
Artem Titove92675b2018-05-22 10:21:27 +0200307
charujain9893e252017-09-14 13:33:22 +0200308def CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700309 # Disallow referencing source files with paths above the GN file location.
310 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
311 re.MULTILINE | re.DOTALL)
312 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
313 violating_gn_files = set()
314 violating_source_entries = []
315 for gn_file in gn_files:
316 contents = input_api.ReadFile(gn_file)
317 for source_block_match in source_pattern.finditer(contents):
318 # Find all source list entries starting with ../ in the source block
319 # (exclude overrides entries).
320 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
321 source_file = file_list_match.group(1)
322 if 'overrides/' not in source_file:
323 violating_source_entries.append(source_file)
324 violating_gn_files.add(gn_file)
325 if violating_gn_files:
326 return [output_api.PresubmitError(
327 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100328 'allowed. Please introduce new GN targets in the proper location '
329 'instead.\n'
ehmaldonado5b1ba082016-09-02 05:51:08 -0700330 'Invalid source entries:\n'
331 '%s\n'
332 'Violating GN files:' % '\n'.join(violating_source_entries),
333 items=violating_gn_files)]
334 return []
335
Artem Titove92675b2018-05-22 10:21:27 +0200336
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200337def CheckNoMixingSources(input_api, gn_files, output_api):
338 """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target.
339
340 See bugs.webrtc.org/7743 for more context.
341 """
Artem Titove92675b2018-05-22 10:21:27 +0200342
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200343 def _MoreThanOneSourceUsed(*sources_lists):
344 sources_used = 0
345 for source_list in sources_lists:
346 if len(source_list):
347 sources_used += 1
348 return sources_used > 1
349
350 errors = defaultdict(lambda: [])
kjellander7439f972016-12-05 22:47:46 -0800351 for gn_file in gn_files:
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200352 gn_file_content = input_api.ReadFile(gn_file)
353 for target_match in TARGET_RE.finditer(gn_file_content):
354 # list_of_sources is a list of tuples of the form
355 # (c_files, cc_files, objc_files) that keeps track of all the sources
356 # defined in a target. A GN target can have more that on definition of
357 # sources (since it supports if/else statements).
358 # E.g.:
359 # rtc_static_library("foo") {
360 # if (is_win) {
361 # sources = [ "foo.cc" ]
362 # } else {
363 # sources = [ "foo.mm" ]
364 # }
365 # }
366 # This is allowed and the presubmit check should support this case.
367 list_of_sources = []
kjellander7439f972016-12-05 22:47:46 -0800368 c_files = []
369 cc_files = []
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200370 objc_files = []
371 target_name = target_match.group('target_name')
372 target_contents = target_match.group('target_contents')
373 for sources_match in SOURCES_RE.finditer(target_contents):
374 if '+=' not in sources_match.group(0):
375 if c_files or cc_files or objc_files:
376 list_of_sources.append((c_files, cc_files, objc_files))
377 c_files = []
378 cc_files = []
379 objc_files = []
380 for file_match in FILE_PATH_RE.finditer(sources_match.group(1)):
381 file_path = file_match.group('file_path')
382 extension = file_match.group('extension')
383 if extension == '.c':
384 c_files.append(file_path + extension)
385 if extension == '.cc':
386 cc_files.append(file_path + extension)
387 if extension in ['.m', '.mm']:
388 objc_files.append(file_path + extension)
389 list_of_sources.append((c_files, cc_files, objc_files))
390 for c_files_list, cc_files_list, objc_files_list in list_of_sources:
391 if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list):
392 all_sources = sorted(c_files_list + cc_files_list + objc_files_list)
393 errors[gn_file.LocalPath()].append((target_name, all_sources))
394 if errors:
kjellander7439f972016-12-05 22:47:46 -0800395 return [output_api.PresubmitError(
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200396 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n'
397 'Please create a separate target for each collection of sources.\n'
kjellander7439f972016-12-05 22:47:46 -0800398 'Mixed sources: \n'
399 '%s\n'
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200400 'Violating GN files:\n%s\n' % (json.dumps(errors, indent=2),
401 '\n'.join(errors.keys())))]
kjellander7439f972016-12-05 22:47:46 -0800402 return []
403
Artem Titove92675b2018-05-22 10:21:27 +0200404
charujain9893e252017-09-14 13:33:22 +0200405def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
ehmaldonado4fb97462017-01-30 05:27:22 -0800406 cwd = input_api.PresubmitLocalPath()
Oleh Prypin2f33a562017-10-04 20:17:54 +0200407 with _AddToPath(input_api.os_path.join(
408 cwd, 'tools_webrtc', 'presubmit_checks_lib')):
409 from check_package_boundaries import CheckPackageBoundaries
410 build_files = [os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files]
411 errors = CheckPackageBoundaries(cwd, build_files)[:5]
412 if errors:
ehmaldonado4fb97462017-01-30 05:27:22 -0800413 return [output_api.PresubmitError(
Oleh Prypin2f33a562017-10-04 20:17:54 +0200414 'There are package boundary violations in the following GN files:',
415 long_text='\n\n'.join(str(err) for err in errors))]
ehmaldonado4fb97462017-01-30 05:27:22 -0800416 return []
417
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100418
419def _ReportErrorFileAndLineNumber(filename, line_num):
420 """Default error formatter for _FindNewViolationsOfRule."""
421 return '%s (line %s)' % (filename, line_num)
422
423
424def CheckNoStreamUsageIsAdded(input_api, output_api,
Artem Titov739351d2018-05-11 12:21:36 +0200425 source_file_filter,
426 error_formatter=_ReportErrorFileAndLineNumber):
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100427 """Make sure that no more dependencies on stringstream are added."""
428 error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
429 'deprecated.\n'
430 'This includes the following types:\n'
431 'std::istringstream, std::ostringstream, std::wistringstream, '
432 'std::wostringstream,\n'
433 'std::wstringstream, std::ostream, std::wostream, std::istream,'
434 'std::wistream,\n'
435 'std::iostream, std::wiostream.\n'
436 'If you are not adding this code (e.g. you are just moving '
437 'existing code),\n'
438 'you can add a comment on the line that causes the problem:\n\n'
439 '#include <sstream> // no-presubmit-check TODO(webrtc:8982)\n'
440 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n'
441 '\n'
Karl Wibergebd01e82018-03-14 15:08:39 +0100442 'If you are adding new code, consider using '
443 'rtc::SimpleStringBuilder\n'
444 '(in rtc_base/strings/string_builder.h).\n'
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100445 'Affected files:\n')
446 errors = [] # 2-element tuples with (file, line number)
447 include_re = input_api.re.compile(r'#include <(i|o|s)stream>')
448 usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream')
449 no_presubmit_re = input_api.re.compile(
Jonas Olsson74395342018-04-03 12:22:07 +0200450 r'// no-presubmit-check TODO\(webrtc:8982\)')
Artem Titova04d1402018-05-11 11:23:00 +0200451 file_filter = lambda x: (input_api.FilterSourceFile(x)
452 and source_file_filter(x))
453 for f in input_api.AffectedSourceFiles(file_filter):
Mirko Bonadeid2c83322018-03-19 10:31:47 +0000454 if f.LocalPath() == 'PRESUBMIT.py':
455 continue
456 for line_num, line in f.ChangedContents():
457 if ((include_re.search(line) or usage_re.search(line))
458 and not no_presubmit_re.search(line)):
459 errors.append(error_formatter(f.LocalPath(), line_num))
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100460 if errors:
461 return [output_api.PresubmitError(error_msg, errors)]
462 return []
463
Artem Titove92675b2018-05-22 10:21:27 +0200464
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200465def CheckPublicDepsIsNotUsed(gn_files, input_api, output_api):
466 """Checks that public_deps is not used without a good reason."""
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100467 result = []
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200468 no_presubmit_check_re = input_api.re.compile(
469 r'# no-presubmit-check TODO\(webrtc:8603\)')
470 error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files '
471 'because it doesn\'t map well to downstream build systems.\n'
472 'Used in: %s (line %d).\n'
473 'If you are not adding this code (e.g. you are just moving '
474 'existing code) or you have a good reason, you can add a '
475 'comment on the line that causes the problem:\n\n'
476 'public_deps = [ # no-presubmit-check TODO(webrtc:8603)\n')
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100477 for affected_file in gn_files:
478 for (line_number, affected_line) in affected_file.ChangedContents():
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200479 if ('public_deps' in affected_line
480 and not no_presubmit_check_re.search(affected_line)):
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100481 result.append(
482 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
483 line_number)))
484 return result
485
Artem Titove92675b2018-05-22 10:21:27 +0200486
Patrik Höglund6f491062018-01-11 12:04:23 +0100487def CheckCheckIncludesIsNotUsed(gn_files, output_api):
488 result = []
489 error_msg = ('check_includes overrides are not allowed since it can cause '
490 'incorrect dependencies to form. It effectively means that your '
491 'module can include any .h file without depending on its '
492 'corresponding target. There are some exceptional cases when '
493 'this is allowed: if so, get approval from a .gn owner in the'
494 'root OWNERS file.\n'
495 'Used in: %s (line %d).')
496 for affected_file in gn_files:
497 for (line_number, affected_line) in affected_file.ChangedContents():
498 if 'check_includes' in affected_line:
499 result.append(
500 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
501 line_number)))
502 return result
503
Artem Titove92675b2018-05-22 10:21:27 +0200504
Artem Titova04d1402018-05-11 11:23:00 +0200505def CheckGnChanges(input_api, output_api, source_file_filter):
506 file_filter = lambda x: (input_api.FilterSourceFile(
Oleh Prypinafe01652017-10-04 15:56:08 +0200507 x, white_list=(r'.+\.(gn|gni)$',),
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100508 black_list=(r'.*/presubmit_checks_lib/testdata/.*',))
Artem Titova04d1402018-05-11 11:23:00 +0200509 and source_file_filter(x))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700510
511 gn_files = []
Artem Titova04d1402018-05-11 11:23:00 +0200512 for f in input_api.AffectedSourceFiles(file_filter):
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200513 gn_files.append(f)
ehmaldonado5b1ba082016-09-02 05:51:08 -0700514
515 result = []
516 if gn_files:
charujain9893e252017-09-14 13:33:22 +0200517 result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api))
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200518 result.extend(CheckNoMixingSources(input_api, gn_files, output_api))
519 result.extend(CheckNoPackageBoundaryViolations(input_api, gn_files,
520 output_api))
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200521 result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, output_api))
Patrik Höglund6f491062018-01-11 12:04:23 +0100522 result.extend(CheckCheckIncludesIsNotUsed(gn_files, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700523 return result
524
Artem Titove92675b2018-05-22 10:21:27 +0200525
Oleh Prypin920b6532017-10-05 11:28:51 +0200526def CheckGnGen(input_api, output_api):
527 """Runs `gn gen --check` with default args to detect mismatches between
528 #includes and dependencies in the BUILD.gn files, as well as general build
529 errors.
530 """
531 with _AddToPath(input_api.os_path.join(
532 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
533 from gn_check import RunGnCheck
534 errors = RunGnCheck(input_api.PresubmitLocalPath())[:5]
535 if errors:
536 return [output_api.PresubmitPromptWarning(
537 'Some #includes do not match the build dependency graph. Please run:\n'
538 ' gn gen --check <out_dir>',
539 long_text='\n\n'.join(errors))]
540 return []
541
Artem Titove92675b2018-05-22 10:21:27 +0200542
Artem Titova04d1402018-05-11 11:23:00 +0200543def CheckUnwantedDependencies(input_api, output_api, source_file_filter):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000544 """Runs checkdeps on #include statements added in this
545 change. Breaking - rules is an error, breaking ! rules is a
546 warning.
547 """
548 # Copied from Chromium's src/PRESUBMIT.py.
549
550 # We need to wait until we have an input_api object and use this
551 # roundabout construct to import checkdeps because this file is
552 # eval-ed and thus doesn't have __file__.
Oleh Prypin2f33a562017-10-04 20:17:54 +0200553 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
554 'buildtools', 'checkdeps')
555 if not os.path.exists(checkdeps_path):
556 return [output_api.PresubmitError(
557 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
558 'download all the DEPS entries?' % checkdeps_path)]
559 with _AddToPath(checkdeps_path):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000560 import checkdeps
561 from cpp_checker import CppChecker
562 from rules import Rule
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000563
564 added_includes = []
Artem Titova04d1402018-05-11 11:23:00 +0200565 for f in input_api.AffectedFiles(file_filter=source_file_filter):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000566 if not CppChecker.IsCppFile(f.LocalPath()):
567 continue
568
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200569 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000570 added_includes.append([f.LocalPath(), changed_lines])
571
572 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
573
574 error_descriptions = []
575 warning_descriptions = []
576 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
577 added_includes):
578 description_with_path = '%s\n %s' % (path, rule_description)
579 if rule_type == Rule.DISALLOW:
580 error_descriptions.append(description_with_path)
581 else:
582 warning_descriptions.append(description_with_path)
583
584 results = []
585 if error_descriptions:
586 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 03:47:05 -0700587 'You added one or more #includes that violate checkdeps rules.\n'
588 'Check that the DEPS files in these locations contain valid rules.\n'
589 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
590 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000591 error_descriptions))
592 if warning_descriptions:
593 results.append(output_api.PresubmitPromptOrNotify(
594 'You added one or more #includes of files that are temporarily\n'
595 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 03:47:05 -0700596 '#include? See relevant DEPS file(s) for details and contacts.\n'
597 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
598 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000599 warning_descriptions))
600 return results
601
Artem Titove92675b2018-05-22 10:21:27 +0200602
charujain9893e252017-09-14 13:33:22 +0200603def CheckCommitMessageBugEntry(input_api, output_api):
604 """Check that bug entries are well-formed in commit message."""
605 bogus_bug_msg = (
Mirko Bonadei61880182017-10-12 15:12:35 +0200606 'Bogus Bug entry: %s. Please specify the issue tracker prefix and the '
charujain9893e252017-09-14 13:33:22 +0200607 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.')
608 results = []
Mirko Bonadei61880182017-10-12 15:12:35 +0200609 for bug in input_api.change.BugsFromDescription():
charujain9893e252017-09-14 13:33:22 +0200610 bug = bug.strip()
611 if bug.lower() == 'none':
612 continue
charujain81a58c72017-09-25 13:25:45 +0200613 if 'b/' not in bug and ':' not in bug:
charujain9893e252017-09-14 13:33:22 +0200614 try:
615 if int(bug) > 100000:
616 # Rough indicator for current chromium bugs.
617 prefix_guess = 'chromium'
618 else:
619 prefix_guess = 'webrtc'
Mirko Bonadei61880182017-10-12 15:12:35 +0200620 results.append('Bug entry requires issue tracker prefix, e.g. %s:%s' %
charujain9893e252017-09-14 13:33:22 +0200621 (prefix_guess, bug))
622 except ValueError:
623 results.append(bogus_bug_msg % bug)
charujain81a58c72017-09-25 13:25:45 +0200624 elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)):
charujain9893e252017-09-14 13:33:22 +0200625 results.append(bogus_bug_msg % bug)
626 return [output_api.PresubmitError(r) for r in results]
627
Artem Titove92675b2018-05-22 10:21:27 +0200628
charujain9893e252017-09-14 13:33:22 +0200629def CheckChangeHasBugField(input_api, output_api):
Mirko Bonadei61880182017-10-12 15:12:35 +0200630 """Requires that the changelist is associated with a bug.
kjellanderd1e26a92016-09-19 08:11:16 -0700631
632 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
Mirko Bonadei61880182017-10-12 15:12:35 +0200633 since it fails the presubmit if the bug field is missing or doesn't contain
kjellanderd1e26a92016-09-19 08:11:16 -0700634 a bug reference.
Mirko Bonadei61880182017-10-12 15:12:35 +0200635
636 This supports both 'BUG=' and 'Bug:' since we are in the process of migrating
637 to Gerrit and it encourages the usage of 'Bug:'.
kjellanderd1e26a92016-09-19 08:11:16 -0700638 """
Mirko Bonadei61880182017-10-12 15:12:35 +0200639 if input_api.change.BugsFromDescription():
kjellanderd1e26a92016-09-19 08:11:16 -0700640 return []
641 else:
642 return [output_api.PresubmitError(
Mirko Bonadei61880182017-10-12 15:12:35 +0200643 'The "Bug: [bug number]" footer is mandatory. Please create a bug and '
kjellanderd1e26a92016-09-19 08:11:16 -0700644 'reference it using either of:\n'
Mirko Bonadei61880182017-10-12 15:12:35 +0200645 ' * https://bugs.webrtc.org - reference it using Bug: webrtc:XXXX\n'
646 ' * https://crbug.com - reference it using Bug: chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000647
Artem Titove92675b2018-05-22 10:21:27 +0200648
Artem Titova04d1402018-05-11 11:23:00 +0200649def CheckJSONParseErrors(input_api, output_api, source_file_filter):
kjellander569cf942016-02-11 05:02:59 -0800650 """Check that JSON files do not contain syntax errors."""
651
652 def FilterFile(affected_file):
Artem Titova04d1402018-05-11 11:23:00 +0200653 return (input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
654 and source_file_filter(affected_file))
kjellander569cf942016-02-11 05:02:59 -0800655
656 def GetJSONParseError(input_api, filename):
657 try:
658 contents = input_api.ReadFile(filename)
659 input_api.json.loads(contents)
660 except ValueError as e:
661 return e
662 return None
663
664 results = []
665 for affected_file in input_api.AffectedFiles(
666 file_filter=FilterFile, include_deletes=False):
667 parse_error = GetJSONParseError(input_api,
668 affected_file.AbsoluteLocalPath())
669 if parse_error:
670 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
Artem Titove92675b2018-05-22 10:21:27 +0200671 (affected_file.LocalPath(),
672 parse_error)))
kjellander569cf942016-02-11 05:02:59 -0800673 return results
674
675
charujain9893e252017-09-14 13:33:22 +0200676def RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 06:42:43 -0700677 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200678 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
679
680 test_directories = [
Edward Lemur6d01f6d2017-09-14 17:02:01 +0200681 input_api.PresubmitLocalPath(),
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200682 Join('rtc_tools', 'py_event_log_analyzer'),
683 Join('rtc_tools'),
684 Join('audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 05:27:22 -0800685 ] + [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200686 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 05:27:22 -0800687 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200688 ]
689
690 tests = []
691 for directory in test_directories:
692 tests.extend(
693 input_api.canned_checks.GetUnitTestsInDirectory(
694 input_api,
695 output_api,
696 directory,
697 whitelist=[r'.+_test\.py$']))
698 return input_api.RunTests(tests, parallel=True)
699
700
Artem Titova04d1402018-05-11 11:23:00 +0200701def CheckUsageOfGoogleProtobufNamespace(input_api, output_api,
702 source_file_filter):
mbonadei38415b22017-04-07 05:38:01 -0700703 """Checks that the namespace google::protobuf has not been used."""
704 files = []
705 pattern = input_api.re.compile(r'google::protobuf')
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200706 proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h')
Artem Titova04d1402018-05-11 11:23:00 +0200707 file_filter = lambda x: (input_api.FilterSourceFile(x)
708 and source_file_filter(x))
709 for f in input_api.AffectedSourceFiles(file_filter):
mbonadei38415b22017-04-07 05:38:01 -0700710 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
711 continue
712 contents = input_api.ReadFile(f)
713 if pattern.search(contents):
714 files.append(f)
715
716 if files:
717 return [output_api.PresubmitError(
718 'Please avoid to use namespace `google::protobuf` directly.\n'
719 'Add a using directive in `%s` and include that header instead.'
720 % proto_utils_path, files)]
721 return []
722
723
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200724def _LicenseHeader(input_api):
725 """Returns the license header regexp."""
726 # Accept any year number from 2003 to the current year
727 current_year = int(input_api.time.strftime('%Y'))
728 allowed_years = (str(s) for s in reversed(xrange(2003, current_year + 1)))
729 years_re = '(' + '|'.join(allowed_years) + ')'
730 license_header = (
731 r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
732 r'All [Rr]ights [Rr]eserved\.\n'
733 r'.*?\n'
734 r'.*? Use of this source code is governed by a BSD-style license\n'
735 r'.*? that can be found in the LICENSE file in the root of the source\n'
736 r'.*? tree\. An additional intellectual property rights grant can be '
737 r'found\n'
738 r'.*? in the file PATENTS\. All contributing project authors may\n'
739 r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
740 ) % {
741 'year': years_re,
742 }
743 return license_header
744
745
charujain9893e252017-09-14 13:33:22 +0200746def CommonChecks(input_api, output_api):
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000747 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000748 results = []
tkchin42f580e2015-11-26 23:18:23 -0800749 # Filter out files that are in objc or ios dirs from being cpplint-ed since
750 # they do not follow C++ lint rules.
751 black_list = input_api.DEFAULT_BLACK_LIST + (
752 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000753 r".*objc\.[hcm]+$",
tkchin42f580e2015-11-26 23:18:23 -0800754 )
755 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
charujain9893e252017-09-14 13:33:22 +0200756 results.extend(CheckApprovedFilesLintClean(
tkchin42f580e2015-11-26 23:18:23 -0800757 input_api, output_api, source_file_filter))
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200758 results.extend(input_api.canned_checks.CheckLicense(
759 input_api, output_api, _LicenseHeader(input_api)))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000760 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100761 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200762 r'^build[\\\/].*\.py$',
763 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-12 22:43:38 -0700764 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 12:01:17 +0100765 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200766 r'^out.*[\\\/].*\.py$',
767 r'^testing[\\\/].*\.py$',
768 r'^third_party[\\\/].*\.py$',
Artem Titovc47c9c02018-05-17 10:00:20 +0200769 r'^third_party_chromium[\\\/].*\.py$',
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100770 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 12:21:39 -0800771 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200772 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
773 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200774 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200775 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800776
nisse3d21e232016-09-02 03:07:06 -0700777 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200778 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
779 # we need to have different license checks in talk/ and webrtc/ directories.
780 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200781
tkchin3cd9a302016-06-08 12:40:28 -0700782 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
783 # ObjC subdirectories ObjC headers.
784 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100785 # Skip long-lines check for DEPS and GN files.
786 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
Artem Titova04d1402018-05-11 11:23:00 +0200787 # Also we will skip most checks for third_party directory.
Artem Titovc47c9c02018-05-17 10:00:20 +0200788 third_party_filter_list = (r'^third_party[\\\/].+',
789 r'^third_party_chromium[\\\/].+')
tkchin3cd9a302016-06-08 12:40:28 -0700790 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
Artem Titova04d1402018-05-11 11:23:00 +0200791 black_list=build_file_filter_list + objc_filter_list +
792 third_party_filter_list)
tkchin3cd9a302016-06-08 12:40:28 -0700793 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
794 white_list=objc_filter_list)
Artem Titove92675b2018-05-22 10:21:27 +0200795 non_third_party_sources = lambda x: input_api.FilterSourceFile(x,
796 black_list=third_party_filter_list)
797
Artem Titov71d4dc32018-05-23 10:16:30 +0200798 results.extend(CheckNoGitRepoInThirdParty(input_api, output_api))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000799 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700800 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
801 results.extend(input_api.canned_checks.CheckLongLines(
802 input_api, output_api, maxlen=100,
803 source_file_filter=hundred_char_sources))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000804 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
Artem Titova04d1402018-05-11 11:23:00 +0200805 input_api, output_api, source_file_filter=non_third_party_sources))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000806 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
Artem Titova04d1402018-05-11 11:23:00 +0200807 input_api, output_api, source_file_filter=non_third_party_sources))
kjellandere5dc62a2016-12-14 00:16:21 -0800808 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
809 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000810 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
Artem Titova04d1402018-05-11 11:23:00 +0200811 input_api, output_api, source_file_filter=non_third_party_sources))
Yves Gerey87a93532018-06-20 15:51:49 +0200812 results.extend(input_api.canned_checks.CheckPatchFormatted(
813 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200814 results.extend(CheckNativeApiHeaderChanges(input_api, output_api))
Artem Titova04d1402018-05-11 11:23:00 +0200815 results.extend(CheckNoIOStreamInHeaders(
816 input_api, output_api, source_file_filter=non_third_party_sources))
817 results.extend(CheckNoPragmaOnce(
818 input_api, output_api, source_file_filter=non_third_party_sources))
819 results.extend(CheckNoFRIEND_TEST(
820 input_api, output_api, source_file_filter=non_third_party_sources))
821 results.extend(CheckGnChanges(
822 input_api, output_api, source_file_filter=non_third_party_sources))
823 results.extend(CheckUnwantedDependencies(
824 input_api, output_api, source_file_filter=non_third_party_sources))
825 results.extend(CheckJSONParseErrors(
826 input_api, output_api, source_file_filter=non_third_party_sources))
charujain9893e252017-09-14 13:33:22 +0200827 results.extend(RunPythonTests(input_api, output_api))
Artem Titova04d1402018-05-11 11:23:00 +0200828 results.extend(CheckUsageOfGoogleProtobufNamespace(
829 input_api, output_api, source_file_filter=non_third_party_sources))
830 results.extend(CheckOrphanHeaders(
831 input_api, output_api, source_file_filter=non_third_party_sources))
832 results.extend(CheckNewlineAtTheEndOfProtoFiles(
833 input_api, output_api, source_file_filter=non_third_party_sources))
834 results.extend(CheckNoStreamUsageIsAdded(
Artem Titov739351d2018-05-11 12:21:36 +0200835 input_api, output_api, non_third_party_sources))
Artem Titove92675b2018-05-22 10:21:27 +0200836 results.extend(CheckThirdPartyChanges(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000837 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000838
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000839
Artem Titov71d4dc32018-05-23 10:16:30 +0200840def CheckNoGitRepoInThirdParty(input_api, output_api):
841 if os.path.isdir(input_api.os_path.join(
842 input_api.PresubmitLocalPath(), 'third_party', '.git')):
843 return [output_api.PresubmitError("Please remove third_party/.git "
844 "directory. This error means that "
845 "possibly you also have to apply other "
846 "instructions from the May 11th PSA from "
847 "titovartem@.")]
848 return []
849
850
Artem Titove92675b2018-05-22 10:21:27 +0200851def CheckThirdPartyChanges(input_api, output_api):
852 with _AddToPath(input_api.os_path.join(
853 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
854 from check_3pp import CheckThirdPartyDirectory
855 return CheckThirdPartyDirectory(input_api, output_api)
856
857
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 = []
Artem Titov9aef5dc2018-05-22 16:44:23 +0200869
870 # We have to skip OWNERS check for chromium-specific third_party deps.
871 chromium_deps_file = input_api.os_path.join(
872 input_api.PresubmitLocalPath(),
873 'THIRD_PARTY_CHROMIUM_DEPS.json')
874 with open(chromium_deps_file, 'rb') as f:
875 chromium_deps = json.load(f).get('dependencies', [])
876 deps_blacklist = []
877 for dep in chromium_deps:
878 deps_blacklist.append(r'^third_party[\\\/]%s[\\\/].+' % dep)
879 deps_filter = lambda x: input_api.FilterSourceFile(
880 x, black_list=deps_blacklist)
881
charujain9893e252017-09-14 13:33:22 +0200882 results.extend(CommonChecks(input_api, output_api))
883 results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
Artem Titov9aef5dc2018-05-22 16:44:23 +0200884 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api,
885 source_file_filter=deps_filter))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000886 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
887 input_api, output_api))
888 results.extend(input_api.canned_checks.CheckChangeHasDescription(
889 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200890 results.extend(CheckChangeHasBugField(input_api, output_api))
891 results.extend(CheckCommitMessageBugEntry(input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000892 results.extend(input_api.canned_checks.CheckTreeIsOpen(
893 input_api, output_api,
894 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000895 return results
mbonadei74973ed2017-05-09 07:58:05 -0700896
897
Artem Titova04d1402018-05-11 11:23:00 +0200898def CheckOrphanHeaders(input_api, output_api, source_file_filter):
mbonadei74973ed2017-05-09 07:58:05 -0700899 # We need to wait until we have an input_api object and use this
900 # roundabout construct to import prebubmit_checks_lib because this file is
901 # eval-ed and thus doesn't have __file__.
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100902 error_msg = """{} should be listed in {}."""
mbonadei74973ed2017-05-09 07:58:05 -0700903 results = []
Patrik Höglund7e60de22018-01-09 14:22:00 +0100904 orphan_blacklist = [
905 os.path.join('tools_webrtc', 'ios', 'SDK'),
906 ]
Oleh Prypin2f33a562017-10-04 20:17:54 +0200907 with _AddToPath(input_api.os_path.join(
908 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
mbonadei74973ed2017-05-09 07:58:05 -0700909 from check_orphan_headers import GetBuildGnPathFromFilePath
910 from check_orphan_headers import IsHeaderInBuildGn
mbonadei74973ed2017-05-09 07:58:05 -0700911
Artem Titova04d1402018-05-11 11:23:00 +0200912 file_filter = lambda x: input_api.FilterSourceFile(
913 x, black_list=orphan_blacklist) and source_file_filter(x)
914 for f in input_api.AffectedSourceFiles(file_filter):
Patrik Höglund7e60de22018-01-09 14:22:00 +0100915 if f.LocalPath().endswith('.h'):
mbonadei74973ed2017-05-09 07:58:05 -0700916 file_path = os.path.abspath(f.LocalPath())
917 root_dir = os.getcwd()
918 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
919 root_dir)
920 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
921 if not in_build_gn:
922 results.append(output_api.PresubmitError(error_msg.format(
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100923 f.LocalPath(), os.path.relpath(gn_file_path))))
mbonadei74973ed2017-05-09 07:58:05 -0700924 return results
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200925
926
Artem Titove92675b2018-05-22 10:21:27 +0200927def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api, source_file_filter):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200928 """Checks that all .proto files are terminated with a newline."""
929 error_msg = 'File {} must end with exactly one newline.'
930 results = []
Artem Titova04d1402018-05-11 11:23:00 +0200931 file_filter = lambda x: input_api.FilterSourceFile(
932 x, white_list=(r'.+\.proto$',)) and source_file_filter(x)
933 for f in input_api.AffectedSourceFiles(file_filter):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200934 file_path = f.LocalPath()
935 with open(file_path) as f:
936 lines = f.readlines()
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200937 if len(lines) > 0 and not lines[-1].endswith('\n'):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200938 results.append(output_api.PresubmitError(error_msg.format(file_path)))
939 return results