blob: 381119e15747af0eef94bd2cd8a3209031398f5e [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
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +00009import os
kjellander@webrtc.org85759802013-10-22 16:47:40 +000010import re
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +000011import sys
kjellander@webrtc.org85759802013-10-22 16:47:40 +000012
13
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000014def _CheckNoIOStreamInHeaders(input_api, output_api):
15 """Checks to make sure no .h files include <iostream>."""
16 files = []
17 pattern = input_api.re.compile(r'^#include\s*<iostream>',
18 input_api.re.MULTILINE)
19 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
20 if not f.LocalPath().endswith('.h'):
21 continue
22 contents = input_api.ReadFile(f)
23 if pattern.search(contents):
24 files.append(f)
25
26 if len(files):
27 return [ output_api.PresubmitError(
28 'Do not #include <iostream> in header files, since it inserts static ' +
29 'initialization into every file including the header. Instead, ' +
30 '#include <ostream>. See http://crbug.com/94794',
31 files) ]
32 return []
33
kjellander@webrtc.orge4158642014-08-06 09:11:18 +000034
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000035def _CheckNoFRIEND_TEST(input_api, output_api):
36 """Make sure that gtest's FRIEND_TEST() macro is not used, the
37 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
38 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
39 problems = []
40
41 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
42 for f in input_api.AffectedFiles(file_filter=file_filter):
43 for line_num, line in f.ChangedContents():
44 if 'FRIEND_TEST(' in line:
45 problems.append(' %s:%d' % (f.LocalPath(), line_num))
46
47 if not problems:
48 return []
49 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
50 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
51 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
52
kjellander@webrtc.orge4158642014-08-06 09:11:18 +000053
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000054def _CheckApprovedFilesLintClean(input_api, output_api,
55 source_file_filter=None):
56 """Checks that all new or whitelisted .cc and .h files pass cpplint.py.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000057 This check is based on _CheckChangeLintsClean in
58 depot_tools/presubmit_canned_checks.py but has less filters and only checks
59 added files."""
60 result = []
61
62 # Initialize cpplint.
63 import cpplint
64 # Access to a protected member _XX of a client class
65 # pylint: disable=W0212
66 cpplint._cpplint_state.ResetErrorCounts()
67
68 # Justifications for each filter:
69 #
70 # - build/header_guard : WebRTC coding style says they should be prefixed
71 # with WEBRTC_, which is not possible to configure in
72 # cpplint.py.
73 cpplint._SetFilters('-build/header_guard')
74
75 # Use the strictest verbosity level for cpplint.py (level 1) which is the
76 # default when running cpplint.py from command line.
77 # To make it possible to work with not-yet-converted code, we're only applying
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000078 # it to new (or moved/renamed) files and files listed in LINT_FOLDERS.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000079 verbosity_level = 1
80 files = []
81 for f in input_api.AffectedSourceFiles(source_file_filter):
82 # Note that moved/renamed files also count as added for svn.
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +000083 if (f.Action() == 'A'):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000084 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000085
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000086 for file_name in files:
87 cpplint.ProcessFile(file_name, verbosity_level)
88
89 if cpplint._cpplint_state.error_count > 0:
90 if input_api.is_committing:
91 # TODO(kjellander): Change back to PresubmitError below when we're
92 # confident with the lint settings.
93 res_type = output_api.PresubmitPromptWarning
94 else:
95 res_type = output_api.PresubmitPromptWarning
96 result = [res_type('Changelist failed cpplint.py check.')]
97
98 return result
99
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000100def _CheckNoRtcBaseDeps(input_api, gyp_files, output_api):
101 pattern = input_api.re.compile(r"base.gyp:rtc_base\s*'")
102 violating_files = []
103 for f in gyp_files:
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000104 gyp_exceptions = (
105 'base_tests.gyp',
106 'desktop_capture.gypi',
107 'libjingle.gyp',
henrike@webrtc.org28af6412014-11-04 15:11:46 +0000108 'libjingle_tests.gyp',
kjellander@webrtc.orge7237282015-02-26 11:12:17 +0000109 'p2p.gyp',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000110 'sound.gyp',
111 'webrtc_test_common.gyp',
112 'webrtc_tests.gypi',
113 )
114 if f.LocalPath().endswith(gyp_exceptions):
115 continue
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000116 contents = input_api.ReadFile(f)
117 if pattern.search(contents):
118 violating_files.append(f)
119 if violating_files:
120 return [output_api.PresubmitError(
121 'Depending on rtc_base is not allowed. Change your dependency to '
122 'rtc_base_approved and possibly sanitize and move the desired source '
123 'file(s) to rtc_base_approved.\nChanged GYP files:',
124 items=violating_files)]
125 return []
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000126
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000127def _CheckNoSourcesAboveGyp(input_api, gyp_files, output_api):
128 # Disallow referencing source files with paths above the GYP file location.
129 source_pattern = input_api.re.compile(r'sources.*?\[(.*?)\]',
130 re.MULTILINE | re.DOTALL)
kjellander@webrtc.orga33f05e2015-01-29 14:29:45 +0000131 file_pattern = input_api.re.compile(r"'((\.\./.*?)|(<\(webrtc_root\).*?))'")
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000132 violating_gyp_files = set()
133 violating_source_entries = []
134 for gyp_file in gyp_files:
135 contents = input_api.ReadFile(gyp_file)
136 for source_block_match in source_pattern.finditer(contents):
137 # Find all source list entries starting with ../ in the source block.
138 for file_list_match in file_pattern.finditer(source_block_match.group(0)):
139 violating_source_entries.append(file_list_match.group(0))
140 violating_gyp_files.add(gyp_file)
141 if violating_gyp_files:
142 return [output_api.PresubmitError(
143 'Referencing source files above the directory of the GYP file is not '
144 'allowed. Please introduce new GYP targets and/or GYP files in the '
145 'proper location instead.\n'
146 'Invalid source entries:\n'
147 '%s\n'
148 'Violating GYP files:' % '\n'.join(violating_source_entries),
149 items=violating_gyp_files)]
150 return []
151
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000152def _CheckGypChanges(input_api, output_api):
153 source_file_filter = lambda x: input_api.FilterSourceFile(
154 x, white_list=(r'.+\.(gyp|gypi)$',))
155
156 gyp_files = []
157 for f in input_api.AffectedSourceFiles(source_file_filter):
kjellander@webrtc.org3398a4a2014-11-24 10:05:37 +0000158 if f.LocalPath().startswith('webrtc'):
159 gyp_files.append(f)
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000160
161 result = []
162 if gyp_files:
163 result.append(output_api.PresubmitNotifyResult(
164 'As you\'re changing GYP files: please make sure corresponding '
165 'BUILD.gn files are also updated.\nChanged GYP files:',
166 items=gyp_files))
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000167 result.extend(_CheckNoRtcBaseDeps(input_api, gyp_files, output_api))
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000168 result.extend(_CheckNoSourcesAboveGyp(input_api, gyp_files, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000169 return result
170
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000171def _CheckUnwantedDependencies(input_api, output_api):
172 """Runs checkdeps on #include statements added in this
173 change. Breaking - rules is an error, breaking ! rules is a
174 warning.
175 """
176 # Copied from Chromium's src/PRESUBMIT.py.
177
178 # We need to wait until we have an input_api object and use this
179 # roundabout construct to import checkdeps because this file is
180 # eval-ed and thus doesn't have __file__.
181 original_sys_path = sys.path
182 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000183 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
184 'buildtools', 'checkdeps')
185 if not os.path.exists(checkdeps_path):
186 return [output_api.PresubmitError(
187 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
188 'download Chromium and setup the symlinks?' % checkdeps_path)]
189 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000190 import checkdeps
191 from cpp_checker import CppChecker
192 from rules import Rule
193 finally:
194 # Restore sys.path to what it was before.
195 sys.path = original_sys_path
196
197 added_includes = []
198 for f in input_api.AffectedFiles():
199 if not CppChecker.IsCppFile(f.LocalPath()):
200 continue
201
202 changed_lines = [line for _line_num, line in f.ChangedContents()]
203 added_includes.append([f.LocalPath(), changed_lines])
204
205 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
206
207 error_descriptions = []
208 warning_descriptions = []
209 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
210 added_includes):
211 description_with_path = '%s\n %s' % (path, rule_description)
212 if rule_type == Rule.DISALLOW:
213 error_descriptions.append(description_with_path)
214 else:
215 warning_descriptions.append(description_with_path)
216
217 results = []
218 if error_descriptions:
219 results.append(output_api.PresubmitError(
220 'You added one or more #includes that violate checkdeps rules.',
221 error_descriptions))
222 if warning_descriptions:
223 results.append(output_api.PresubmitPromptOrNotify(
224 'You added one or more #includes of files that are temporarily\n'
225 'allowed but being removed. Can you avoid introducing the\n'
226 '#include? See relevant DEPS file(s) for details and contacts.',
227 warning_descriptions))
228 return results
229
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000230
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000231def _CommonChecks(input_api, output_api):
232 """Checks common to both upload and commit."""
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000233 # TODO(kjellander): Use presubmit_canned_checks.PanProjectChecks too.
niklase@google.comda159d62011-05-30 11:51:34 +0000234 results = []
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000235 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
236 black_list=(r'^.*gviz_api\.py$',
237 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000238 # Embedded shell-script fakes out pylint.
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000239 r'^build/.*\.py$',
240 r'^buildtools/.*\.py$',
kjellander@webrtc.org89256622014-08-20 12:10:11 +0000241 r'^chromium/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000242 r'^out.*/.*\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000243 r'^talk/site_scons/site_tools/talk_linux.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000244 r'^testing/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000245 r'^third_party/.*\.py$',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000246 r'^tools/clang/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000247 r'^tools/gn/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000248 r'^tools/gyp/.*\.py$',
249 r'^tools/perf_expectations/.*\.py$',
phoglund@webrtc.org6d07ad92013-05-14 09:42:39 +0000250 r'^tools/protoc_wrapper/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000251 r'^tools/python/.*\.py$',
252 r'^tools/python_charts/data/.*\.py$',
kjellander@webrtc.org33654222013-08-22 07:57:00 +0000253 r'^tools/refactoring/.*\.py$',
kjellander@webrtc.orgf9bdbe32013-12-11 13:37:12 +0000254 r'^tools/swarming_client/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000255 # TODO(phoglund): should arguably be checked.
256 r'^tools/valgrind-webrtc/.*\.py$',
257 r'^tools/valgrind/.*\.py$',
258 # TODO(phoglund): should arguably be checked.
259 r'^webrtc/build/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000260 r'^xcodebuild.*/.*\.py$',),
261
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000262 disabled_warnings=['F0401', # Failed to import x
263 'E0611', # No package y in x
264 'W0232', # Class has no __init__ method
265 ]))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000266 results.extend(input_api.canned_checks.CheckLongLines(
pbos@webrtc.orgf2e7bc62013-04-08 15:46:07 +0000267 input_api, output_api, maxlen=80))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000268 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
269 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000270 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
271 input_api, output_api))
272 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
273 input_api, output_api))
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000274 results.extend(_CheckApprovedFilesLintClean(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000275 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
276 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000277 results.extend(_CheckGypChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000278 results.extend(_CheckUnwantedDependencies(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000279 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000280
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000281
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000282def CheckChangeOnUpload(input_api, output_api):
283 results = []
284 results.extend(_CommonChecks(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000285 return results
286
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000287
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000288def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000289 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000290 results.extend(_CommonChecks(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000291 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000292 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
293 input_api, output_api))
294 results.extend(input_api.canned_checks.CheckChangeHasDescription(
295 input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000296 results.extend(input_api.canned_checks.CheckChangeHasBugField(
297 input_api, output_api))
298 results.extend(input_api.canned_checks.CheckChangeHasTestField(
299 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000300 results.extend(input_api.canned_checks.CheckTreeIsOpen(
301 input_api, output_api,
302 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000303 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000304
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000305
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000306def GetDefaultTryConfigs(bots=None):
307 """Returns a list of ('bot', set(['tests']), optionally filtered by [bots].
308
309 For WebRTC purposes, we always return an empty list of tests, since we want
310 to run all tests by default on all our trybots.
311 """
312 return { 'tryserver.webrtc': dict((bot, []) for bot in bots)}
313
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000314
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000315# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000316def GetPreferredTryMasters(project, change):
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000317 files = change.LocalPaths()
318
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000319 android_gn_bots = [
320 'android_gn',
321 'android_gn_rel',
322 ]
kjellander@webrtc.orgcf2b3ac2013-12-20 21:20:42 +0000323 android_bots = [
324 'android',
kjellander@webrtc.org9359eda2014-06-08 17:55:51 +0000325 'android_arm64',
kjellander@webrtc.orgcf2b3ac2013-12-20 21:20:42 +0000326 'android_rel',
327 'android_clang',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000328 ] + android_gn_bots
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000329 ios_bots = [
330 'ios',
kjellander@webrtc.orgd91d3592014-12-08 07:05:38 +0000331 'ios_arm64',
332 'ios_arm64_rel',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000333 'ios_rel',
334 ]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000335 linux_gn_bots = [
336 'linux_gn',
337 'linux_gn_rel',
338 ]
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000339 linux_bots = [
340 'linux',
341 'linux_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000342 'linux_baremetal',
kjellander@webrtc.org3b839d02014-10-24 21:41:24 +0000343 'linux_msan',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000344 'linux_rel',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000345 'linux_tsan2',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000346 ] + linux_gn_bots
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000347 mac_gn_bots = [
348 'mac_x64_gn',
349 'mac_x64_gn_rel',
350 ]
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000351 mac_bots = [
352 'mac',
353 'mac_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000354 'mac_baremetal',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000355 'mac_rel',
kjellander@webrtc.orgc0fc4dd2015-02-17 08:30:29 +0000356 'mac_x64',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000357 'mac_x64_rel',
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000358 ] + mac_gn_bots
359 win_gn_bots = [
360 'win_x64_gn',
361 'win_x64_gn_rel',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000362 ]
363 win_bots = [
364 'win',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000365 'win_baremetal',
kjellander@webrtc.orga956ec22014-04-14 08:38:27 +0000366 'win_drmemory_light',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000367 'win_rel',
368 'win_x64_rel',
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000369 ] + win_gn_bots
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000370 if not files or all(re.search(r'[\\/]OWNERS$', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000371 return {}
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000372 if all(re.search(r'[\\/]BUILD.gn$', f) for f in files):
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000373 return GetDefaultTryConfigs(android_gn_bots + linux_gn_bots + mac_gn_bots +
374 win_gn_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000375 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000376 return GetDefaultTryConfigs(mac_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000377 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000378 return GetDefaultTryConfigs(win_bots)
379 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
380 return GetDefaultTryConfigs(android_bots)
381 if all(re.search('[/_]ios[/_.]', f) for f in files):
382 return GetDefaultTryConfigs(ios_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000383
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000384 return GetDefaultTryConfigs(android_bots + ios_bots + linux_bots + mac_bots +
385 win_bots)