blob: 320b07a24d45133d70976df81fc2479beef309fc [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',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000109 'sound.gyp',
110 'webrtc_test_common.gyp',
111 'webrtc_tests.gypi',
112 )
113 if f.LocalPath().endswith(gyp_exceptions):
114 continue
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000115 contents = input_api.ReadFile(f)
116 if pattern.search(contents):
117 violating_files.append(f)
118 if violating_files:
119 return [output_api.PresubmitError(
120 'Depending on rtc_base is not allowed. Change your dependency to '
121 'rtc_base_approved and possibly sanitize and move the desired source '
122 'file(s) to rtc_base_approved.\nChanged GYP files:',
123 items=violating_files)]
124 return []
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000125
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000126def _CheckNoSourcesAboveGyp(input_api, gyp_files, output_api):
127 # Disallow referencing source files with paths above the GYP file location.
128 source_pattern = input_api.re.compile(r'sources.*?\[(.*?)\]',
129 re.MULTILINE | re.DOTALL)
kjellander@webrtc.orga33f05e2015-01-29 14:29:45 +0000130 file_pattern = input_api.re.compile(r"'((\.\./.*?)|(<\(webrtc_root\).*?))'")
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000131 violating_gyp_files = set()
132 violating_source_entries = []
133 for gyp_file in gyp_files:
134 contents = input_api.ReadFile(gyp_file)
135 for source_block_match in source_pattern.finditer(contents):
136 # Find all source list entries starting with ../ in the source block.
137 for file_list_match in file_pattern.finditer(source_block_match.group(0)):
138 violating_source_entries.append(file_list_match.group(0))
139 violating_gyp_files.add(gyp_file)
140 if violating_gyp_files:
141 return [output_api.PresubmitError(
142 'Referencing source files above the directory of the GYP file is not '
143 'allowed. Please introduce new GYP targets and/or GYP files in the '
144 'proper location instead.\n'
145 'Invalid source entries:\n'
146 '%s\n'
147 'Violating GYP files:' % '\n'.join(violating_source_entries),
148 items=violating_gyp_files)]
149 return []
150
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000151def _CheckGypChanges(input_api, output_api):
152 source_file_filter = lambda x: input_api.FilterSourceFile(
153 x, white_list=(r'.+\.(gyp|gypi)$',))
154
155 gyp_files = []
156 for f in input_api.AffectedSourceFiles(source_file_filter):
kjellander@webrtc.org3398a4a2014-11-24 10:05:37 +0000157 if f.LocalPath().startswith('webrtc'):
158 gyp_files.append(f)
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000159
160 result = []
161 if gyp_files:
162 result.append(output_api.PresubmitNotifyResult(
163 'As you\'re changing GYP files: please make sure corresponding '
164 'BUILD.gn files are also updated.\nChanged GYP files:',
165 items=gyp_files))
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000166 result.extend(_CheckNoRtcBaseDeps(input_api, gyp_files, output_api))
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000167 result.extend(_CheckNoSourcesAboveGyp(input_api, gyp_files, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000168 return result
169
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000170def _CheckUnwantedDependencies(input_api, output_api):
171 """Runs checkdeps on #include statements added in this
172 change. Breaking - rules is an error, breaking ! rules is a
173 warning.
174 """
175 # Copied from Chromium's src/PRESUBMIT.py.
176
177 # We need to wait until we have an input_api object and use this
178 # roundabout construct to import checkdeps because this file is
179 # eval-ed and thus doesn't have __file__.
180 original_sys_path = sys.path
181 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000182 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
183 'buildtools', 'checkdeps')
184 if not os.path.exists(checkdeps_path):
185 return [output_api.PresubmitError(
186 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
187 'download Chromium and setup the symlinks?' % checkdeps_path)]
188 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000189 import checkdeps
190 from cpp_checker import CppChecker
191 from rules import Rule
192 finally:
193 # Restore sys.path to what it was before.
194 sys.path = original_sys_path
195
196 added_includes = []
197 for f in input_api.AffectedFiles():
198 if not CppChecker.IsCppFile(f.LocalPath()):
199 continue
200
201 changed_lines = [line for _line_num, line in f.ChangedContents()]
202 added_includes.append([f.LocalPath(), changed_lines])
203
204 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
205
206 error_descriptions = []
207 warning_descriptions = []
208 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
209 added_includes):
210 description_with_path = '%s\n %s' % (path, rule_description)
211 if rule_type == Rule.DISALLOW:
212 error_descriptions.append(description_with_path)
213 else:
214 warning_descriptions.append(description_with_path)
215
216 results = []
217 if error_descriptions:
218 results.append(output_api.PresubmitError(
219 'You added one or more #includes that violate checkdeps rules.',
220 error_descriptions))
221 if warning_descriptions:
222 results.append(output_api.PresubmitPromptOrNotify(
223 'You added one or more #includes of files that are temporarily\n'
224 'allowed but being removed. Can you avoid introducing the\n'
225 '#include? See relevant DEPS file(s) for details and contacts.',
226 warning_descriptions))
227 return results
228
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000229
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000230def _CommonChecks(input_api, output_api):
231 """Checks common to both upload and commit."""
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000232 # TODO(kjellander): Use presubmit_canned_checks.PanProjectChecks too.
niklase@google.comda159d62011-05-30 11:51:34 +0000233 results = []
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000234 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
235 black_list=(r'^.*gviz_api\.py$',
236 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000237 # Embedded shell-script fakes out pylint.
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000238 r'^build/.*\.py$',
239 r'^buildtools/.*\.py$',
kjellander@webrtc.org89256622014-08-20 12:10:11 +0000240 r'^chromium/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000241 r'^out.*/.*\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000242 r'^talk/site_scons/site_tools/talk_linux.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000243 r'^testing/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000244 r'^third_party/.*\.py$',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000245 r'^tools/clang/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000246 r'^tools/gn/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000247 r'^tools/gyp/.*\.py$',
248 r'^tools/perf_expectations/.*\.py$',
phoglund@webrtc.org6d07ad92013-05-14 09:42:39 +0000249 r'^tools/protoc_wrapper/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000250 r'^tools/python/.*\.py$',
251 r'^tools/python_charts/data/.*\.py$',
kjellander@webrtc.org33654222013-08-22 07:57:00 +0000252 r'^tools/refactoring/.*\.py$',
kjellander@webrtc.orgf9bdbe32013-12-11 13:37:12 +0000253 r'^tools/swarming_client/.*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000254 # TODO(phoglund): should arguably be checked.
255 r'^tools/valgrind-webrtc/.*\.py$',
256 r'^tools/valgrind/.*\.py$',
257 # TODO(phoglund): should arguably be checked.
258 r'^webrtc/build/.*\.py$',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000259 r'^xcodebuild.*/.*\.py$',),
260
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000261 disabled_warnings=['F0401', # Failed to import x
262 'E0611', # No package y in x
263 'W0232', # Class has no __init__ method
264 ]))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000265 results.extend(input_api.canned_checks.CheckLongLines(
pbos@webrtc.orgf2e7bc62013-04-08 15:46:07 +0000266 input_api, output_api, maxlen=80))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000267 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
268 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000269 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
270 input_api, output_api))
271 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
272 input_api, output_api))
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000273 results.extend(_CheckApprovedFilesLintClean(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000274 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
275 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000276 results.extend(_CheckGypChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000277 results.extend(_CheckUnwantedDependencies(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000278 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000279
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000280
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000281def CheckChangeOnUpload(input_api, output_api):
282 results = []
283 results.extend(_CommonChecks(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000284 return results
285
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000286
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000287def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000288 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000289 results.extend(_CommonChecks(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000290 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000291 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
292 input_api, output_api))
293 results.extend(input_api.canned_checks.CheckChangeHasDescription(
294 input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000295 results.extend(input_api.canned_checks.CheckChangeHasBugField(
296 input_api, output_api))
297 results.extend(input_api.canned_checks.CheckChangeHasTestField(
298 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000299 results.extend(input_api.canned_checks.CheckTreeIsOpen(
300 input_api, output_api,
301 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000302 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000303
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000304
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000305def GetDefaultTryConfigs(bots=None):
306 """Returns a list of ('bot', set(['tests']), optionally filtered by [bots].
307
308 For WebRTC purposes, we always return an empty list of tests, since we want
309 to run all tests by default on all our trybots.
310 """
311 return { 'tryserver.webrtc': dict((bot, []) for bot in bots)}
312
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000313
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000314# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000315def GetPreferredTryMasters(project, change):
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000316 files = change.LocalPaths()
317
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000318 android_gn_bots = [
319 'android_gn',
320 'android_gn_rel',
321 ]
kjellander@webrtc.orgcf2b3ac2013-12-20 21:20:42 +0000322 android_bots = [
323 'android',
kjellander@webrtc.org9359eda2014-06-08 17:55:51 +0000324 'android_arm64',
kjellander@webrtc.orgcf2b3ac2013-12-20 21:20:42 +0000325 'android_rel',
326 'android_clang',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000327 ] + android_gn_bots
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000328 ios_bots = [
329 'ios',
kjellander@webrtc.orgd91d3592014-12-08 07:05:38 +0000330 'ios_arm64',
331 'ios_arm64_rel',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000332 'ios_rel',
333 ]
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000334 linux_gn_bots = [
335 'linux_gn',
336 'linux_gn_rel',
337 ]
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000338 linux_bots = [
339 'linux',
340 'linux_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000341 'linux_baremetal',
kjellander@webrtc.org3b839d02014-10-24 21:41:24 +0000342 'linux_msan',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000343 'linux_rel',
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000344 'linux_tsan2',
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000345 ] + linux_gn_bots
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000346 mac_gn_bots = [
347 'mac_x64_gn',
348 'mac_x64_gn_rel',
349 ]
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000350 mac_bots = [
351 'mac',
352 'mac_asan',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000353 'mac_baremetal',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000354 'mac_rel',
355 'mac_x64_rel',
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000356 ] + mac_gn_bots
357 win_gn_bots = [
358 'win_x64_gn',
359 'win_x64_gn_rel',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000360 ]
361 win_bots = [
362 'win',
kjellander@webrtc.org570bc3d2014-01-22 19:00:01 +0000363 'win_baremetal',
kjellander@webrtc.orga956ec22014-04-14 08:38:27 +0000364 'win_drmemory_light',
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000365 'win_rel',
366 'win_x64_rel',
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000367 ] + win_gn_bots
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000368 if not files or all(re.search(r'[\\/]OWNERS$', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000369 return {}
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000370 if all(re.search(r'[\\/]BUILD.gn$', f) for f in files):
kjellander@webrtc.org1592df72015-01-09 15:38:29 +0000371 return GetDefaultTryConfigs(android_gn_bots + linux_gn_bots + mac_gn_bots +
372 win_gn_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000373 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000374 return GetDefaultTryConfigs(mac_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000375 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000376 return GetDefaultTryConfigs(win_bots)
377 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
378 return GetDefaultTryConfigs(android_bots)
379 if all(re.search('[/_]ios[/_.]', f) for f in files):
380 return GetDefaultTryConfigs(ios_bots)
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000381
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000382 return GetDefaultTryConfigs(android_bots + ios_bots + linux_bots + mac_bots +
383 win_bots)