blob: 0243267ec7da118dd8e961e908fcb6449ae37526 [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.org85759802013-10-22 16:47:40 +00009import re
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +000010import sys
kjellander@webrtc.org85759802013-10-22 16:47:40 +000011
12
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000013def _CheckNoIOStreamInHeaders(input_api, output_api):
14 """Checks to make sure no .h files include <iostream>."""
15 files = []
16 pattern = input_api.re.compile(r'^#include\s*<iostream>',
17 input_api.re.MULTILINE)
18 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
19 if not f.LocalPath().endswith('.h'):
20 continue
21 contents = input_api.ReadFile(f)
22 if pattern.search(contents):
23 files.append(f)
24
25 if len(files):
26 return [ output_api.PresubmitError(
27 'Do not #include <iostream> in header files, since it inserts static ' +
28 'initialization into every file including the header. Instead, ' +
29 '#include <ostream>. See http://crbug.com/94794',
30 files) ]
31 return []
32
kjellander@webrtc.orge4158642014-08-06 09:11:18 +000033
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000034def _CheckNoFRIEND_TEST(input_api, output_api):
35 """Make sure that gtest's FRIEND_TEST() macro is not used, the
36 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
37 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
38 problems = []
39
40 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
41 for f in input_api.AffectedFiles(file_filter=file_filter):
42 for line_num, line in f.ChangedContents():
43 if 'FRIEND_TEST(' in line:
44 problems.append(' %s:%d' % (f.LocalPath(), line_num))
45
46 if not problems:
47 return []
48 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
49 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
50 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
51
kjellander@webrtc.orge4158642014-08-06 09:11:18 +000052
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000053def _CheckApprovedFilesLintClean(input_api, output_api,
54 source_file_filter=None):
55 """Checks that all new or whitelisted .cc and .h files pass cpplint.py.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000056 This check is based on _CheckChangeLintsClean in
57 depot_tools/presubmit_canned_checks.py but has less filters and only checks
58 added files."""
59 result = []
60
61 # Initialize cpplint.
62 import cpplint
63 # Access to a protected member _XX of a client class
64 # pylint: disable=W0212
65 cpplint._cpplint_state.ResetErrorCounts()
66
67 # Justifications for each filter:
68 #
69 # - build/header_guard : WebRTC coding style says they should be prefixed
70 # with WEBRTC_, which is not possible to configure in
71 # cpplint.py.
72 cpplint._SetFilters('-build/header_guard')
73
74 # Use the strictest verbosity level for cpplint.py (level 1) which is the
75 # default when running cpplint.py from command line.
76 # To make it possible to work with not-yet-converted code, we're only applying
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000077 # it to new (or moved/renamed) files and files listed in LINT_FOLDERS.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000078 verbosity_level = 1
79 files = []
80 for f in input_api.AffectedSourceFiles(source_file_filter):
81 # Note that moved/renamed files also count as added for svn.
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +000082 if (f.Action() == 'A'):
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000083 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000084
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000085 for file_name in files:
86 cpplint.ProcessFile(file_name, verbosity_level)
87
88 if cpplint._cpplint_state.error_count > 0:
89 if input_api.is_committing:
90 # TODO(kjellander): Change back to PresubmitError below when we're
91 # confident with the lint settings.
92 res_type = output_api.PresubmitPromptWarning
93 else:
94 res_type = output_api.PresubmitPromptWarning
95 result = [res_type('Changelist failed cpplint.py check.')]
96
97 return result
98
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +000099def _CheckNoRtcBaseDeps(input_api, gyp_files, output_api):
100 pattern = input_api.re.compile(r"base.gyp:rtc_base\s*'")
101 violating_files = []
102 for f in gyp_files:
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000103 gyp_exceptions = (
104 'base_tests.gyp',
105 'desktop_capture.gypi',
106 'libjingle.gyp',
henrike@webrtc.org28af6412014-11-04 15:11:46 +0000107 'libjingle_tests.gyp',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000108 'sound.gyp',
109 'webrtc_test_common.gyp',
110 'webrtc_tests.gypi',
111 )
112 if f.LocalPath().endswith(gyp_exceptions):
113 continue
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000114 contents = input_api.ReadFile(f)
115 if pattern.search(contents):
116 violating_files.append(f)
117 if violating_files:
118 return [output_api.PresubmitError(
119 'Depending on rtc_base is not allowed. Change your dependency to '
120 'rtc_base_approved and possibly sanitize and move the desired source '
121 'file(s) to rtc_base_approved.\nChanged GYP files:',
122 items=violating_files)]
123 return []
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000124
125def _CheckGypChanges(input_api, output_api):
126 source_file_filter = lambda x: input_api.FilterSourceFile(
127 x, white_list=(r'.+\.(gyp|gypi)$',))
128
129 gyp_files = []
130 for f in input_api.AffectedSourceFiles(source_file_filter):
kjellander@webrtc.org3398a4a2014-11-24 10:05:37 +0000131 if f.LocalPath().startswith('webrtc'):
132 gyp_files.append(f)
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000133
134 result = []
135 if gyp_files:
136 result.append(output_api.PresubmitNotifyResult(
137 'As you\'re changing GYP files: please make sure corresponding '
138 'BUILD.gn files are also updated.\nChanged GYP files:',
139 items=gyp_files))
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000140 result.extend(_CheckNoRtcBaseDeps(input_api, gyp_files, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000141 return result
142
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000143def _CheckUnwantedDependencies(input_api, output_api):
144 """Runs checkdeps on #include statements added in this
145 change. Breaking - rules is an error, breaking ! rules is a
146 warning.
147 """
148 # Copied from Chromium's src/PRESUBMIT.py.
149
150 # We need to wait until we have an input_api object and use this
151 # roundabout construct to import checkdeps because this file is
152 # eval-ed and thus doesn't have __file__.
153 original_sys_path = sys.path
154 try:
155 sys.path = sys.path + [input_api.os_path.join(
156 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
157 import checkdeps
158 from cpp_checker import CppChecker
159 from rules import Rule
160 finally:
161 # Restore sys.path to what it was before.
162 sys.path = original_sys_path
163
164 added_includes = []
165 for f in input_api.AffectedFiles():
166 if not CppChecker.IsCppFile(f.LocalPath()):
167 continue
168
169 changed_lines = [line for _line_num, line in f.ChangedContents()]
170 added_includes.append([f.LocalPath(), changed_lines])
171
172 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
173
174 error_descriptions = []
175 warning_descriptions = []
176 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
177 added_includes):
178 description_with_path = '%s\n %s' % (path, rule_description)
179 if rule_type == Rule.DISALLOW:
180 error_descriptions.append(description_with_path)
181 else:
182 warning_descriptions.append(description_with_path)
183
184 results = []
185 if error_descriptions:
186 results.append(output_api.PresubmitError(
187 'You added one or more #includes that violate checkdeps rules.',
188 error_descriptions))
189 if warning_descriptions:
190 results.append(output_api.PresubmitPromptOrNotify(
191 'You added one or more #includes of files that are temporarily\n'
192 'allowed but being removed. Can you avoid introducing the\n'
193 '#include? See relevant DEPS file(s) for details and contacts.',
194 warning_descriptions))
195 return results
196
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000197
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000198def _CommonChecks(input_api, output_api):
199 """Checks common to both upload and commit."""
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000200 # TODO(kjellander): Use presubmit_canned_checks.PanProjectChecks too.
niklase@google.comda159d62011-05-30 11:51:34 +0000201 results = []
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000202 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
203 black_list=(r'^.*gviz_api\.py$',
204 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000205 # Embedded shell-script fakes out pylint.
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000206 r'^build/.*\.py$',
207 r'^buildtools/.*\.py$',
kjellander@webrtc.org89256622014-08-20 12:10:11 +0000208 r'^chromium/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000209 r'^out.*/.*\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000210 r'^talk/site_scons/site_tools/talk_linux.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000211 r'^testing/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000212 r'^third_party/.*\.py$',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000213 r'^tools/clang/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000214 r'^tools/gn/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000215 r'^tools/gyp/.*\.py$',
216 r'^tools/perf_expectations/.*\.py$',
phoglund@webrtc.org6d07ad92013-05-14 09:42:39 +0000217 r'^tools/protoc_wrapper/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000218 r'^tools/python/.*\.py$',
219 r'^tools/python_charts/data/.*\.py$',
kjellander@webrtc.org33654222013-08-22 07:57:00 +0000220 r'^tools/refactoring/.*\.py$',
kjellander@webrtc.orgf9bdbe32013-12-11 13:37:12 +0000221 r'^tools/swarming_client/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000222 # TODO(phoglund): should arguably be checked.
223 r'^tools/valgrind-webrtc/.*\.py$',
224 r'^tools/valgrind/.*\.py$',
225 # TODO(phoglund): should arguably be checked.
226 r'^webrtc/build/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000227 r'^xcodebuild.*/.*\.py$',),
228
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000229 disabled_warnings=['F0401', # Failed to import x
230 'E0611', # No package y in x
231 'W0232', # Class has no __init__ method
232 ]))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000233 results.extend(input_api.canned_checks.CheckLongLines(
pbos@webrtc.orgf2e7bc62013-04-08 15:46:07 +0000234 input_api, output_api, maxlen=80))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000235 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
236 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000237 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
238 input_api, output_api))
239 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
240 input_api, output_api))
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000241 results.extend(_CheckApprovedFilesLintClean(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000242 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
243 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000244 results.extend(_CheckGypChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000245 results.extend(_CheckUnwantedDependencies(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000246 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000247
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000248
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000249def CheckChangeOnUpload(input_api, output_api):
250 results = []
251 results.extend(_CommonChecks(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000252 return results
253
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000254
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000255def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000256 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000257 results.extend(_CommonChecks(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000258 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000259 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
260 input_api, output_api))
261 results.extend(input_api.canned_checks.CheckChangeHasDescription(
262 input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000263 results.extend(input_api.canned_checks.CheckChangeHasBugField(
264 input_api, output_api))
265 results.extend(input_api.canned_checks.CheckChangeHasTestField(
266 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000267 results.extend(input_api.canned_checks.CheckTreeIsOpen(
268 input_api, output_api,
269 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000270 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000271
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000272
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000273def GetDefaultTryConfigs(bots=None):
274 """Returns a list of ('bot', set(['tests']), optionally filtered by [bots].
275
276 For WebRTC purposes, we always return an empty list of tests, since we want
277 to run all tests by default on all our trybots.
278 """
279 return { 'tryserver.webrtc': dict((bot, []) for bot in bots)}
280
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000281
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000282# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000283def GetPreferredTryMasters(project, change):
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000284 files = change.LocalPaths()
285
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000286 android_gn_bots = [
287 'android_gn',
288 'android_gn_rel',
289 ]
kjellander@webrtc.orgcf2b3ac2013-12-20 21:20:42 +0000290 android_bots = [
291 'android',
kjellander@webrtc.org9359eda2014-06-08 17:55:51 +0000292 'android_arm64',
kjellander@webrtc.orgcf2b3ac2013-12-20 21:20:42 +0000293 'android_rel',
294 'android_clang',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000295 ] + android_gn_bots
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000296 ios_bots = [
297 'ios',
kjellander@webrtc.orgd91d3592014-12-08 07:05:38 +0000298 'ios_arm64',
299 'ios_arm64_rel',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000300 'ios_rel',
301 ]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000302 linux_gn_bots = [
303 'linux_gn',
304 'linux_gn_rel',
305 ]
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000306 linux_bots = [
307 'linux',
308 'linux_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000309 'linux_baremetal',
kjellander@webrtc.org3b839d02014-10-24 21:41:24 +0000310 'linux_msan',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000311 'linux_rel',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000312 'linux_tsan2',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000313 ] + linux_gn_bots
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000314 mac_bots = [
315 'mac',
316 'mac_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000317 'mac_baremetal',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000318 'mac_rel',
319 'mac_x64_rel',
320 ]
321 win_bots = [
322 'win',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000323 'win_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000324 'win_baremetal',
kjellander@webrtc.orga956ec22014-04-14 08:38:27 +0000325 'win_drmemory_light',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000326 'win_rel',
327 'win_x64_rel',
328 ]
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000329 if not files or all(re.search(r'[\\/]OWNERS$', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000330 return {}
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000331 if all(re.search(r'[\\/]BUILD.gn$', f) for f in files):
332 return GetDefaultTryConfigs(android_gn_bots + linux_gn_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000333 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000334 return GetDefaultTryConfigs(mac_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000335 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000336 return GetDefaultTryConfigs(win_bots)
337 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
338 return GetDefaultTryConfigs(android_bots)
339 if all(re.search('[/_]ios[/_.]', f) for f in files):
340 return GetDefaultTryConfigs(ios_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000341
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000342 return GetDefaultTryConfigs(android_bots + ios_bots + linux_bots + mac_bots +
343 win_bots)