Handling cursor visibility changing events for ChromeOS
[chromium-blink-merge.git] / PRESUBMIT.py
blob6ab44910877fbd05cbf94e12fb0af77f00cf777f
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Top-level presubmit script for Chromium.
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8 for more details about the presubmit API built into gcl.
9 """
12 import re
13 import subprocess
14 import sys
17 _EXCLUDED_PATHS = (
18 r"^breakpad[\\\/].*",
19 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
20 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
21 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
22 r"^skia[\\\/].*",
23 r"^v8[\\\/].*",
24 r".*MakeFile$",
25 r".+_autogen\.h$",
26 r"^cc[\\\/].*",
27 r"^webkit[\\\/]compositor_bindings[\\\/].*",
28 r".+[\\\/]pnacl_shim\.c$",
32 _TEST_ONLY_WARNING = (
33 'You might be calling functions intended only for testing from\n'
34 'production code. It is OK to ignore this warning if you know what\n'
35 'you are doing, as the heuristics used to detect the situation are\n'
36 'not perfect. The commit queue will not block on this warning.\n'
37 'Email joi@chromium.org if you have questions.')
40 _INCLUDE_ORDER_WARNING = (
41 'Your #include order seems to be broken. Send mail to\n'
42 'marja@chromium.org if this is not the case.')
45 _BANNED_OBJC_FUNCTIONS = (
47 'addTrackingRect:',
49 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
50 'prohibited. Please use CrTrackingArea instead.',
51 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
53 False,
56 'NSTrackingArea',
58 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
59 'instead.',
60 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
62 False,
65 'convertPointFromBase:',
67 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
68 'Please use |convertPoint:(point) fromView:nil| instead.',
69 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
71 True,
74 'convertPointToBase:',
76 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
77 'Please use |convertPoint:(point) toView:nil| instead.',
78 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
80 True,
83 'convertRectFromBase:',
85 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
86 'Please use |convertRect:(point) fromView:nil| instead.',
87 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
89 True,
92 'convertRectToBase:',
94 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
95 'Please use |convertRect:(point) toView:nil| instead.',
96 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
98 True,
101 'convertSizeFromBase:',
103 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
104 'Please use |convertSize:(point) fromView:nil| instead.',
105 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
107 True,
110 'convertSizeToBase:',
112 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
113 'Please use |convertSize:(point) toView:nil| instead.',
114 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
116 True,
121 _BANNED_CPP_FUNCTIONS = (
122 # Make sure that gtest's FRIEND_TEST() macro is not used; the
123 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
124 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
126 'FRIEND_TEST(',
128 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
129 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
131 False,
135 'ScopedAllowIO',
137 'New code should not use ScopedAllowIO. Post a task to the blocking',
138 'pool or the FILE thread instead.',
140 True,
142 r"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
146 'FilePathWatcher::Delegate',
148 'New code should not use FilePathWatcher::Delegate. Use the callback',
149 'interface instead.',
151 False,
155 'browser::FindOrCreateTabbedBrowser',
157 'This function is deprecated and we\'re working on removing it. Pass',
158 'more context to get a Browser*, like a WebContents, window, or session',
159 'id. Talk to robertshield@ for more information.',
161 True,
165 'RunAllPending()',
167 'This function is deprecated and we\'re working on removing it. Rename',
168 'to RunUntilIdle',
170 True,
177 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
178 """Attempts to prevent use of functions intended only for testing in
179 non-testing code. For now this is just a best-effort implementation
180 that ignores header files and may have some false positives. A
181 better implementation would probably need a proper C++ parser.
183 # We only scan .cc files and the like, as the declaration of
184 # for-testing functions in header files are hard to distinguish from
185 # calls to such functions without a proper C++ parser.
186 platform_specifiers = r'(_(android|chromeos|gtk|mac|posix|win))?'
187 source_extensions = r'\.(cc|cpp|cxx|mm)$'
188 file_inclusion_pattern = r'.+%s' % source_extensions
189 file_exclusion_patterns = (
190 r'.*[/\\](fake_|test_|mock_).+%s' % source_extensions,
191 r'.+_test_(base|support|util)%s' % source_extensions,
192 r'.+_(api|browser|perf|unit|ui)?test%s%s' % (platform_specifiers,
193 source_extensions),
194 r'.+profile_sync_service_harness%s' % source_extensions,
196 path_exclusion_patterns = (
197 r'.*[/\\](test|tool(s)?)[/\\].*',
198 # At request of folks maintaining this folder.
199 r'chrome[/\\]browser[/\\]automation[/\\].*',
202 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
203 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
204 exclusion_pattern = input_api.re.compile(
205 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
206 base_function_pattern, base_function_pattern))
208 def FilterFile(affected_file):
209 black_list = (file_exclusion_patterns + path_exclusion_patterns +
210 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
211 return input_api.FilterSourceFile(
212 affected_file,
213 white_list=(file_inclusion_pattern, ),
214 black_list=black_list)
216 problems = []
217 for f in input_api.AffectedSourceFiles(FilterFile):
218 local_path = f.LocalPath()
219 lines = input_api.ReadFile(f).splitlines()
220 line_number = 0
221 for line in lines:
222 if (inclusion_pattern.search(line) and
223 not exclusion_pattern.search(line)):
224 problems.append(
225 '%s:%d\n %s' % (local_path, line_number, line.strip()))
226 line_number += 1
228 if problems:
229 if not input_api.is_committing:
230 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
231 else:
232 # We don't warn on commit, to avoid stopping commits going through CQ.
233 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
234 else:
235 return []
238 def _CheckNoIOStreamInHeaders(input_api, output_api):
239 """Checks to make sure no .h files include <iostream>."""
240 files = []
241 pattern = input_api.re.compile(r'^#include\s*<iostream>',
242 input_api.re.MULTILINE)
243 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
244 if not f.LocalPath().endswith('.h'):
245 continue
246 contents = input_api.ReadFile(f)
247 if pattern.search(contents):
248 files.append(f)
250 if len(files):
251 return [ output_api.PresubmitError(
252 'Do not #include <iostream> in header files, since it inserts static '
253 'initialization into every file including the header. Instead, '
254 '#include <ostream>. See http://crbug.com/94794',
255 files) ]
256 return []
259 def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
260 """Checks to make sure no source files use UNIT_TEST"""
261 problems = []
262 for f in input_api.AffectedFiles():
263 if (not f.LocalPath().endswith(('.cc', '.mm'))):
264 continue
266 for line_num, line in f.ChangedContents():
267 if 'UNIT_TEST' in line:
268 problems.append(' %s:%d' % (f.LocalPath(), line_num))
270 if not problems:
271 return []
272 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
273 '\n'.join(problems))]
276 def _CheckNoNewWStrings(input_api, output_api):
277 """Checks to make sure we don't introduce use of wstrings."""
278 problems = []
279 for f in input_api.AffectedFiles():
280 if (not f.LocalPath().endswith(('.cc', '.h')) or
281 f.LocalPath().endswith('test.cc')):
282 continue
284 allowWString = False
285 for line_num, line in f.ChangedContents():
286 if 'presubmit: allow wstring' in line:
287 allowWString = True
288 elif not allowWString and 'wstring' in line:
289 problems.append(' %s:%d' % (f.LocalPath(), line_num))
290 allowWString = False
291 else:
292 allowWString = False
294 if not problems:
295 return []
296 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
297 ' If you are calling a cross-platform API that accepts a wstring, '
298 'fix the API.\n' +
299 '\n'.join(problems))]
302 def _CheckNoDEPSGIT(input_api, output_api):
303 """Make sure .DEPS.git is never modified manually."""
304 if any(f.LocalPath().endswith('.DEPS.git') for f in
305 input_api.AffectedFiles()):
306 return [output_api.PresubmitError(
307 'Never commit changes to .DEPS.git. This file is maintained by an\n'
308 'automated system based on what\'s in DEPS and your changes will be\n'
309 'overwritten.\n'
310 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
311 'for more information')]
312 return []
315 def _CheckNoBannedFunctions(input_api, output_api):
316 """Make sure that banned functions are not used."""
317 warnings = []
318 errors = []
320 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
321 for f in input_api.AffectedFiles(file_filter=file_filter):
322 for line_num, line in f.ChangedContents():
323 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
324 if func_name in line:
325 problems = warnings;
326 if error:
327 problems = errors;
328 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
329 for message_line in message:
330 problems.append(' %s' % message_line)
332 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
333 for f in input_api.AffectedFiles(file_filter=file_filter):
334 for line_num, line in f.ChangedContents():
335 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
336 def IsBlacklisted(affected_file, blacklist):
337 local_path = affected_file.LocalPath()
338 for item in blacklist:
339 if input_api.re.match(item, local_path):
340 return True
341 return False
342 if IsBlacklisted(f, excluded_paths):
343 continue
344 if func_name in line:
345 problems = warnings;
346 if error:
347 problems = errors;
348 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
349 for message_line in message:
350 problems.append(' %s' % message_line)
352 result = []
353 if (warnings):
354 result.append(output_api.PresubmitPromptWarning(
355 'Banned functions were used.\n' + '\n'.join(warnings)))
356 if (errors):
357 result.append(output_api.PresubmitError(
358 'Banned functions were used.\n' + '\n'.join(errors)))
359 return result
362 def _CheckNoPragmaOnce(input_api, output_api):
363 """Make sure that banned functions are not used."""
364 files = []
365 pattern = input_api.re.compile(r'^#pragma\s+once',
366 input_api.re.MULTILINE)
367 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
368 if not f.LocalPath().endswith('.h'):
369 continue
370 contents = input_api.ReadFile(f)
371 if pattern.search(contents):
372 files.append(f)
374 if files:
375 return [output_api.PresubmitError(
376 'Do not use #pragma once in header files.\n'
377 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
378 files)]
379 return []
382 def _CheckNoTrinaryTrueFalse(input_api, output_api):
383 """Checks to make sure we don't introduce use of foo ? true : false."""
384 problems = []
385 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
386 for f in input_api.AffectedFiles():
387 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
388 continue
390 for line_num, line in f.ChangedContents():
391 if pattern.match(line):
392 problems.append(' %s:%d' % (f.LocalPath(), line_num))
394 if not problems:
395 return []
396 return [output_api.PresubmitPromptWarning(
397 'Please consider avoiding the "? true : false" pattern if possible.\n' +
398 '\n'.join(problems))]
401 def _CheckUnwantedDependencies(input_api, output_api):
402 """Runs checkdeps on #include statements added in this
403 change. Breaking - rules is an error, breaking ! rules is a
404 warning.
406 # We need to wait until we have an input_api object and use this
407 # roundabout construct to import checkdeps because this file is
408 # eval-ed and thus doesn't have __file__.
409 original_sys_path = sys.path
410 try:
411 sys.path = sys.path + [input_api.os_path.join(
412 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
413 import checkdeps
414 from cpp_checker import CppChecker
415 from rules import Rule
416 finally:
417 # Restore sys.path to what it was before.
418 sys.path = original_sys_path
420 added_includes = []
421 for f in input_api.AffectedFiles():
422 if not CppChecker.IsCppFile(f.LocalPath()):
423 continue
425 changed_lines = [line for line_num, line in f.ChangedContents()]
426 added_includes.append([f.LocalPath(), changed_lines])
428 deps_checker = checkdeps.DepsChecker()
430 error_descriptions = []
431 warning_descriptions = []
432 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
433 added_includes):
434 description_with_path = '%s\n %s' % (path, rule_description)
435 if rule_type == Rule.DISALLOW:
436 error_descriptions.append(description_with_path)
437 else:
438 warning_descriptions.append(description_with_path)
440 results = []
441 if error_descriptions:
442 results.append(output_api.PresubmitError(
443 'You added one or more #includes that violate checkdeps rules.',
444 error_descriptions))
445 if warning_descriptions:
446 if not input_api.is_committing:
447 warning_factory = output_api.PresubmitPromptWarning
448 else:
449 # We don't want to block use of the CQ when there is a warning
450 # of this kind, so we only show a message when committing.
451 warning_factory = output_api.PresubmitNotifyResult
452 results.append(warning_factory(
453 'You added one or more #includes of files that are temporarily\n'
454 'allowed but being removed. Can you avoid introducing the\n'
455 '#include? See relevant DEPS file(s) for details and contacts.',
456 warning_descriptions))
457 return results
460 def _CheckFilePermissions(input_api, output_api):
461 """Check that all files have their permissions properly set."""
462 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
463 input_api.change.RepositoryRoot()]
464 for f in input_api.AffectedFiles():
465 args += ['--file', f.LocalPath()]
466 errors = []
467 (errors, stderrdata) = subprocess.Popen(args).communicate()
469 results = []
470 if errors:
471 results.append(output_api.PresubmitError('checkperms.py failed.',
472 errors))
473 return results
476 def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
477 """Makes sure we don't include ui/aura/window_property.h
478 in header files.
480 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
481 errors = []
482 for f in input_api.AffectedFiles():
483 if not f.LocalPath().endswith('.h'):
484 continue
485 for line_num, line in f.ChangedContents():
486 if pattern.match(line):
487 errors.append(' %s:%d' % (f.LocalPath(), line_num))
489 results = []
490 if errors:
491 results.append(output_api.PresubmitError(
492 'Header files should not include ui/aura/window_property.h', errors))
493 return results
496 def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
497 """Checks that the lines in scope occur in the right order.
499 1. C system files in alphabetical order
500 2. C++ system files in alphabetical order
501 3. Project's .h files
504 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
505 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
506 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
508 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
510 state = C_SYSTEM_INCLUDES
512 previous_line = ''
513 previous_line_num = 0
514 problem_linenums = []
515 for line_num, line in scope:
516 if c_system_include_pattern.match(line):
517 if state != C_SYSTEM_INCLUDES:
518 problem_linenums.append((line_num, previous_line_num))
519 elif previous_line and previous_line > line:
520 problem_linenums.append((line_num, previous_line_num))
521 elif cpp_system_include_pattern.match(line):
522 if state == C_SYSTEM_INCLUDES:
523 state = CPP_SYSTEM_INCLUDES
524 elif state == CUSTOM_INCLUDES:
525 problem_linenums.append((line_num, previous_line_num))
526 elif previous_line and previous_line > line:
527 problem_linenums.append((line_num, previous_line_num))
528 elif custom_include_pattern.match(line):
529 if state != CUSTOM_INCLUDES:
530 state = CUSTOM_INCLUDES
531 elif previous_line and previous_line > line:
532 problem_linenums.append((line_num, previous_line_num))
533 else:
534 problem_linenums.append(line_num)
535 previous_line = line
536 previous_line_num = line_num
538 warnings = []
539 for (line_num, previous_line_num) in problem_linenums:
540 if line_num in changed_linenums or previous_line_num in changed_linenums:
541 warnings.append(' %s:%d' % (file_path, line_num))
542 return warnings
545 def _CheckIncludeOrderInFile(input_api, f, is_source, changed_linenums):
546 """Checks the #include order for the given file f."""
548 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
549 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
550 # often need to appear in a specific order.
551 excluded_include_pattern = input_api.re.compile(r'\s*#include \<.*/.*')
552 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
553 if_pattern = input_api.re.compile(r'\s*#\s*(if|elif|else|endif).*')
555 contents = f.NewContents()
556 warnings = []
557 line_num = 0
559 # Handle the special first include for source files. If the header file is
560 # some/path/file.h, the corresponding source file can be some/path/file.cc,
561 # some/other/path/file.cc, some/path/file_platform.cc etc. It's also possible
562 # that no special first include exists.
563 if is_source:
564 for line in contents:
565 line_num += 1
566 if system_include_pattern.match(line):
567 # No special first include -> process the line again along with normal
568 # includes.
569 line_num -= 1
570 break
571 match = custom_include_pattern.match(line)
572 if match:
573 match_dict = match.groupdict()
574 header_basename = input_api.os_path.basename(
575 match_dict['FILE']).replace('.h', '')
576 if header_basename not in input_api.os_path.basename(f.LocalPath()):
577 # No special first include -> process the line again along with normal
578 # includes.
579 line_num -= 1
580 break
582 # Split into scopes: Each region between #if and #endif is its own scope.
583 scopes = []
584 current_scope = []
585 for line in contents[line_num:]:
586 line_num += 1
587 if if_pattern.match(line):
588 scopes.append(current_scope)
589 current_scope = []
590 elif ((system_include_pattern.match(line) or
591 custom_include_pattern.match(line)) and
592 not excluded_include_pattern.match(line)):
593 current_scope.append((line_num, line))
594 scopes.append(current_scope)
596 for scope in scopes:
597 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
598 changed_linenums))
599 return warnings
602 def _CheckIncludeOrder(input_api, output_api):
603 """Checks that the #include order is correct.
605 1. The corresponding header for source files.
606 2. C system files in alphabetical order
607 3. C++ system files in alphabetical order
608 4. Project's .h files in alphabetical order
610 Each region between #if and #endif follows these rules separately.
613 warnings = []
614 for f in input_api.AffectedFiles():
615 changed_linenums = set([line_num for line_num, _ in f.ChangedContents()])
616 if f.LocalPath().endswith('.cc'):
617 warnings.extend(_CheckIncludeOrderInFile(input_api, f, True,
618 changed_linenums))
619 elif f.LocalPath().endswith('.h'):
620 warnings.extend(_CheckIncludeOrderInFile(input_api, f, False,
621 changed_linenums))
623 results = []
624 if warnings:
625 results.append(output_api.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING,
626 warnings))
627 return results
630 def _CheckForVersionControlConflictsInFile(input_api, f):
631 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
632 errors = []
633 for line_num, line in f.ChangedContents():
634 if pattern.match(line):
635 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
636 return errors
639 def _CheckForVersionControlConflicts(input_api, output_api):
640 """Usually this is not intentional and will cause a compile failure."""
641 errors = []
642 for f in input_api.AffectedFiles():
643 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
645 results = []
646 if errors:
647 results.append(output_api.PresubmitError(
648 'Version control conflict markers found, please resolve.', errors))
649 return results
652 def _CommonChecks(input_api, output_api):
653 """Checks common to both upload and commit."""
654 results = []
655 results.extend(input_api.canned_checks.PanProjectChecks(
656 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
657 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
658 results.extend(
659 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
660 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
661 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
662 results.extend(_CheckNoNewWStrings(input_api, output_api))
663 results.extend(_CheckNoDEPSGIT(input_api, output_api))
664 results.extend(_CheckNoBannedFunctions(input_api, output_api))
665 results.extend(_CheckNoPragmaOnce(input_api, output_api))
666 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
667 results.extend(_CheckUnwantedDependencies(input_api, output_api))
668 results.extend(_CheckFilePermissions(input_api, output_api))
669 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
670 results.extend(_CheckIncludeOrder(input_api, output_api))
671 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
673 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
674 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
675 input_api, output_api,
676 input_api.PresubmitLocalPath(),
677 whitelist=[r'.+_test\.py$']))
678 return results
681 def _CheckSubversionConfig(input_api, output_api):
682 """Verifies the subversion config file is correctly setup.
684 Checks that autoprops are enabled, returns an error otherwise.
686 join = input_api.os_path.join
687 if input_api.platform == 'win32':
688 appdata = input_api.environ.get('APPDATA', '')
689 if not appdata:
690 return [output_api.PresubmitError('%APPDATA% is not configured.')]
691 path = join(appdata, 'Subversion', 'config')
692 else:
693 home = input_api.environ.get('HOME', '')
694 if not home:
695 return [output_api.PresubmitError('$HOME is not configured.')]
696 path = join(home, '.subversion', 'config')
698 error_msg = (
699 'Please look at http://dev.chromium.org/developers/coding-style to\n'
700 'configure your subversion configuration file. This enables automatic\n'
701 'properties to simplify the project maintenance.\n'
702 'Pro-tip: just download and install\n'
703 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
705 try:
706 lines = open(path, 'r').read().splitlines()
707 # Make sure auto-props is enabled and check for 2 Chromium standard
708 # auto-prop.
709 if (not '*.cc = svn:eol-style=LF' in lines or
710 not '*.pdf = svn:mime-type=application/pdf' in lines or
711 not 'enable-auto-props = yes' in lines):
712 return [
713 output_api.PresubmitNotifyResult(
714 'It looks like you have not configured your subversion config '
715 'file or it is not up-to-date.\n' + error_msg)
717 except (OSError, IOError):
718 return [
719 output_api.PresubmitNotifyResult(
720 'Can\'t find your subversion config file.\n' + error_msg)
722 return []
725 def _CheckAuthorizedAuthor(input_api, output_api):
726 """For non-googler/chromites committers, verify the author's email address is
727 in AUTHORS.
729 # TODO(maruel): Add it to input_api?
730 import fnmatch
732 author = input_api.change.author_email
733 if not author:
734 input_api.logging.info('No author, skipping AUTHOR check')
735 return []
736 authors_path = input_api.os_path.join(
737 input_api.PresubmitLocalPath(), 'AUTHORS')
738 valid_authors = (
739 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
740 for line in open(authors_path))
741 valid_authors = [item.group(1).lower() for item in valid_authors if item]
742 if input_api.verbose:
743 print 'Valid authors are %s' % ', '.join(valid_authors)
744 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
745 return [output_api.PresubmitPromptWarning(
746 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
747 '\n'
748 'http://www.chromium.org/developers/contributing-code and read the '
749 '"Legal" section\n'
750 'If you are a chromite, verify the contributor signed the CLA.') %
751 author)]
752 return []
755 def CheckChangeOnUpload(input_api, output_api):
756 results = []
757 results.extend(_CommonChecks(input_api, output_api))
758 return results
761 def CheckChangeOnCommit(input_api, output_api):
762 results = []
763 results.extend(_CommonChecks(input_api, output_api))
764 # TODO(thestig) temporarily disabled, doesn't work in third_party/
765 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
766 # input_api, output_api, sources))
767 # Make sure the tree is 'open'.
768 results.extend(input_api.canned_checks.CheckTreeIsOpen(
769 input_api,
770 output_api,
771 json_url='http://chromium-status.appspot.com/current?format=json'))
772 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
773 output_api, 'http://codereview.chromium.org',
774 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
775 'tryserver@chromium.org'))
777 results.extend(input_api.canned_checks.CheckChangeHasBugField(
778 input_api, output_api))
779 results.extend(input_api.canned_checks.CheckChangeHasDescription(
780 input_api, output_api))
781 results.extend(_CheckSubversionConfig(input_api, output_api))
782 return results
785 def GetPreferredTrySlaves(project, change):
786 files = change.LocalPaths()
788 if not files:
789 return []
791 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
792 return ['mac_rel', 'mac_asan']
793 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
794 return ['win_rel']
795 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
796 return ['android_dbg', 'android_clang_dbg']
797 if all(re.search('^native_client_sdk', f) for f in files):
798 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
799 if all(re.search('[/_]ios[/_.]', f) for f in files):
800 return ['ios_rel_device', 'ios_dbg_simulator']
802 trybots = [
803 'android_clang_dbg',
804 'android_dbg',
805 'ios_dbg_simulator',
806 'ios_rel_device',
807 'linux_asan',
808 'linux_aura',
809 'linux_chromeos',
810 'linux_clang:compile',
811 'linux_rel',
812 'mac_asan',
813 'mac_rel',
814 'win_aura',
815 'win_rel',
818 # Match things like path/aura/file.cc and path/file_aura.cc.
819 # Same for chromeos.
820 if any(re.search('[/_](aura|chromeos)', f) for f in files):
821 trybots += ['linux_chromeos_clang:compile', 'linux_chromeos_asan']
823 return trybots