blob: 6360cb51e0ff56ba0eec4a96dca5a79f4d58c3b8 [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/session.cc',
35 'p2p/base/session.h',
36 'p2p/base/pseudotcp.cc',
37 'p2p/base/pseudotcp.h',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038 'rtc_base',
39 'sdk/android/src/jni',
40 'sdk/objc',
41 'system_wrappers',
42 'test',
Henrik Kjellander90fd7d82017-05-09 08:30:10 +020043 'tools_webrtc',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020044 'voice_engine',
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +010045]
46
jbauchc4e3ead2016-02-19 00:25:55 -080047# These filters will always be removed, even if the caller specifies a filter
48# set, as they are problematic or broken in some way.
49#
50# Justifications for each filter:
51# - build/c++11 : Rvalue ref checks are unreliable (false positives),
52# include file and feature blacklists are
53# google3-specific.
kjellandere5a87a52016-04-27 02:32:12 -070054# - whitespace/operators: Same as above (doesn't seem sufficient to eliminate
55# all move-related errors).
jbauchc4e3ead2016-02-19 00:25:55 -080056BLACKLIST_LINT_FILTERS = [
57 '-build/c++11',
kjellandere5a87a52016-04-27 02:32:12 -070058 '-whitespace/operators',
jbauchc4e3ead2016-02-19 00:25:55 -080059]
60
kjellanderfd595232015-12-04 02:44:09 -080061# List of directories of "supported" native APIs. That means changes to headers
62# will be done in a compatible way following this scheme:
63# 1. Non-breaking changes are made.
64# 2. The old APIs as marked as deprecated (with comments).
65# 3. Deprecation is announced to discuss-webrtc@googlegroups.com and
66# webrtc-users@google.com (internal list).
67# 4. (later) The deprecated APIs are removed.
kjellander53047c92015-12-02 23:56:14 -080068NATIVE_API_DIRS = (
Karl Wibergef52d8b82017-10-25 13:20:03 +020069 'api', # All subdirectories of api/ are included as well.
Mirko Bonadeia4eeeff2018-01-11 13:16:52 +010070 'media/base',
71 'media/engine',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020072 'modules/audio_device/include',
73 'pc',
kjellanderdd705472016-06-09 11:17:27 -070074)
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020075
kjellanderdd705472016-06-09 11:17:27 -070076# These directories should not be used but are maintained only to avoid breaking
77# some legacy downstream code.
78LEGACY_API_DIRS = (
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020079 'common_audio/include',
80 'modules/audio_coding/include',
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020081 'modules/audio_processing/include',
82 'modules/bitrate_controller/include',
83 'modules/congestion_controller/include',
84 'modules/include',
85 'modules/remote_bitrate_estimator/include',
86 'modules/rtp_rtcp/include',
87 'modules/rtp_rtcp/source',
88 'modules/utility/include',
89 'modules/video_coding/codecs/h264/include',
90 'modules/video_coding/codecs/i420/include',
91 'modules/video_coding/codecs/vp8/include',
92 'modules/video_coding/codecs/vp9/include',
93 'modules/video_coding/include',
94 'rtc_base',
95 'system_wrappers/include',
kjellander53047c92015-12-02 23:56:14 -080096)
Mirko Bonadei4dc4e252017-09-19 13:49:16 +020097
Karl Wibergd4f01c12017-11-10 10:55:45 +010098# NOTE: The set of directories in API_DIRS should be the same as those
99# listed in the table in native-api.md.
kjellanderdd705472016-06-09 11:17:27 -0700100API_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
kjellander53047c92015-12-02 23:56:14 -0800101
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200102# TARGET_RE matches a GN target, and extracts the target name and the contents.
103TARGET_RE = re.compile(r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {'
104 r'(?P<target_contents>.*?)'
105 r'(?P=indent)}',
106 re.MULTILINE | re.DOTALL)
107
108# SOURCES_RE matches a block of sources inside a GN target.
109SOURCES_RE = re.compile(r'sources \+?= \[(?P<sources>.*?)\]',
110 re.MULTILINE | re.DOTALL)
111
112# FILE_PATH_RE matchies a file path.
113FILE_PATH_RE = re.compile(r'"(?P<file_path>(\w|\/)+)(?P<extension>\.\w+)"')
114
kjellander53047c92015-12-02 23:56:14 -0800115
Oleh Prypin2f33a562017-10-04 20:17:54 +0200116@contextmanager
117def _AddToPath(*paths):
118 original_sys_path = sys.path
119 sys.path.extend(paths)
120 try:
121 yield
122 finally:
123 # Restore sys.path to what it was before.
124 sys.path = original_sys_path
ehmaldonado4fb97462017-01-30 05:27:22 -0800125
126
charujain9893e252017-09-14 13:33:22 +0200127def VerifyNativeApiHeadersListIsValid(input_api, output_api):
kjellander53047c92015-12-02 23:56:14 -0800128 """Ensures the list of native API header directories is up to date."""
129 non_existing_paths = []
130 native_api_full_paths = [
131 input_api.os_path.join(input_api.PresubmitLocalPath(),
kjellanderdd705472016-06-09 11:17:27 -0700132 *path.split('/')) for path in API_DIRS]
kjellander53047c92015-12-02 23:56:14 -0800133 for path in native_api_full_paths:
134 if not os.path.isdir(path):
135 non_existing_paths.append(path)
136 if non_existing_paths:
137 return [output_api.PresubmitError(
138 'Directories to native API headers have changed which has made the '
139 'list in PRESUBMIT.py outdated.\nPlease update it to the current '
140 'location of our native APIs.',
141 non_existing_paths)]
142 return []
143
kjellanderc88b5d52017-04-05 06:42:43 -0700144API_CHANGE_MSG = """
kwibergeb133022016-04-07 07:41:48 -0700145You seem to be changing native API header files. Please make sure that you:
oprypin375b9ac2017-02-13 04:13:23 -0800146 1. Make compatible changes that don't break existing clients. Usually
147 this is done by keeping the existing method signatures unchanged.
148 2. Mark the old stuff as deprecated (see RTC_DEPRECATED macro).
kwibergeb133022016-04-07 07:41:48 -0700149 3. Create a timeline and plan for when the deprecated stuff will be
150 removed. (The amount of time we give users to change their code
151 should be informed by how much work it is for them. If they just
152 need to replace one name with another or something equally
153 simple, 1-2 weeks might be good; if they need to do serious work,
154 up to 3 months may be called for.)
155 4. Update/inform existing downstream code owners to stop using the
156 deprecated stuff. (Send announcements to
157 discuss-webrtc@googlegroups.com and webrtc-users@google.com.)
158 5. Remove the deprecated stuff, once the agreed-upon amount of time
159 has passed.
160Related files:
161"""
kjellander53047c92015-12-02 23:56:14 -0800162
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
charujain9893e252017-09-14 13:33:22 +0200185def CheckNoIOStreamInHeaders(input_api, output_api):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000186 """Checks to make sure no .h files include <iostream>."""
187 files = []
188 pattern = input_api.re.compile(r'^#include\s*<iostream>',
189 input_api.re.MULTILINE)
190 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
191 if not f.LocalPath().endswith('.h'):
192 continue
193 contents = input_api.ReadFile(f)
194 if pattern.search(contents):
195 files.append(f)
196
197 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200198 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000199 'Do not #include <iostream> in header files, since it inserts static ' +
200 'initialization into every file including the header. Instead, ' +
201 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200202 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000203 return []
204
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000205
charujain9893e252017-09-14 13:33:22 +0200206def CheckNoPragmaOnce(input_api, output_api):
kjellander6aeef742017-02-20 01:13:18 -0800207 """Make sure that banned functions are not used."""
208 files = []
209 pattern = input_api.re.compile(r'^#pragma\s+once',
210 input_api.re.MULTILINE)
211 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
212 if not f.LocalPath().endswith('.h'):
213 continue
214 contents = input_api.ReadFile(f)
215 if pattern.search(contents):
216 files.append(f)
217
218 if files:
219 return [output_api.PresubmitError(
220 'Do not use #pragma once in header files.\n'
221 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
222 files)]
223 return []
224
225
charujain9893e252017-09-14 13:33:22 +0200226def CheckNoFRIEND_TEST(input_api, output_api): # pylint: disable=invalid-name
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000227 """Make sure that gtest's FRIEND_TEST() macro is not used, the
228 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
229 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
230 problems = []
231
232 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
233 for f in input_api.AffectedFiles(file_filter=file_filter):
234 for line_num, line in f.ChangedContents():
235 if 'FRIEND_TEST(' in line:
236 problems.append(' %s:%d' % (f.LocalPath(), line_num))
237
238 if not problems:
239 return []
240 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
241 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
242 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
243
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000244
charujain9893e252017-09-14 13:33:22 +0200245def IsLintBlacklisted(blacklist_paths, file_path):
oprypin2aa463f2017-03-23 03:17:02 -0700246 """ Checks if a file is blacklisted for lint check."""
247 for path in blacklist_paths:
248 if file_path == path or os.path.dirname(file_path).startswith(path):
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100249 return True
250 return False
251
252
charujain9893e252017-09-14 13:33:22 +0200253def CheckApprovedFilesLintClean(input_api, output_api,
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000254 source_file_filter=None):
oprypin2aa463f2017-03-23 03:17:02 -0700255 """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py.
charujain9893e252017-09-14 13:33:22 +0200256 This check is based on CheckChangeLintsClean in
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000257 depot_tools/presubmit_canned_checks.py but has less filters and only checks
258 added files."""
259 result = []
260
261 # Initialize cpplint.
262 import cpplint
263 # Access to a protected member _XX of a client class
264 # pylint: disable=W0212
265 cpplint._cpplint_state.ResetErrorCounts()
266
jbauchc4e3ead2016-02-19 00:25:55 -0800267 lint_filters = cpplint._Filters()
268 lint_filters.extend(BLACKLIST_LINT_FILTERS)
269 cpplint._SetFilters(','.join(lint_filters))
270
oprypin2aa463f2017-03-23 03:17:02 -0700271 # Create a platform independent blacklist for cpplint.
272 blacklist_paths = [input_api.os_path.join(*path.split('/'))
273 for path in CPPLINT_BLACKLIST]
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100274
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000275 # Use the strictest verbosity level for cpplint.py (level 1) which is the
oprypin2aa463f2017-03-23 03:17:02 -0700276 # default when running cpplint.py from command line. To make it possible to
277 # work with not-yet-converted code, we're only applying it to new (or
278 # moved/renamed) files and files not listed in CPPLINT_BLACKLIST.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000279 verbosity_level = 1
280 files = []
281 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200282 # Note that moved/renamed files also count as added.
charujain9893e252017-09-14 13:33:22 +0200283 if f.Action() == 'A' or not IsLintBlacklisted(blacklist_paths,
oprypin2aa463f2017-03-23 03:17:02 -0700284 f.LocalPath()):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000285 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000286
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000287 for file_name in files:
288 cpplint.ProcessFile(file_name, verbosity_level)
289
290 if cpplint._cpplint_state.error_count > 0:
291 if input_api.is_committing:
oprypin8e58d652017-03-21 07:52:41 -0700292 res_type = output_api.PresubmitError
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000293 else:
294 res_type = output_api.PresubmitPromptWarning
295 result = [res_type('Changelist failed cpplint.py check.')]
296
297 return result
298
charujain9893e252017-09-14 13:33:22 +0200299def CheckNoSourcesAbove(input_api, gn_files, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700300 # Disallow referencing source files with paths above the GN file location.
301 source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
302 re.MULTILINE | re.DOTALL)
303 file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
304 violating_gn_files = set()
305 violating_source_entries = []
306 for gn_file in gn_files:
307 contents = input_api.ReadFile(gn_file)
308 for source_block_match in source_pattern.finditer(contents):
309 # Find all source list entries starting with ../ in the source block
310 # (exclude overrides entries).
311 for file_list_match in file_pattern.finditer(source_block_match.group(1)):
312 source_file = file_list_match.group(1)
313 if 'overrides/' not in source_file:
314 violating_source_entries.append(source_file)
315 violating_gn_files.add(gn_file)
316 if violating_gn_files:
317 return [output_api.PresubmitError(
318 'Referencing source files above the directory of the GN file is not '
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100319 'allowed. Please introduce new GN targets in the proper location '
320 'instead.\n'
ehmaldonado5b1ba082016-09-02 05:51:08 -0700321 'Invalid source entries:\n'
322 '%s\n'
323 'Violating GN files:' % '\n'.join(violating_source_entries),
324 items=violating_gn_files)]
325 return []
326
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200327def CheckNoMixingSources(input_api, gn_files, output_api):
328 """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target.
329
330 See bugs.webrtc.org/7743 for more context.
331 """
332 def _MoreThanOneSourceUsed(*sources_lists):
333 sources_used = 0
334 for source_list in sources_lists:
335 if len(source_list):
336 sources_used += 1
337 return sources_used > 1
338
339 errors = defaultdict(lambda: [])
kjellander7439f972016-12-05 22:47:46 -0800340 for gn_file in gn_files:
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200341 gn_file_content = input_api.ReadFile(gn_file)
342 for target_match in TARGET_RE.finditer(gn_file_content):
343 # list_of_sources is a list of tuples of the form
344 # (c_files, cc_files, objc_files) that keeps track of all the sources
345 # defined in a target. A GN target can have more that on definition of
346 # sources (since it supports if/else statements).
347 # E.g.:
348 # rtc_static_library("foo") {
349 # if (is_win) {
350 # sources = [ "foo.cc" ]
351 # } else {
352 # sources = [ "foo.mm" ]
353 # }
354 # }
355 # This is allowed and the presubmit check should support this case.
356 list_of_sources = []
kjellander7439f972016-12-05 22:47:46 -0800357 c_files = []
358 cc_files = []
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200359 objc_files = []
360 target_name = target_match.group('target_name')
361 target_contents = target_match.group('target_contents')
362 for sources_match in SOURCES_RE.finditer(target_contents):
363 if '+=' not in sources_match.group(0):
364 if c_files or cc_files or objc_files:
365 list_of_sources.append((c_files, cc_files, objc_files))
366 c_files = []
367 cc_files = []
368 objc_files = []
369 for file_match in FILE_PATH_RE.finditer(sources_match.group(1)):
370 file_path = file_match.group('file_path')
371 extension = file_match.group('extension')
372 if extension == '.c':
373 c_files.append(file_path + extension)
374 if extension == '.cc':
375 cc_files.append(file_path + extension)
376 if extension in ['.m', '.mm']:
377 objc_files.append(file_path + extension)
378 list_of_sources.append((c_files, cc_files, objc_files))
379 for c_files_list, cc_files_list, objc_files_list in list_of_sources:
380 if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list):
381 all_sources = sorted(c_files_list + cc_files_list + objc_files_list)
382 errors[gn_file.LocalPath()].append((target_name, all_sources))
383 if errors:
kjellander7439f972016-12-05 22:47:46 -0800384 return [output_api.PresubmitError(
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200385 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n'
386 'Please create a separate target for each collection of sources.\n'
kjellander7439f972016-12-05 22:47:46 -0800387 'Mixed sources: \n'
388 '%s\n'
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200389 'Violating GN files:\n%s\n' % (json.dumps(errors, indent=2),
390 '\n'.join(errors.keys())))]
kjellander7439f972016-12-05 22:47:46 -0800391 return []
392
charujain9893e252017-09-14 13:33:22 +0200393def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
ehmaldonado4fb97462017-01-30 05:27:22 -0800394 cwd = input_api.PresubmitLocalPath()
Oleh Prypin2f33a562017-10-04 20:17:54 +0200395 with _AddToPath(input_api.os_path.join(
396 cwd, 'tools_webrtc', 'presubmit_checks_lib')):
397 from check_package_boundaries import CheckPackageBoundaries
398 build_files = [os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files]
399 errors = CheckPackageBoundaries(cwd, build_files)[:5]
400 if errors:
ehmaldonado4fb97462017-01-30 05:27:22 -0800401 return [output_api.PresubmitError(
Oleh Prypin2f33a562017-10-04 20:17:54 +0200402 'There are package boundary violations in the following GN files:',
403 long_text='\n\n'.join(str(err) for err in errors))]
ehmaldonado4fb97462017-01-30 05:27:22 -0800404 return []
405
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100406
407def _ReportErrorFileAndLineNumber(filename, line_num):
408 """Default error formatter for _FindNewViolationsOfRule."""
409 return '%s (line %s)' % (filename, line_num)
410
411
412def CheckNoStreamUsageIsAdded(input_api, output_api,
413 error_formatter=_ReportErrorFileAndLineNumber):
414 """Make sure that no more dependencies on stringstream are added."""
415 error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
416 'deprecated.\n'
417 'This includes the following types:\n'
418 'std::istringstream, std::ostringstream, std::wistringstream, '
419 'std::wostringstream,\n'
420 'std::wstringstream, std::ostream, std::wostream, std::istream,'
421 'std::wistream,\n'
422 'std::iostream, std::wiostream.\n'
423 'If you are not adding this code (e.g. you are just moving '
424 'existing code),\n'
425 'you can add a comment on the line that causes the problem:\n\n'
426 '#include <sstream> // no-presubmit-check TODO(webrtc:8982)\n'
427 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n'
428 '\n'
429 'If you are adding new code, please consider using '
430 'rtc::SimpleStringBuilder (rtc_base/string/string_builder.h).\n'
431 'Affected files:\n')
432 errors = [] # 2-element tuples with (file, line number)
433 include_re = input_api.re.compile(r'#include <(i|o|s)stream>')
434 usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream')
435 no_presubmit_re = input_api.re.compile(
436 r' // no-presubmit-check TODO\(webrtc:8982\)')
437 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
438 if f.LocalPath() == 'PRESUBMIT.py':
439 continue
440 for line_num, line in f.ChangedContents():
441 if ((include_re.search(line) or usage_re.search(line))
442 and not no_presubmit_re.search(line)):
443 errors.append(error_formatter(f.LocalPath(), line_num))
444 if errors:
445 return [output_api.PresubmitError(error_msg, errors)]
446 return []
447
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100448def CheckPublicDepsIsNotUsed(gn_files, output_api):
449 result = []
450 error_msg = ('public_deps is not allowed in WebRTC BUILD.gn files because '
451 'it doesn\'t map well to downstream build systems.\n'
452 'Used in: %s (line %d).')
453 for affected_file in gn_files:
454 for (line_number, affected_line) in affected_file.ChangedContents():
455 if 'public_deps' in affected_line:
456 result.append(
457 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
458 line_number)))
459 return result
460
Patrik Höglund6f491062018-01-11 12:04:23 +0100461def CheckCheckIncludesIsNotUsed(gn_files, output_api):
462 result = []
463 error_msg = ('check_includes overrides are not allowed since it can cause '
464 'incorrect dependencies to form. It effectively means that your '
465 'module can include any .h file without depending on its '
466 'corresponding target. There are some exceptional cases when '
467 'this is allowed: if so, get approval from a .gn owner in the'
468 'root OWNERS file.\n'
469 'Used in: %s (line %d).')
470 for affected_file in gn_files:
471 for (line_number, affected_line) in affected_file.ChangedContents():
472 if 'check_includes' in affected_line:
473 result.append(
474 output_api.PresubmitError(error_msg % (affected_file.LocalPath(),
475 line_number)))
476 return result
477
charujain9893e252017-09-14 13:33:22 +0200478def CheckGnChanges(input_api, output_api):
ehmaldonado5b1ba082016-09-02 05:51:08 -0700479 source_file_filter = lambda x: input_api.FilterSourceFile(
Oleh Prypinafe01652017-10-04 15:56:08 +0200480 x, white_list=(r'.+\.(gn|gni)$',),
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100481 black_list=(r'.*/presubmit_checks_lib/testdata/.*',))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700482
483 gn_files = []
484 for f in input_api.AffectedSourceFiles(source_file_filter):
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200485 gn_files.append(f)
ehmaldonado5b1ba082016-09-02 05:51:08 -0700486
487 result = []
488 if gn_files:
charujain9893e252017-09-14 13:33:22 +0200489 result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api))
Mirko Bonadei4dc4e252017-09-19 13:49:16 +0200490 result.extend(CheckNoMixingSources(input_api, gn_files, output_api))
491 result.extend(CheckNoPackageBoundaryViolations(input_api, gn_files,
492 output_api))
Mirko Bonadei5c1ad592017-12-12 11:52:27 +0100493 result.extend(CheckPublicDepsIsNotUsed(gn_files, output_api))
Patrik Höglund6f491062018-01-11 12:04:23 +0100494 result.extend(CheckCheckIncludesIsNotUsed(gn_files, output_api))
ehmaldonado5b1ba082016-09-02 05:51:08 -0700495 return result
496
Oleh Prypin920b6532017-10-05 11:28:51 +0200497def CheckGnGen(input_api, output_api):
498 """Runs `gn gen --check` with default args to detect mismatches between
499 #includes and dependencies in the BUILD.gn files, as well as general build
500 errors.
501 """
502 with _AddToPath(input_api.os_path.join(
503 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
504 from gn_check import RunGnCheck
505 errors = RunGnCheck(input_api.PresubmitLocalPath())[:5]
506 if errors:
507 return [output_api.PresubmitPromptWarning(
508 'Some #includes do not match the build dependency graph. Please run:\n'
509 ' gn gen --check <out_dir>',
510 long_text='\n\n'.join(errors))]
511 return []
512
charujain9893e252017-09-14 13:33:22 +0200513def CheckUnwantedDependencies(input_api, output_api):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000514 """Runs checkdeps on #include statements added in this
515 change. Breaking - rules is an error, breaking ! rules is a
516 warning.
517 """
518 # Copied from Chromium's src/PRESUBMIT.py.
519
520 # We need to wait until we have an input_api object and use this
521 # roundabout construct to import checkdeps because this file is
522 # eval-ed and thus doesn't have __file__.
Oleh Prypin2f33a562017-10-04 20:17:54 +0200523 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
524 'buildtools', 'checkdeps')
525 if not os.path.exists(checkdeps_path):
526 return [output_api.PresubmitError(
527 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
528 'download all the DEPS entries?' % checkdeps_path)]
529 with _AddToPath(checkdeps_path):
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000530 import checkdeps
531 from cpp_checker import CppChecker
532 from rules import Rule
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000533
534 added_includes = []
535 for f in input_api.AffectedFiles():
536 if not CppChecker.IsCppFile(f.LocalPath()):
537 continue
538
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200539 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000540 added_includes.append([f.LocalPath(), changed_lines])
541
542 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
543
544 error_descriptions = []
545 warning_descriptions = []
546 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
547 added_includes):
548 description_with_path = '%s\n %s' % (path, rule_description)
549 if rule_type == Rule.DISALLOW:
550 error_descriptions.append(description_with_path)
551 else:
552 warning_descriptions.append(description_with_path)
553
554 results = []
555 if error_descriptions:
556 results.append(output_api.PresubmitError(
kjellandera7066a32017-03-23 03:47:05 -0700557 'You added one or more #includes that violate checkdeps rules.\n'
558 'Check that the DEPS files in these locations contain valid rules.\n'
559 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
560 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000561 error_descriptions))
562 if warning_descriptions:
563 results.append(output_api.PresubmitPromptOrNotify(
564 'You added one or more #includes of files that are temporarily\n'
565 'allowed but being removed. Can you avoid introducing the\n'
kjellandera7066a32017-03-23 03:47:05 -0700566 '#include? See relevant DEPS file(s) for details and contacts.\n'
567 'See https://cs.chromium.org/chromium/src/buildtools/checkdeps/ for '
568 'more details about checkdeps.',
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000569 warning_descriptions))
570 return results
571
charujain9893e252017-09-14 13:33:22 +0200572def CheckCommitMessageBugEntry(input_api, output_api):
573 """Check that bug entries are well-formed in commit message."""
574 bogus_bug_msg = (
Mirko Bonadei61880182017-10-12 15:12:35 +0200575 'Bogus Bug entry: %s. Please specify the issue tracker prefix and the '
charujain9893e252017-09-14 13:33:22 +0200576 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.')
577 results = []
Mirko Bonadei61880182017-10-12 15:12:35 +0200578 for bug in input_api.change.BugsFromDescription():
charujain9893e252017-09-14 13:33:22 +0200579 bug = bug.strip()
580 if bug.lower() == 'none':
581 continue
charujain81a58c72017-09-25 13:25:45 +0200582 if 'b/' not in bug and ':' not in bug:
charujain9893e252017-09-14 13:33:22 +0200583 try:
584 if int(bug) > 100000:
585 # Rough indicator for current chromium bugs.
586 prefix_guess = 'chromium'
587 else:
588 prefix_guess = 'webrtc'
Mirko Bonadei61880182017-10-12 15:12:35 +0200589 results.append('Bug entry requires issue tracker prefix, e.g. %s:%s' %
charujain9893e252017-09-14 13:33:22 +0200590 (prefix_guess, bug))
591 except ValueError:
592 results.append(bogus_bug_msg % bug)
charujain81a58c72017-09-25 13:25:45 +0200593 elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)):
charujain9893e252017-09-14 13:33:22 +0200594 results.append(bogus_bug_msg % bug)
595 return [output_api.PresubmitError(r) for r in results]
596
597def CheckChangeHasBugField(input_api, output_api):
Mirko Bonadei61880182017-10-12 15:12:35 +0200598 """Requires that the changelist is associated with a bug.
kjellanderd1e26a92016-09-19 08:11:16 -0700599
600 This check is stricter than the one in depot_tools/presubmit_canned_checks.py
Mirko Bonadei61880182017-10-12 15:12:35 +0200601 since it fails the presubmit if the bug field is missing or doesn't contain
kjellanderd1e26a92016-09-19 08:11:16 -0700602 a bug reference.
Mirko Bonadei61880182017-10-12 15:12:35 +0200603
604 This supports both 'BUG=' and 'Bug:' since we are in the process of migrating
605 to Gerrit and it encourages the usage of 'Bug:'.
kjellanderd1e26a92016-09-19 08:11:16 -0700606 """
Mirko Bonadei61880182017-10-12 15:12:35 +0200607 if input_api.change.BugsFromDescription():
kjellanderd1e26a92016-09-19 08:11:16 -0700608 return []
609 else:
610 return [output_api.PresubmitError(
Mirko Bonadei61880182017-10-12 15:12:35 +0200611 'The "Bug: [bug number]" footer is mandatory. Please create a bug and '
kjellanderd1e26a92016-09-19 08:11:16 -0700612 'reference it using either of:\n'
Mirko Bonadei61880182017-10-12 15:12:35 +0200613 ' * https://bugs.webrtc.org - reference it using Bug: webrtc:XXXX\n'
614 ' * https://crbug.com - reference it using Bug: chromium:XXXXXX')]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000615
charujain9893e252017-09-14 13:33:22 +0200616def CheckJSONParseErrors(input_api, output_api):
kjellander569cf942016-02-11 05:02:59 -0800617 """Check that JSON files do not contain syntax errors."""
618
619 def FilterFile(affected_file):
620 return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
621
622 def GetJSONParseError(input_api, filename):
623 try:
624 contents = input_api.ReadFile(filename)
625 input_api.json.loads(contents)
626 except ValueError as e:
627 return e
628 return None
629
630 results = []
631 for affected_file in input_api.AffectedFiles(
632 file_filter=FilterFile, include_deletes=False):
633 parse_error = GetJSONParseError(input_api,
634 affected_file.AbsoluteLocalPath())
635 if parse_error:
636 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
637 (affected_file.LocalPath(), parse_error)))
638 return results
639
640
charujain9893e252017-09-14 13:33:22 +0200641def RunPythonTests(input_api, output_api):
kjellanderc88b5d52017-04-05 06:42:43 -0700642 def Join(*args):
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200643 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
644
645 test_directories = [
Edward Lemur6d01f6d2017-09-14 17:02:01 +0200646 input_api.PresubmitLocalPath(),
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200647 Join('rtc_tools', 'py_event_log_analyzer'),
648 Join('rtc_tools'),
649 Join('audio', 'test', 'unittests'),
ehmaldonado4fb97462017-01-30 05:27:22 -0800650 ] + [
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200651 root for root, _, files in os.walk(Join('tools_webrtc'))
ehmaldonado4fb97462017-01-30 05:27:22 -0800652 if any(f.endswith('_test.py') for f in files)
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200653 ]
654
655 tests = []
656 for directory in test_directories:
657 tests.extend(
658 input_api.canned_checks.GetUnitTestsInDirectory(
659 input_api,
660 output_api,
661 directory,
662 whitelist=[r'.+_test\.py$']))
663 return input_api.RunTests(tests, parallel=True)
664
665
charujain9893e252017-09-14 13:33:22 +0200666def CheckUsageOfGoogleProtobufNamespace(input_api, output_api):
mbonadei38415b22017-04-07 05:38:01 -0700667 """Checks that the namespace google::protobuf has not been used."""
668 files = []
669 pattern = input_api.re.compile(r'google::protobuf')
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200670 proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h')
mbonadei38415b22017-04-07 05:38:01 -0700671 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
672 if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
673 continue
674 contents = input_api.ReadFile(f)
675 if pattern.search(contents):
676 files.append(f)
677
678 if files:
679 return [output_api.PresubmitError(
680 'Please avoid to use namespace `google::protobuf` directly.\n'
681 'Add a using directive in `%s` and include that header instead.'
682 % proto_utils_path, files)]
683 return []
684
685
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200686def _LicenseHeader(input_api):
687 """Returns the license header regexp."""
688 # Accept any year number from 2003 to the current year
689 current_year = int(input_api.time.strftime('%Y'))
690 allowed_years = (str(s) for s in reversed(xrange(2003, current_year + 1)))
691 years_re = '(' + '|'.join(allowed_years) + ')'
692 license_header = (
693 r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
694 r'All [Rr]ights [Rr]eserved\.\n'
695 r'.*?\n'
696 r'.*? Use of this source code is governed by a BSD-style license\n'
697 r'.*? that can be found in the LICENSE file in the root of the source\n'
698 r'.*? tree\. An additional intellectual property rights grant can be '
699 r'found\n'
700 r'.*? in the file PATENTS\. All contributing project authors may\n'
701 r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
702 ) % {
703 'year': years_re,
704 }
705 return license_header
706
707
charujain9893e252017-09-14 13:33:22 +0200708def CommonChecks(input_api, output_api):
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000709 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000710 results = []
tkchin42f580e2015-11-26 23:18:23 -0800711 # Filter out files that are in objc or ios dirs from being cpplint-ed since
712 # they do not follow C++ lint rules.
713 black_list = input_api.DEFAULT_BLACK_LIST + (
714 r".*\bobjc[\\\/].*",
Kári Tristan Helgason3fa35172016-09-09 08:55:05 +0000715 r".*objc\.[hcm]+$",
tkchin42f580e2015-11-26 23:18:23 -0800716 )
717 source_file_filter = lambda x: input_api.FilterSourceFile(x, None, black_list)
charujain9893e252017-09-14 13:33:22 +0200718 results.extend(CheckApprovedFilesLintClean(
tkchin42f580e2015-11-26 23:18:23 -0800719 input_api, output_api, source_file_filter))
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200720 results.extend(input_api.canned_checks.CheckLicense(
721 input_api, output_api, _LicenseHeader(input_api)))
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000722 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100723 black_list=(r'^base[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200724 r'^build[\\\/].*\.py$',
725 r'^buildtools[\\\/].*\.py$',
kjellander38c65c82017-04-12 22:43:38 -0700726 r'^infra[\\\/].*\.py$',
Henrik Kjellander0779e8f2016-12-22 12:01:17 +0100727 r'^ios[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200728 r'^out.*[\\\/].*\.py$',
729 r'^testing[\\\/].*\.py$',
730 r'^third_party[\\\/].*\.py$',
kjellander@webrtc.org177567c2016-12-22 10:40:28 +0100731 r'^tools[\\\/].*\.py$',
kjellanderafd54942016-12-17 12:21:39 -0800732 # TODO(phoglund): should arguably be checked.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +0200733 r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
734 r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200735 r'^xcodebuild.*[\\\/].*\.py$',),
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200736 pylintrc='pylintrc'))
kjellander569cf942016-02-11 05:02:59 -0800737
nisse3d21e232016-09-02 03:07:06 -0700738 # TODO(nisse): talk/ is no more, so make below checks simpler?
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200739 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
740 # we need to have different license checks in talk/ and webrtc/ directories.
741 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200742
tkchin3cd9a302016-06-08 12:40:28 -0700743 # .m and .mm files are ObjC files. For simplicity we will consider .h files in
744 # ObjC subdirectories ObjC headers.
745 objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
Henrik Kjellanderb4af3d62016-11-16 20:11:29 +0100746 # Skip long-lines check for DEPS and GN files.
747 build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
tkchin3cd9a302016-06-08 12:40:28 -0700748 eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
749 black_list=build_file_filter_list + objc_filter_list)
750 hundred_char_sources = lambda x: input_api.FilterSourceFile(x,
751 white_list=objc_filter_list)
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000752 results.extend(input_api.canned_checks.CheckLongLines(
tkchin3cd9a302016-06-08 12:40:28 -0700753 input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
754 results.extend(input_api.canned_checks.CheckLongLines(
755 input_api, output_api, maxlen=100,
756 source_file_filter=hundred_char_sources))
757
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000758 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
759 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000760 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
761 input_api, output_api))
kjellandere5dc62a2016-12-14 00:16:21 -0800762 results.extend(input_api.canned_checks.CheckAuthorizedAuthor(
763 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000764 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
765 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200766 results.extend(CheckNativeApiHeaderChanges(input_api, output_api))
767 results.extend(CheckNoIOStreamInHeaders(input_api, output_api))
768 results.extend(CheckNoPragmaOnce(input_api, output_api))
769 results.extend(CheckNoFRIEND_TEST(input_api, output_api))
770 results.extend(CheckGnChanges(input_api, output_api))
771 results.extend(CheckUnwantedDependencies(input_api, output_api))
772 results.extend(CheckJSONParseErrors(input_api, output_api))
773 results.extend(RunPythonTests(input_api, output_api))
774 results.extend(CheckUsageOfGoogleProtobufNamespace(input_api, output_api))
Mirko Bonadei866d3372017-09-15 12:35:26 +0200775 results.extend(CheckOrphanHeaders(input_api, output_api))
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200776 results.extend(CheckNewlineAtTheEndOfProtoFiles(input_api, output_api))
Mirko Bonadeia51bbd82018-03-08 16:15:45 +0100777 results.extend(CheckNoStreamUsageIsAdded(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000778 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000779
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000780
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000781def CheckChangeOnUpload(input_api, output_api):
782 results = []
charujain9893e252017-09-14 13:33:22 +0200783 results.extend(CommonChecks(input_api, output_api))
Oleh Prypin920b6532017-10-05 11:28:51 +0200784 results.extend(CheckGnGen(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200785 results.extend(
786 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000787 return results
788
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000789
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000790def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000791 results = []
charujain9893e252017-09-14 13:33:22 +0200792 results.extend(CommonChecks(input_api, output_api))
793 results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000794 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000795 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
796 input_api, output_api))
797 results.extend(input_api.canned_checks.CheckChangeHasDescription(
798 input_api, output_api))
charujain9893e252017-09-14 13:33:22 +0200799 results.extend(CheckChangeHasBugField(input_api, output_api))
800 results.extend(CheckCommitMessageBugEntry(input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000801 results.extend(input_api.canned_checks.CheckTreeIsOpen(
802 input_api, output_api,
803 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000804 return results
mbonadei74973ed2017-05-09 07:58:05 -0700805
806
charujain9893e252017-09-14 13:33:22 +0200807def CheckOrphanHeaders(input_api, output_api):
mbonadei74973ed2017-05-09 07:58:05 -0700808 # We need to wait until we have an input_api object and use this
809 # roundabout construct to import prebubmit_checks_lib because this file is
810 # eval-ed and thus doesn't have __file__.
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100811 error_msg = """{} should be listed in {}."""
mbonadei74973ed2017-05-09 07:58:05 -0700812 results = []
Patrik Höglund7e60de22018-01-09 14:22:00 +0100813 orphan_blacklist = [
814 os.path.join('tools_webrtc', 'ios', 'SDK'),
815 ]
Oleh Prypin2f33a562017-10-04 20:17:54 +0200816 with _AddToPath(input_api.os_path.join(
817 input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
mbonadei74973ed2017-05-09 07:58:05 -0700818 from check_orphan_headers import GetBuildGnPathFromFilePath
819 from check_orphan_headers import IsHeaderInBuildGn
mbonadei74973ed2017-05-09 07:58:05 -0700820
Patrik Höglund7e60de22018-01-09 14:22:00 +0100821 source_file_filter = lambda x: input_api.FilterSourceFile(
822 x, black_list=orphan_blacklist)
823 for f in input_api.AffectedSourceFiles(source_file_filter):
824 if f.LocalPath().endswith('.h'):
mbonadei74973ed2017-05-09 07:58:05 -0700825 file_path = os.path.abspath(f.LocalPath())
826 root_dir = os.getcwd()
827 gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
828 root_dir)
829 in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
830 if not in_build_gn:
831 results.append(output_api.PresubmitError(error_msg.format(
Patrik Höglund2f3f7222017-12-19 11:08:56 +0100832 f.LocalPath(), os.path.relpath(gn_file_path))))
mbonadei74973ed2017-05-09 07:58:05 -0700833 return results
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200834
835
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200836def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200837 """Checks that all .proto files are terminated with a newline."""
838 error_msg = 'File {} must end with exactly one newline.'
839 results = []
840 source_file_filter = lambda x: input_api.FilterSourceFile(
841 x, white_list=(r'.+\.proto$',))
842 for f in input_api.AffectedSourceFiles(source_file_filter):
843 file_path = f.LocalPath()
844 with open(file_path) as f:
845 lines = f.readlines()
Mirko Bonadeia730c1c2017-09-18 11:33:13 +0200846 if len(lines) > 0 and not lines[-1].endswith('\n'):
Mirko Bonadei960fd5b2017-06-29 14:59:36 +0200847 results.append(output_api.PresubmitError(error_msg.format(file_path)))
848 return results