blob: 5a40612bfbf50f07af6dc8e1dbede8e7c9b3d9f7 [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
16
oprypin2aa463f2017-03-23 03:17:02 -070017# Files and directories that are *skipped* by cpplint in the presubmit script.
18CPPLINT_BLACKLIST = [
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019 'api/video_codecs/video_decoder.h',
20 'common_types.cc',
21 'common_types.h',
22 'examples/objc',
Steve Antone78bcb92017-10-31 09:53:08 -070023 'media/base/streamparams.h',
24 'media/base/videocommon.h',
25 'media/engine/fakewebrtcdeviceinfo.h',
26 'media/sctp/sctptransport.cc',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027 'modules/audio_coding',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028 'modules/audio_device',
29 'modules/audio_processing',
30 'modules/desktop_capture',
31 'modules/include/module_common_types.h',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032 'modules/utility',
33 'modules/video_capture',
Steve Anton6c38cc72017-11-29 10:25:58 -080034 'p2p/base/pseudotcp.cc',
35 'p2p/base/pseudotcp.h',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036 'rtc_base',
37 'sdk/android/src/jni',
38 'sdk/objc',
39 'system_wrappers',
40 'test',
Henrik Kjellander90fd7d82017-05-09 08:30:10 +020041 'tools_webrtc',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020042 'voice_engine',
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
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
charujain9893e252017-09-14 13:33:22 +0200161def CheckNativeApiHeaderChanges(input_api, output_api):
kjellander53047c92015-12-02 23:56:14 -0800162 """Checks to remind proper changing of native APIs."""
163 files = []
Karl Wiberg6bfac032017-10-27 15:14:20 +0200164 source_file_filter = lambda x: input_api.FilterSourceFile(
165 x, white_list=[r'.+\.(gn|gni|h)$'])
166 for f in input_api.AffectedSourceFiles(source_file_filter):
167 for path in API_DIRS:
168 dn = os.path.dirname(f.LocalPath())
169 if path == 'api':
170 # Special case: Subdirectories included.
171 if dn == 'api' or dn.startswith('api/'):
172 files.append(f)
173 else:
174 # Normal case: Subdirectories not included.
175 if dn == path:
176 files.append(f)
kjellander53047c92015-12-02 23:56:14 -0800177
178 if files:
kjellanderc88b5d52017-04-05 06:42:43 -0700179 return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
kjellander53047c92015-12-02 23:56:14 -0800180 return []
181
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100182
charujain9893e252017-09-14 13:33:22 +0200183def CheckNoIOStreamInHeaders(input_api, output_api):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000184 """Checks to make sure no .h files include <iostream>."""
185 files = []
186 pattern = input_api.re.compile(r'^#include\s*<iostream>',
187 input_api.re.MULTILINE)
188 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
189 if not f.LocalPath().endswith('.h'):
190 continue
191 contents = input_api.ReadFile(f)
192 if pattern.search(contents):
193 files.append(f)
194
195 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200196 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000197 'Do not #include <iostream> in header files, since it inserts static ' +
198 'initialization into every file including the header. Instead, ' +
199 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200200 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000201 return []
202
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000203
charujain9893e252017-09-14 13:33:22 +0200204def CheckNoPragmaOnce(input_api, output_api):
kjellander6aeef742017-02-20 01:13:18 -0800205 """Make sure that banned functions are not used."""
206 files = []
207 pattern = input_api.re.compile(r'^#pragma\s+once',
208 input_api.re.MULTILINE)
209 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
210 if not f.LocalPath().endswith('.h'):
211 continue
212 contents = input_api.ReadFile(f)
213 if pattern.search(contents):
214 files.append(f)
215
216 if files:
217 return [output_api.PresubmitError(
218 'Do not use #pragma once in header files.\n'
219 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
220 files)]
221 return []
222
223
charujain9893e252017-09-14 13:33:22 +0200224def CheckNoFRIEND_TEST(input_api, output_api): # pylint: disable=invalid-name
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000225 """Make sure that gtest's FRIEND_TEST() macro is not used, the
226 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
227 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
228 problems = []
229
230 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
231 for f in input_api.AffectedFiles(file_filter=file_filter):
232 for line_num, line in f.ChangedContents():
233 if 'FRIEND_TEST(' in line:
234 problems.append(' %s:%d' % (f.LocalPath(), line_num))
235
236 if not problems:
237 return []
238 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
239 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
240 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
241
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000242
charujain9893e252017-09-14 13:33:22 +0200243def IsLintBlacklisted(blacklist_paths, file_path):
oprypin2aa463f2017-03-23 03:17:02 -0700244 """ Checks if a file is blacklisted for lint check."""
245 for path in blacklist_paths:
246 if file_path == path or os.path.dirname(file_path).startswith(path):
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100247 return True
248 return False
249
250
charujain9893e252017-09-14 13:33:22 +0200251def CheckApprovedFilesLintClean(input_api, output_api,
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000252 source_file_filter=None):
oprypin2aa463f2017-03-23 03:17:02 -0700253 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
charujain9893e252017-09-14 13:33:22 +0200254 This check is based on CheckChangeLintsClean in
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000255 depot_tools/presubmit_canned_checks.py but has less filters and only checks
256 added files."""
257 result = []
258
259 # Initialize cpplint.
260 import cpplint
261 # Access to a protected member _XX of a client class
262 # pylint: disable=W0212
263 cpplint._cpplint_state.ResetErrorCounts()
264
jbauchc4e3ead2016-02-19 00:25:55 -0800265 lint_filters = cpplint._Filters()
266 lint_filters.extend(BLACKLIST_LINT_FILTERS)
267 cpplint._SetFilters(','.join(lint_filters))
268
oprypin2aa463f2017-03-23 03:17:02 -0700269 # Create a platform independent blacklist for cpplint.
270 blacklist_paths = [input_api.os_path.join(*path.split('/'))
271 for path in CPPLINT_BLACKLIST]
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100272
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000273 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 03:17:02 -0700274 # default when running cpplint.py from command line. To make it possible to
275 # work with not-yet-converted code, we're only applying it to new (or
276 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000277 verbosity_level = 1
278 files = []
279 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200280 # Note that moved/renamed files also count as added.
charujain9893e252017-09-14 13:33:22 +0200281 if f.Action() == 'A' or not IsLintBlacklisted(blacklist_paths,
oprypin2aa463f2017-03-23 03:17:02 -0700282 f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000283 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000284
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000285 for file_name in files:
286 cpplint.ProcessFile(file_name, verbosity_level)
287
288 if cpplint._cpplint_state.error_count > 0:
289 if input_api.is_committing:
oprypin8e58d652017-03-21 07:52:41 -0700290 res_type = output_api.PresubmitError
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000291 else:
292 res_type = output_api.PresubmitPromptWarning
293 result = [res_type('Changelist failed cpplint.py check.')]
294
295 return result
296
charujain9893e252017-09-14 13:33:22 +0200297def CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700298 # Disallow referencing source files with paths above the GN file location.
299 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
300 re.MULTILINE | re.DOTALL)
301 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
302 violating_gn_files = set()
303 violating_source_entries = []
304 for gn_file in gn_files:
305 contents = input_api.ReadFile(gn_file)
306 for source_block_match in source_pattern.finditer(contents):
307 # Find all source list entries starting with ../ in the source block
308 # (exclude overrides entries).
309 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
310 source_file = file_list_match.group(1)
311 if 'overrides/' not in source_file:
312 violating_source_entries.append(source_file)
313 violating_gn_files.add(gn_file)
314 if violating_gn_files:
315 return [output_api.PresubmitError(
316 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100317 'allowed. Please introduce new GN targets in the proper location '
318 'instead.\n'
ehmaldonado5b1ba082016-09-02 05:51:08 -0700319 'Invalid source entries:\n'
320 '%s\n'
321 'Violating GN files:' % '\n'.join(violating_source_entries),
322 items=violating_gn_files)]
323 return []
324
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200325def CheckNoMixingSources(input_api, gn_files, output_api):
326 """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target.
327
328 See bugs.webrtc.org/7743 for more context.
329 """
330 def _MoreThanOneSourceUsed(*sources_lists):
331 sources_used = 0
332 for source_list in sources_lists:
333 if len(source_list):
334 sources_used += 1
335 return sources_used > 1
336
337 errors = defaultdict(lambda: [])
kjellander7439f972016-12-05 22:47:46 -0800338 for gn_file in gn_files:
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200339 gn_file_content = input_api.ReadFile(gn_file)
340 for target_match in TARGET_RE.finditer(gn_file_content):
341 # list_of_sources is a list of tuples of the form
342 # (c_files, cc_files, objc_files) that keeps track of all the sources
343 # defined in a target. A GN target can have more that on definition of
344 # sources (since it supports if/else statements).
345 # E.g.:
346 # rtc_static_library("foo") {
347 # if (is_win) {
348 # sources = [ "foo.cc" ]
349 # } else {
350 # sources = [ "foo.mm" ]
351 # }
352 # }
353 # This is allowed and the presubmit check should support this case.
354 list_of_sources = []
kjellander7439f972016-12-05 22:47:46 -0800355 c_files = []
356 cc_files = []
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200357 objc_files = []
358 target_name = target_match.group('target_name')
359 target_contents = target_match.group('target_contents')
360 for sources_match in SOURCES_RE.finditer(target_contents):
361 if '+=' not in sources_match.group(0):
362 if c_files or cc_files or objc_files:
363 list_of_sources.append((c_files, cc_files, objc_files))
364 c_files = []
365 cc_files = []
366 objc_files = []
367 for file_match in FILE_PATH_RE.finditer(sources_match.group(1)):
368 file_path = file_match.group('file_path')
369 extension = file_match.group('extension')
370 if extension == '.c':
371 c_files.append(file_path + extension)
372 if extension == '.cc':
373 cc_files.append(file_path + extension)
374 if extension in ['.m', '.mm']:
375 objc_files.append(file_path + extension)
376 list_of_sources.append((c_files, cc_files, objc_files))
377 for c_files_list, cc_files_list, objc_files_list in list_of_sources:
378 if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list):
379 all_sources = sorted(c_files_list + cc_files_list + objc_files_list)
380 errors[gn_file.LocalPath()].append((target_name, all_sources))
381 if errors:
kjellander7439f972016-12-05 22:47:46 -0800382 return [output_api.PresubmitError(
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200383 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n'
384 'Please create a separate target for each collection of sources.\n'
kjellander7439f972016-12-05 22:47:46 -0800385 'Mixed sources: \n'
386 '%s\n'
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200387 'Violating GN files:\n%s\n' % (json.dumps(errors, indent=2),
388 '\n'.join(errors.keys())))]
kjellander7439f972016-12-05 22:47:46 -0800389 return []
390
charujain9893e252017-09-14 13:33:22 +0200391def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
ehmaldonado4fb97462017-01-30 05:27:22 -0800392 cwd = input_api.PresubmitLocalPath()
Oleh Prypin2f33a562017-10-04 20:17:54 +0200393 with _AddToPath(input_api.os_path.join(
394 cwd, 'tools_webrtc', 'presubmit_checks_lib')):
395 from check_package_boundaries import CheckPackageBoundaries
396 build_files = [os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files]
397 errors = CheckPackageBoundaries(cwd, build_files)[:5]
398 if errors:
ehmaldonado4fb97462017-01-30 05:27:22 -0800399 return [output_api.PresubmitError(
Oleh Prypin2f33a562017-10-04 20:17:54 +0200400 'There are package boundary violations in the following GN files:',
401 long_text='\n\n'.join(str(err) for err in errors))]
ehmaldonado4fb97462017-01-30 05:27:22 -0800402 return []
403
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100404
405def _ReportErrorFileAndLineNumber(filename, line_num):
406 """Default error formatter for _FindNewViolationsOfRule."""
407 return '%s (line %s)' % (filename, line_num)
408
409
410def CheckNoStreamUsageIsAdded(input_api, output_api,
411 error_formatter=_ReportErrorFileAndLineNumber):
412 """Make sure that no more dependencies on stringstream are added."""
413 error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
414 'deprecated.\n'
415 'This includes the following types:\n'
416 'std::istringstream, std::ostringstream, std::wistringstream, '
417 'std::wostringstream,\n'
418 'std::wstringstream, std::ostream, std::wostream, std::istream,'
419 'std::wistream,\n'
420 'std::iostream, std::wiostream.\n'
421 'If you are not adding this code (e.g. you are just moving '
422 'existing code),\n'
423 'you can add a comment on the line that causes the problem:\n\n'
424 '#include <sstream> // no-presubmit-check TODO(webrtc:8982)\n'
425 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n'
426 '\n'
Karl Wibergebd01e82018-03-14 15:08:39 +0100427 'If you are adding new code, consider using '
428 'rtc::SimpleStringBuilder\n'
429 '(in rtc_base/strings/string_builder.h).\n'
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100430 'Affected files:\n')
431 errors = [] # 2-element tuples with (file, line number)
432 include_re = input_api.re.compile(r'#include <(i|o|s)stream>')
433 usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream')
434 no_presubmit_re = input_api.re.compile(
Jonas Olsson74395342018-04-03 12:22:07 +0200435 r'// no-presubmit-check TODO\(webrtc:8982\)')
Mirko Bonadeid2c83322018-03-19 10:31:47 +0000436 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
437 if f.LocalPath() == 'PRESUBMIT.py':
438 continue
439 for line_num, line in f.ChangedContents():
440 if ((include_re.search(line) or usage_re.search(line))
441 and not no_presubmit_re.search(line)):
442 errors.append(error_formatter(f.LocalPath(), line_num))
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100443 if errors:
444 return [output_api.PresubmitError(error_msg, errors)]
445 return []
446
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200447def CheckPublicDepsIsNotUsed(gn_files, input_api, output_api):
448 """Checks that public_deps is not used without a good reason."""
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100449 result = []
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200450 no_presubmit_check_re = input_api.re.compile(
451 r'# no-presubmit-check TODO\(webrtc:8603\)')
452 error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files '
453 'because it doesn\'t map well to downstream build systems.\n'
454 'Used in: %s (line %d).\n'
455 'If you are not adding this code (e.g. you are just moving '
456 'existing code) or you have a good reason, you can add a '
457 'comment on the line that causes the problem:\n\n'
458 'public_deps = [ # no-presubmit-check TODO(webrtc:8603)\n')
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100459 for affected_file in gn_files:
460 for (line_number, affected_line) in affected_file.ChangedContents():
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200461 if ('public_deps' in affected_line
462 and not no_presubmit_check_re.search(affected_line)):
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100463 result.append(
464 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
465 line_number)))
466 return result
467
Patrik Höglund6f491062018-01-11 12:04:23 +0100468def CheckCheckIncludesIsNotUsed(gn_files, output_api):
469 result = []
470 error_msg = ('check_includes overrides are not allowed since it can cause '
471 'incorrect dependencies to form. It effectively means that your '
472 'module can include any .h file without depending on its '
473 'corresponding target. There are some exceptional cases when '
474 'this is allowed: if so, get approval from a .gn owner in the'
475 'root OWNERS file.\n'
476 'Used in: %s (line %d).')
477 for affected_file in gn_files:
478 for (line_number, affected_line) in affected_file.ChangedContents():
479 if 'check_includes' in affected_line:
480 result.append(
481 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
482 line_number)))
483 return result
484
charujain9893e252017-09-14 13:33:22 +0200485def CheckGnChanges(input_api, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700486 source_file_filter = lambda x: input_api.FilterSourceFile(
Oleh Prypinafe01652017-10-04 15:56:08 +0200487 x, white_list=(r'.+\.(gn|gni)$',),
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100488 black_list=(r'.*/presubmit_checks_lib/testdata/.*',))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700489
490 gn_files = []
491 for f in input_api.AffectedSourceFiles(source_file_filter):
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200492 gn_files.append(f)
ehmaldonado5b1ba082016-09-02 05:51:08 -0700493
494 result = []
495 if gn_files:
charujain9893e252017-09-14 13:33:22 +0200496 result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api))
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200497 result.extend(CheckNoMixingSources(input_api, gn_files, output_api))
498 result.extend(CheckNoPackageBoundaryViolations(input_api, gn_files,
499 output_api))
Mirko Bonadeia05d47e2018-05-09 11:03:38 +0200500 result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, output_api))
Patrik Höglund6f491062018-01-11 12:04:23 +0100501 result.extend(CheckCheckIncludesIsNotUsed(gn_files, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700502 return result
503
Oleh Prypin920b6532017-10-05 11:28:51 +0200504def CheckGnGen(input_api, output_api):
505 """Runs `gn gen --check` with default args to detect mismatches between
506 #includes and dependencies in the BUILD.gn files, as well as general build
507 errors.
508 """
509 with _AddToPath(input_api.os_path.join(
510 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
511 from gn_check import RunGnCheck
512 errors = RunGnCheck(input_api.PresubmitLocalPath())[:5]
513 if errors:
514 return [output_api.PresubmitPromptWarning(
515 'Some #includes do not match the build dependency graph. Please run:\n'
516 ' gn gen --check <out_dir>',
517 long_text='\n\n'.join(errors))]
518 return []
519
charujain9893e252017-09-14 13:33:22 +0200520def CheckUnwantedDependencies(input_api, output_api):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000521 """Runs checkdeps on #include statements added in this
522 change. Breaking - rules is an error, breaking ! rules is a
523 warning.
524 """
525 # Copied from Chromium's src/PRESUBMIT.py.
526
527 # We need to wait until we have an input_api object and use this
528 # roundabout construct to import checkdeps because this file is
529 # eval-ed and thus doesn't have __file__.
Oleh Prypin2f33a562017-10-04 20:17:54 +0200530 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
531 'buildtools', 'checkdeps')
532 if not os.path.exists(checkdeps_path):
533 return [output_api.PresubmitError(
534 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
535 'download all the DEPS entries?' % checkdeps_path)]
536 with _AddToPath(checkdeps_path):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000537 import checkdeps
538 from cpp_checker import CppChecker
539 from rules import Rule
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000540
541 added_includes = []
542 for f in input_api.AffectedFiles():
543 if not CppChecker.IsCppFile(f.LocalPath()):
544 continue
545
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200546 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000547 added_includes.append([f.LocalPath(), changed_lines])
548
549 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
550
551 error_descriptions = []
552 warning_descriptions = []
553 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
554 added_includes):
555 description_with_path = '%s\n %s' % (path, rule_description)
556 if rule_type == Rule.DISALLOW:
557 error_descriptions.append(description_with_path)
558 else:
559 warning_descriptions.append(description_with_path)
560
561 results = []
562 if error_descriptions:
563 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 03:47:05 -0700564 'You added one or more #includes that violate checkdeps rules.\n'
565 'Check that the DEPS files in these locations contain valid rules.\n'
566 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
567 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000568 error_descriptions))
569 if warning_descriptions:
570 results.append(output_api.PresubmitPromptOrNotify(
571 'You added one or more #includes of files that are temporarily\n'
572 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 03:47:05 -0700573 '#include? See relevant DEPS file(s) for details and contacts.\n'
574 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
575 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000576 warning_descriptions))
577 return results
578
charujain9893e252017-09-14 13:33:22 +0200579def CheckCommitMessageBugEntry(input_api, output_api):
580 """Check that bug entries are well-formed in commit message."""
581 bogus_bug_msg = (
Mirko Bonadei61880182017-10-12 15:12:35 +0200582 'Bogus Bug entry: %s. Please specify the issue tracker prefix and the '
charujain9893e252017-09-14 13:33:22 +0200583 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.')
584 results = []
Mirko Bonadei61880182017-10-12 15:12:35 +0200585 for bug in input_api.change.BugsFromDescription():
charujain9893e252017-09-14 13:33:22 +0200586 bug = bug.strip()
587 if bug.lower() == 'none':
588 continue
charujain81a58c72017-09-25 13:25:45 +0200589 if 'b/' not in bug and ':' not in bug:
charujain9893e252017-09-14 13:33:22 +0200590 try:
591 if int(bug) > 100000:
592 # Rough indicator for current chromium bugs.
593 prefix_guess = 'chromium'
594 else:
595 prefix_guess = 'webrtc'
Mirko Bonadei61880182017-10-12 15:12:35 +0200596 results.append('Bug entry requires issue tracker prefix, e.g. %s:%s' %
charujain9893e252017-09-14 13:33:22 +0200597 (prefix_guess, bug))
598 except ValueError:
599 results.append(bogus_bug_msg % bug)
charujain81a58c72017-09-25 13:25:45 +0200600 elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)):
charujain9893e252017-09-14 13:33:22 +0200601 results.append(bogus_bug_msg % bug)
602 return [output_api.PresubmitError(r) for r in results]
603
604def CheckChangeHasBugField(input_api, output_api):
Mirko Bonadei61880182017-10-12 15:12:35 +0200605 """Requires that the changelist is associated with a bug.
kjellanderd1e26a92016-09-19 08:11:16 -0700606
607 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
Mirko Bonadei61880182017-10-12 15:12:35 +0200608 since it fails the presubmit if the bug field is missing or doesn't contain
kjellanderd1e26a92016-09-19 08:11:16 -0700609 a bug reference.
Mirko Bonadei61880182017-10-12 15:12:35 +0200610
611 This supports both 'BUG=' and 'Bug:' since we are in the process of migrating
612 to Gerrit and it encourages the usage of 'Bug:'.
kjellanderd1e26a92016-09-19 08:11:16 -0700613 """
Mirko Bonadei61880182017-10-12 15:12:35 +0200614 if input_api.change.BugsFromDescription():
kjellanderd1e26a92016-09-19 08:11:16 -0700615 return []
616 else:
617 return [output_api.PresubmitError(
Mirko Bonadei61880182017-10-12 15:12:35 +0200618 'The "Bug: [bug number]" footer is mandatory. Please create a bug and '
kjellanderd1e26a92016-09-19 08:11:16 -0700619 'reference it using either of:\n'
Mirko Bonadei61880182017-10-12 15:12:35 +0200620 ' * https://bugs.webrtc.org - reference it using Bug: webrtc:XXXX\n'
621 ' * https://crbug.com - reference it using Bug: chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000622
charujain9893e252017-09-14 13:33:22 +0200623def CheckJSONParseErrors(input_api, output_api):
kjellander569cf942016-02-11 05:02:59 -0800624 """Check that JSON files do not contain syntax errors."""
625
626 def FilterFile(affected_file):
627 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
628
629 def GetJSONParseError(input_api, filename):
630 try:
631 contents = input_api.ReadFile(filename)
632 input_api.json.loads(contents)
633 except ValueError as e:
634 return e
635 return None
636
637 results = []
638 for affected_file in input_api.AffectedFiles(
639 file_filter=FilterFile, include_deletes=False):
640 parse_error = GetJSONParseError(input_api,
641 affected_file.AbsoluteLocalPath())
642 if parse_error:
643 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
644 (affected_file.LocalPath(), parse_error)))
645 return results
646
647
charujain9893e252017-09-14 13:33:22 +0200648def RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 06:42:43 -0700649 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200650 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
651
652 test_directories = [
Edward Lemur6d01f6d2017-09-14 17:02:01 +0200653 input_api.PresubmitLocalPath(),
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200654 Join('rtc_tools', 'py_event_log_analyzer'),
655 Join('rtc_tools'),
656 Join('audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 05:27:22 -0800657 ] + [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200658 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 05:27:22 -0800659 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200660 ]
661
662 tests = []
663 for directory in test_directories:
664 tests.extend(
665 input_api.canned_checks.GetUnitTestsInDirectory(
666 input_api,
667 output_api,
668 directory,
669 whitelist=[r'.+_test\.py$']))
670 return input_api.RunTests(tests, parallel=True)
671
672
charujain9893e252017-09-14 13:33:22 +0200673def CheckUsageOfGoogleProtobufNamespace(input_api, output_api):
mbonadei38415b22017-04-07 05:38:01 -0700674 """Checks that the namespace google::protobuf has not been used."""
675 files = []
676 pattern = input_api.re.compile(r'google::protobuf')
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200677 proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h')
mbonadei38415b22017-04-07 05:38:01 -0700678 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
679 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
680 continue
681 contents = input_api.ReadFile(f)
682 if pattern.search(contents):
683 files.append(f)
684
685 if files:
686 return [output_api.PresubmitError(
687 'Please avoid to use namespace `google::protobuf` directly.\n'
688 'Add a using directive in `%s` and include that header instead.'
689 % proto_utils_path, files)]
690 return []
691
692
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200693def _LicenseHeader(input_api):
694 """Returns the license header regexp."""
695 # Accept any year number from 2003 to the current year
696 current_year = int(input_api.time.strftime('%Y'))
697 allowed_years = (str(s) for s in reversed(xrange(2003, current_year + 1)))
698 years_re = '(' + '|'.join(allowed_years) + ')'
699 license_header = (
700 r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
701 r'All [Rr]ights [Rr]eserved\.\n'
702 r'.*?\n'
703 r'.*? Use of this source code is governed by a BSD-style license\n'
704 r'.*? that can be found in the LICENSE file in the root of the source\n'
705 r'.*? tree\. An additional intellectual property rights grant can be '
706 r'found\n'
707 r'.*? in the file PATENTS\. All contributing project authors may\n'
708 r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
709 ) % {
710 'year': years_re,
711 }
712 return license_header
713
714
charujain9893e252017-09-14 13:33:22 +0200715def CommonChecks(input_api, output_api):
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000716 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000717 results = []
tkchin42f580e2015-11-26 23:18:23 -0800718 # Filter out files that are in objc or ios dirs from being cpplint-ed since
719 # they do not follow C++ lint rules.
720 black_list = input_api.DEFAULT_BLACK_LIST + (
721 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000722 r".*objc\.[hcm]+$",
tkchin42f580e2015-11-26 23:18:23 -0800723 )
724 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
charujain9893e252017-09-14 13:33:22 +0200725 results.extend(CheckApprovedFilesLintClean(
tkchin42f580e2015-11-26 23:18:23 -0800726 input_api, output_api, source_file_filter))
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200727 results.extend(input_api.canned_checks.CheckLicense(
728 input_api, output_api, _LicenseHeader(input_api)))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000729 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100730 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200731 r'^build[\\\/].*\.py$',
732 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-12 22:43:38 -0700733 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 12:01:17 +0100734 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200735 r'^out.*[\\\/].*\.py$',
736 r'^testing[\\\/].*\.py$',
737 r'^third_party[\\\/].*\.py$',
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100738 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 12:21:39 -0800739 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200740 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
741 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200742 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200743 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800744
nisse3d21e232016-09-02 03:07:06 -0700745 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200746 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
747 # we need to have different license checks in talk/ and webrtc/ directories.
748 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200749
tkchin3cd9a302016-06-08 12:40:28 -0700750 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
751 # ObjC subdirectories ObjC headers.
752 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100753 # Skip long-lines check for DEPS and GN files.
754 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
tkchin3cd9a302016-06-08 12:40:28 -0700755 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
756 black_list=build_file_filter_list + objc_filter_list)
757 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
758 white_list=objc_filter_list)
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000759 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700760 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
761 results.extend(input_api.canned_checks.CheckLongLines(
762 input_api, output_api, maxlen=100,
763 source_file_filter=hundred_char_sources))
764
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000765 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
766 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000767 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
768 input_api, output_api))
kjellandere5dc62a2016-12-14 00:16:21 -0800769 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
770 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000771 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
772 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200773 results.extend(CheckNativeApiHeaderChanges(input_api, output_api))
774 results.extend(CheckNoIOStreamInHeaders(input_api, output_api))
775 results.extend(CheckNoPragmaOnce(input_api, output_api))
776 results.extend(CheckNoFRIEND_TEST(input_api, output_api))
777 results.extend(CheckGnChanges(input_api, output_api))
778 results.extend(CheckUnwantedDependencies(input_api, output_api))
779 results.extend(CheckJSONParseErrors(input_api, output_api))
780 results.extend(RunPythonTests(input_api, output_api))
781 results.extend(CheckUsageOfGoogleProtobufNamespace(input_api, output_api))
Mirko Bonadei866d3372017-09-15 12:35:26 +0200782 results.extend(CheckOrphanHeaders(input_api, output_api))
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200783 results.extend(CheckNewlineAtTheEndOfProtoFiles(input_api, output_api))
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100784 results.extend(CheckNoStreamUsageIsAdded(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000785 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000786
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000787
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000788def CheckChangeOnUpload(input_api, output_api):
789 results = []
charujain9893e252017-09-14 13:33:22 +0200790 results.extend(CommonChecks(input_api, output_api))
Oleh Prypin920b6532017-10-05 11:28:51 +0200791 results.extend(CheckGnGen(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200792 results.extend(
793 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000794 return results
795
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000796
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000797def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000798 results = []
charujain9893e252017-09-14 13:33:22 +0200799 results.extend(CommonChecks(input_api, output_api))
800 results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000801 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000802 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
803 input_api, output_api))
804 results.extend(input_api.canned_checks.CheckChangeHasDescription(
805 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200806 results.extend(CheckChangeHasBugField(input_api, output_api))
807 results.extend(CheckCommitMessageBugEntry(input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000808 results.extend(input_api.canned_checks.CheckTreeIsOpen(
809 input_api, output_api,
810 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000811 return results
mbonadei74973ed2017-05-09 07:58:05 -0700812
813
charujain9893e252017-09-14 13:33:22 +0200814def CheckOrphanHeaders(input_api, output_api):
mbonadei74973ed2017-05-09 07:58:05 -0700815 # We need to wait until we have an input_api object and use this
816 # roundabout construct to import prebubmit_checks_lib because this file is
817 # eval-ed and thus doesn't have __file__.
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100818 error_msg = """{} should be listed in {}."""
mbonadei74973ed2017-05-09 07:58:05 -0700819 results = []
Patrik Höglund7e60de22018-01-09 14:22:00 +0100820 orphan_blacklist = [
821 os.path.join('tools_webrtc', 'ios', 'SDK'),
822 ]
Oleh Prypin2f33a562017-10-04 20:17:54 +0200823 with _AddToPath(input_api.os_path.join(
824 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
mbonadei74973ed2017-05-09 07:58:05 -0700825 from check_orphan_headers import GetBuildGnPathFromFilePath
826 from check_orphan_headers import IsHeaderInBuildGn
mbonadei74973ed2017-05-09 07:58:05 -0700827
Patrik Höglund7e60de22018-01-09 14:22:00 +0100828 source_file_filter = lambda x: input_api.FilterSourceFile(
829 x, black_list=orphan_blacklist)
830 for f in input_api.AffectedSourceFiles(source_file_filter):
831 if f.LocalPath().endswith('.h'):
mbonadei74973ed2017-05-09 07:58:05 -0700832 file_path = os.path.abspath(f.LocalPath())
833 root_dir = os.getcwd()
834 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
835 root_dir)
836 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
837 if not in_build_gn:
838 results.append(output_api.PresubmitError(error_msg.format(
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100839 f.LocalPath(), os.path.relpath(gn_file_path))))
mbonadei74973ed2017-05-09 07:58:05 -0700840 return results
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200841
842
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200843def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200844 """Checks that all .proto files are terminated with a newline."""
845 error_msg = 'File {} must end with exactly one newline.'
846 results = []
847 source_file_filter = lambda x: input_api.FilterSourceFile(
848 x, white_list=(r'.+\.proto$',))
849 for f in input_api.AffectedSourceFiles(source_file_filter):
850 file_path = f.LocalPath()
851 with open(file_path) as f:
852 lines = f.readlines()
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200853 if len(lines) > 0 and not lines[-1].endswith('\n'):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200854 results.append(output_api.PresubmitError(error_msg.format(file_path)))
855 return results