blob: 55e56d80a78d6af13ab788e31f4c0a20bac4ce41 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
[email protected]50d7d721e2009-11-15 17:56:188for more details about the presubmit API built into gcl.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]9d16ad12011-12-14 20:49:4712import re
[email protected]fbcafe5a2012-08-08 15:31:2213import subprocess
[email protected]55f9f382012-07-31 11:02:1814import sys
[email protected]9d16ad12011-12-14 20:49:4715
16
[email protected]379e7dd2010-01-28 17:39:2117_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5418 r"^breakpad[\\\/].*",
[email protected]a18130a2012-01-03 17:52:0819 r"^native_client_sdk[\\\/].*",
20 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r"^skia[\\\/].*",
22 r"^v8[\\\/].*",
23 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
[email protected]94f206c12012-08-25 00:09:1425 r"^cc[\\\/].*",
[email protected]39849c6c2012-09-14 22:15:5926 r"^webkit[\\\/]compositor_bindings[\\\/].*",
[email protected]ce145c02012-09-06 09:49:3427 r".+[\\\/]pnacl_shim\.c$",
[email protected]4306417642009-06-11 00:33:4028)
[email protected]ca8d19842009-02-19 16:33:1229
[email protected]ca8d19842009-02-19 16:33:1230
[email protected]eea609a2011-11-18 13:10:1231_TEST_ONLY_WARNING = (
32 'You might be calling functions intended only for testing from\n'
33 'production code. It is OK to ignore this warning if you know what\n'
34 'you are doing, as the heuristics used to detect the situation are\n'
35 'not perfect. The commit queue will not block on this warning.\n'
36 'Email [email protected] if you have questions.')
37
38
[email protected]127f18ec2012-06-16 05:05:5939_BANNED_OBJC_FUNCTIONS = (
40 (
41 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2042 (
43 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5944 'prohibited. Please use CrTrackingArea instead.',
45 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
46 ),
47 False,
48 ),
49 (
50 'NSTrackingArea',
[email protected]23e6cbc2012-06-16 18:51:2051 (
52 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5953 'instead.',
54 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
55 ),
56 False,
57 ),
58 (
59 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2060 (
61 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5962 'Please use |convertPoint:(point) fromView:nil| instead.',
63 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
64 ),
65 True,
66 ),
67 (
68 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2069 (
70 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5971 'Please use |convertPoint:(point) toView:nil| instead.',
72 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
73 ),
74 True,
75 ),
76 (
77 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2078 (
79 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5980 'Please use |convertRect:(point) fromView:nil| instead.',
81 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
82 ),
83 True,
84 ),
85 (
86 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:2087 (
88 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5989 'Please use |convertRect:(point) toView:nil| instead.',
90 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
91 ),
92 True,
93 ),
94 (
95 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2096 (
97 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5998 'Please use |convertSize:(point) fromView:nil| instead.',
99 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
100 ),
101 True,
102 ),
103 (
104 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20105 (
106 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59107 'Please use |convertSize:(point) toView:nil| instead.',
108 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
109 ),
110 True,
111 ),
112)
113
114
115_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20116 # Make sure that gtest's FRIEND_TEST() macro is not used; the
117 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
118 # used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes.
119 (
120 'FRIEND_TEST(',
121 (
[email protected]e3c945502012-06-26 20:01:49122 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20123 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
124 ),
125 False,
126 ),
127 (
128 'ScopedAllowIO',
129 (
[email protected]e3c945502012-06-26 20:01:49130 'New code should not use ScopedAllowIO. Post a task to the blocking',
131 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20132 ),
[email protected]e3c945502012-06-26 20:01:49133 True,
[email protected]23e6cbc2012-06-16 18:51:20134 ),
135 (
136 'FilePathWatcher::Delegate',
137 (
[email protected]e3c945502012-06-26 20:01:49138 'New code should not use FilePathWatcher::Delegate. Use the callback',
[email protected]23e6cbc2012-06-16 18:51:20139 'interface instead.',
140 ),
141 False,
142 ),
[email protected]e3c945502012-06-26 20:01:49143 (
144 'browser::FindLastActiveWithProfile',
145 (
146 'This function is deprecated and we\'re working on removing it. Pass',
147 'more context to get a Browser*, like a WebContents, window, or session',
148 'id. Talk to ben@ or jam@ for more information.',
149 ),
150 True,
151 ),
152 (
[email protected]e3c945502012-06-26 20:01:49153 'browser::FindAnyBrowser',
154 (
155 'This function is deprecated and we\'re working on removing it. Pass',
156 'more context to get a Browser*, like a WebContents, window, or session',
157 'id. Talk to ben@ or jam@ for more information.',
158 ),
159 True,
160 ),
161 (
162 'browser::FindOrCreateTabbedBrowser',
163 (
164 'This function is deprecated and we\'re working on removing it. Pass',
165 'more context to get a Browser*, like a WebContents, window, or session',
166 'id. Talk to ben@ or jam@ for more information.',
167 ),
168 True,
169 ),
170 (
171 'browser::FindTabbedBrowser',
172 (
173 'This function is deprecated and we\'re working on removing it. Pass',
174 'more context to get a Browser*, like a WebContents, window, or session',
175 'id. Talk to ben@ or jam@ for more information.',
176 ),
177 True,
178 ),
[email protected]127f18ec2012-06-16 05:05:59179)
180
181
[email protected]eea609a2011-11-18 13:10:12182
[email protected]55459852011-08-10 15:17:19183def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
184 """Attempts to prevent use of functions intended only for testing in
185 non-testing code. For now this is just a best-effort implementation
186 that ignores header files and may have some false positives. A
187 better implementation would probably need a proper C++ parser.
188 """
189 # We only scan .cc files and the like, as the declaration of
190 # for-testing functions in header files are hard to distinguish from
191 # calls to such functions without a proper C++ parser.
[email protected]403bfbc92012-06-11 23:30:09192 platform_specifiers = r'(_(android|chromeos|gtk|mac|posix|win))?'
[email protected]55459852011-08-10 15:17:19193 source_extensions = r'\.(cc|cpp|cxx|mm)$'
194 file_inclusion_pattern = r'.+%s' % source_extensions
[email protected]19e77fd2011-10-20 05:24:05195 file_exclusion_patterns = (
[email protected]e21ce382012-01-04 18:48:25196 r'.*[/\\](test_|mock_).+%s' % source_extensions,
[email protected]c762d252012-02-28 02:07:24197 r'.+_test_(base|support|util)%s' % source_extensions,
[email protected]403bfbc92012-06-11 23:30:09198 r'.+_(api|browser|perf|unit|ui)?test%s%s' % (platform_specifiers,
199 source_extensions),
[email protected]19e77fd2011-10-20 05:24:05200 r'.+profile_sync_service_harness%s' % source_extensions,
201 )
202 path_exclusion_patterns = (
203 r'.*[/\\](test|tool(s)?)[/\\].*',
204 # At request of folks maintaining this folder.
205 r'chrome[/\\]browser[/\\]automation[/\\].*',
206 )
[email protected]55459852011-08-10 15:17:19207
208 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
209 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
210 exclusion_pattern = input_api.re.compile(
211 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
212 base_function_pattern, base_function_pattern))
213
214 def FilterFile(affected_file):
[email protected]19e77fd2011-10-20 05:24:05215 black_list = (file_exclusion_patterns + path_exclusion_patterns +
[email protected]3afb12a42011-08-15 13:48:33216 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19217 return input_api.FilterSourceFile(
218 affected_file,
219 white_list=(file_inclusion_pattern, ),
220 black_list=black_list)
221
222 problems = []
223 for f in input_api.AffectedSourceFiles(FilterFile):
224 local_path = f.LocalPath()
225 lines = input_api.ReadFile(f).splitlines()
226 line_number = 0
227 for line in lines:
228 if (inclusion_pattern.search(line) and
229 not exclusion_pattern.search(line)):
230 problems.append(
231 '%s:%d\n %s' % (local_path, line_number, line.strip()))
232 line_number += 1
233
234 if problems:
[email protected]eea609a2011-11-18 13:10:12235 if not input_api.is_committing:
236 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
237 else:
238 # We don't warn on commit, to avoid stopping commits going through CQ.
239 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
[email protected]55459852011-08-10 15:17:19240 else:
241 return []
242
243
[email protected]10689ca2011-09-02 02:31:54244def _CheckNoIOStreamInHeaders(input_api, output_api):
245 """Checks to make sure no .h files include <iostream>."""
246 files = []
247 pattern = input_api.re.compile(r'^#include\s*<iostream>',
248 input_api.re.MULTILINE)
249 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
250 if not f.LocalPath().endswith('.h'):
251 continue
252 contents = input_api.ReadFile(f)
253 if pattern.search(contents):
254 files.append(f)
255
256 if len(files):
257 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06258 'Do not #include <iostream> in header files, since it inserts static '
259 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54260 '#include <ostream>. See http://crbug.com/94794',
261 files) ]
262 return []
263
264
[email protected]72df4e782012-06-21 16:28:18265def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
266 """Checks to make sure no source files use UNIT_TEST"""
267 problems = []
268 for f in input_api.AffectedFiles():
269 if (not f.LocalPath().endswith(('.cc', '.mm'))):
270 continue
271
272 for line_num, line in f.ChangedContents():
273 if 'UNIT_TEST' in line:
274 problems.append(' %s:%d' % (f.LocalPath(), line_num))
275
276 if not problems:
277 return []
278 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
279 '\n'.join(problems))]
280
281
[email protected]8ea5d4b2011-09-13 21:49:22282def _CheckNoNewWStrings(input_api, output_api):
283 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27284 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22285 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20286 if (not f.LocalPath().endswith(('.cc', '.h')) or
287 f.LocalPath().endswith('test.cc')):
288 continue
[email protected]8ea5d4b2011-09-13 21:49:22289
[email protected]a11dbe9b2012-08-07 01:32:58290 allowWString = False
[email protected]b5c24292011-11-28 14:38:20291 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58292 if 'presubmit: allow wstring' in line:
293 allowWString = True
294 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27295 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58296 allowWString = False
297 else:
298 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22299
[email protected]55463aa62011-10-12 00:48:27300 if not problems:
301 return []
302 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58303 ' If you are calling a cross-platform API that accepts a wstring, '
304 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27305 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22306
307
[email protected]2a8ac9c2011-10-19 17:20:44308def _CheckNoDEPSGIT(input_api, output_api):
309 """Make sure .DEPS.git is never modified manually."""
310 if any(f.LocalPath().endswith('.DEPS.git') for f in
311 input_api.AffectedFiles()):
312 return [output_api.PresubmitError(
313 'Never commit changes to .DEPS.git. This file is maintained by an\n'
314 'automated system based on what\'s in DEPS and your changes will be\n'
315 'overwritten.\n'
316 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
317 'for more information')]
318 return []
319
320
[email protected]127f18ec2012-06-16 05:05:59321def _CheckNoBannedFunctions(input_api, output_api):
322 """Make sure that banned functions are not used."""
323 warnings = []
324 errors = []
325
326 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
327 for f in input_api.AffectedFiles(file_filter=file_filter):
328 for line_num, line in f.ChangedContents():
329 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
330 if func_name in line:
331 problems = warnings;
332 if error:
333 problems = errors;
334 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
335 for message_line in message:
336 problems.append(' %s' % message_line)
337
338 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
339 for f in input_api.AffectedFiles(file_filter=file_filter):
340 for line_num, line in f.ChangedContents():
341 for func_name, message, error in _BANNED_CPP_FUNCTIONS:
342 if func_name in line:
343 problems = warnings;
344 if error:
345 problems = errors;
346 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
347 for message_line in message:
348 problems.append(' %s' % message_line)
349
350 result = []
351 if (warnings):
352 result.append(output_api.PresubmitPromptWarning(
353 'Banned functions were used.\n' + '\n'.join(warnings)))
354 if (errors):
355 result.append(output_api.PresubmitError(
356 'Banned functions were used.\n' + '\n'.join(errors)))
357 return result
358
359
[email protected]6c063c62012-07-11 19:11:06360def _CheckNoPragmaOnce(input_api, output_api):
361 """Make sure that banned functions are not used."""
362 files = []
363 pattern = input_api.re.compile(r'^#pragma\s+once',
364 input_api.re.MULTILINE)
365 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
366 if not f.LocalPath().endswith('.h'):
367 continue
368 contents = input_api.ReadFile(f)
369 if pattern.search(contents):
370 files.append(f)
371
372 if files:
373 return [output_api.PresubmitError(
374 'Do not use #pragma once in header files.\n'
375 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
376 files)]
377 return []
378
[email protected]127f18ec2012-06-16 05:05:59379
[email protected]e7479052012-09-19 00:26:12380def _CheckNoTrinaryTrueFalse(input_api, output_api):
381 """Checks to make sure we don't introduce use of foo ? true : false."""
382 problems = []
383 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
384 for f in input_api.AffectedFiles():
385 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
386 continue
387
388 for line_num, line in f.ChangedContents():
389 if pattern.match(line):
390 problems.append(' %s:%d' % (f.LocalPath(), line_num))
391
392 if not problems:
393 return []
394 return [output_api.PresubmitPromptWarning(
395 'Please consider avoiding the "? true : false" pattern if possible.\n' +
396 '\n'.join(problems))]
397
398
[email protected]55f9f382012-07-31 11:02:18399def _CheckUnwantedDependencies(input_api, output_api):
400 """Runs checkdeps on #include statements added in this
401 change. Breaking - rules is an error, breaking ! rules is a
402 warning.
403 """
404 # We need to wait until we have an input_api object and use this
405 # roundabout construct to import checkdeps because this file is
406 # eval-ed and thus doesn't have __file__.
407 original_sys_path = sys.path
408 try:
409 sys.path = sys.path + [input_api.os_path.join(
410 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
411 import checkdeps
412 from cpp_checker import CppChecker
413 from rules import Rule
414 finally:
415 # Restore sys.path to what it was before.
416 sys.path = original_sys_path
417
418 added_includes = []
419 for f in input_api.AffectedFiles():
420 if not CppChecker.IsCppFile(f.LocalPath()):
421 continue
422
423 changed_lines = [line for line_num, line in f.ChangedContents()]
424 added_includes.append([f.LocalPath(), changed_lines])
425
426 deps_checker = checkdeps.DepsChecker()
427
428 error_descriptions = []
429 warning_descriptions = []
430 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
431 added_includes):
432 description_with_path = '%s\n %s' % (path, rule_description)
433 if rule_type == Rule.DISALLOW:
434 error_descriptions.append(description_with_path)
435 else:
436 warning_descriptions.append(description_with_path)
437
438 results = []
439 if error_descriptions:
440 results.append(output_api.PresubmitError(
441 'You added one or more #includes that violate checkdeps rules.',
442 error_descriptions))
443 if warning_descriptions:
[email protected]779caa52012-08-21 17:05:59444 if not input_api.is_committing:
445 warning_factory = output_api.PresubmitPromptWarning
446 else:
447 # We don't want to block use of the CQ when there is a warning
448 # of this kind, so we only show a message when committing.
449 warning_factory = output_api.PresubmitNotifyResult
450 results.append(warning_factory(
[email protected]55f9f382012-07-31 11:02:18451 'You added one or more #includes of files that are temporarily\n'
452 'allowed but being removed. Can you avoid introducing the\n'
453 '#include? See relevant DEPS file(s) for details and contacts.',
454 warning_descriptions))
455 return results
456
457
[email protected]fbcafe5a2012-08-08 15:31:22458def _CheckFilePermissions(input_api, output_api):
459 """Check that all files have their permissions properly set."""
460 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
461 input_api.change.RepositoryRoot()]
462 for f in input_api.AffectedFiles():
463 args += ['--file', f.LocalPath()]
464 errors = []
465 (errors, stderrdata) = subprocess.Popen(args).communicate()
466
467 results = []
468 if errors:
469 results.append(output_api.PreSubmitError('checkperms.py failed.',
470 errors))
471 return results
472
473
[email protected]22c9bd72011-03-27 16:47:39474def _CommonChecks(input_api, output_api):
475 """Checks common to both upload and commit."""
476 results = []
477 results.extend(input_api.canned_checks.PanProjectChecks(
478 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
[email protected]66daa702011-05-28 14:41:46479 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:19480 results.extend(
481 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:54482 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:18483 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:22484 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:44485 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:59486 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:06487 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:12488 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:18489 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:22490 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]22c9bd72011-03-27 16:47:39491 return results
[email protected]1f7b4172010-01-28 01:17:34492
[email protected]b337cb5b2011-01-23 21:24:05493
494def _CheckSubversionConfig(input_api, output_api):
495 """Verifies the subversion config file is correctly setup.
496
497 Checks that autoprops are enabled, returns an error otherwise.
498 """
499 join = input_api.os_path.join
500 if input_api.platform == 'win32':
501 appdata = input_api.environ.get('APPDATA', '')
502 if not appdata:
503 return [output_api.PresubmitError('%APPDATA% is not configured.')]
504 path = join(appdata, 'Subversion', 'config')
505 else:
506 home = input_api.environ.get('HOME', '')
507 if not home:
508 return [output_api.PresubmitError('$HOME is not configured.')]
509 path = join(home, '.subversion', 'config')
510
511 error_msg = (
512 'Please look at http://dev.chromium.org/developers/coding-style to\n'
513 'configure your subversion configuration file. This enables automatic\n'
[email protected]c6a3c10b2011-01-24 16:14:20514 'properties to simplify the project maintenance.\n'
515 'Pro-tip: just download and install\n'
516 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
[email protected]b337cb5b2011-01-23 21:24:05517
518 try:
519 lines = open(path, 'r').read().splitlines()
520 # Make sure auto-props is enabled and check for 2 Chromium standard
521 # auto-prop.
522 if (not '*.cc = svn:eol-style=LF' in lines or
523 not '*.pdf = svn:mime-type=application/pdf' in lines or
524 not 'enable-auto-props = yes' in lines):
525 return [
[email protected]79ed7e62011-02-21 21:08:53526 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05527 'It looks like you have not configured your subversion config '
[email protected]b5359c02011-02-01 20:29:56528 'file or it is not up-to-date.\n' + error_msg)
[email protected]b337cb5b2011-01-23 21:24:05529 ]
530 except (OSError, IOError):
531 return [
[email protected]79ed7e62011-02-21 21:08:53532 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05533 'Can\'t find your subversion config file.\n' + error_msg)
534 ]
535 return []
536
537
[email protected]66daa702011-05-28 14:41:46538def _CheckAuthorizedAuthor(input_api, output_api):
539 """For non-googler/chromites committers, verify the author's email address is
540 in AUTHORS.
541 """
[email protected]9bb9cb82011-06-13 20:43:01542 # TODO(maruel): Add it to input_api?
543 import fnmatch
544
[email protected]66daa702011-05-28 14:41:46545 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:01546 if not author:
547 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:46548 return []
[email protected]c99663292011-05-31 19:46:08549 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:46550 input_api.PresubmitLocalPath(), 'AUTHORS')
551 valid_authors = (
552 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
553 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:18554 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]9bb9cb82011-06-13 20:43:01555 if input_api.verbose:
556 print 'Valid authors are %s' % ', '.join(valid_authors)
[email protected]d8b50be2011-06-15 14:19:44557 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]66daa702011-05-28 14:41:46558 return [output_api.PresubmitPromptWarning(
559 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
560 '\n'
561 'http://www.chromium.org/developers/contributing-code and read the '
562 '"Legal" section\n'
563 'If you are a chromite, verify the contributor signed the CLA.') %
564 author)]
565 return []
566
567
[email protected]1f7b4172010-01-28 01:17:34568def CheckChangeOnUpload(input_api, output_api):
569 results = []
570 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54571 return results
[email protected]ca8d19842009-02-19 16:33:12572
573
574def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:54575 results = []
[email protected]1f7b4172010-01-28 01:17:34576 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:51577 # TODO(thestig) temporarily disabled, doesn't work in third_party/
578 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
579 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:54580 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:27581 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:34582 input_api,
583 output_api,
[email protected]4efa42142010-08-26 01:29:26584 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:27585 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
[email protected]4ddc5df2011-12-12 03:05:04586 output_api, 'http://codereview.chromium.org',
[email protected]c1ba4c52012-03-09 14:23:28587 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
588 '[email protected]'))
[email protected]806e98e2010-03-19 17:49:27589
[email protected]3e4eb112011-01-18 03:29:54590 results.extend(input_api.canned_checks.CheckChangeHasBugField(
591 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:41592 results.extend(input_api.canned_checks.CheckChangeHasDescription(
593 input_api, output_api))
[email protected]b337cb5b2011-01-23 21:24:05594 results.extend(_CheckSubversionConfig(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54595 return results
[email protected]ca8d19842009-02-19 16:33:12596
597
[email protected]5efb2a822011-09-27 23:06:13598def GetPreferredTrySlaves(project, change):
[email protected]4ce995ea2012-06-27 02:13:10599 files = change.LocalPaths()
600
[email protected]3019c902012-06-29 00:09:03601 if not files:
602 return []
603
[email protected]d668899a2012-09-06 18:16:59604 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
[email protected]641f2e3e2012-09-03 11:16:24605 return ['mac_rel', 'mac_asan']
[email protected]d668899a2012-09-06 18:16:59606 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
[email protected]4ce995ea2012-06-27 02:13:10607 return ['win_rel']
[email protected]d668899a2012-09-06 18:16:59608 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
[email protected]c4781e52012-09-13 18:24:38609 return ['android_dbg']
[email protected]356aa542012-09-19 23:31:29610 if all(re.search('^native_client_sdk', f) for f in files):
611 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
[email protected]4ce995ea2012-06-27 02:13:10612
[email protected]d602b902012-07-19 16:30:31613 trybots = ['win_rel', 'linux_rel', 'mac_rel', 'linux_clang:compile',
[email protected]c4781e52012-09-13 18:24:38614 'linux_chromeos', 'android_dbg', 'linux_asan', 'mac_asan']
[email protected]911753b2012-08-02 12:11:54615
616 # Match things like path/aura/file.cc and path/file_aura.cc.
[email protected]0be9553a2012-08-10 00:14:45617 # Same for ash and chromeos.
618 if any(re.search('[/_](ash|aura)', f) for f in files):
[email protected]641f2e3e2012-09-03 11:16:24619 trybots += ['linux_chromeos', 'linux_chromeos_clang:compile', 'win_aura',
620 'linux_chromeos_asan']
[email protected]0be9553a2012-08-10 00:14:45621 else:
622 if any(re.search('[/_]chromeos', f) for f in files):
[email protected]641f2e3e2012-09-03 11:16:24623 trybots += ['linux_chromeos', 'linux_chromeos_clang:compile',
624 'linux_chromeos_asan']
[email protected]4ce995ea2012-06-27 02:13:10625
[email protected]4ce995ea2012-06-27 02:13:10626 return trybots