Fix regression of Autofill UI
[chromium-blink-merge.git] / PRESUBMIT.py
blob5c532d3956843867f12c9968a543a5c8f3a299ad
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,
134 'ScopedAllowIO',
136 'New code should not use ScopedAllowIO. Post a task to the blocking',
137 'pool or the FILE thread instead.',
139 True,
142 'FilePathWatcher::Delegate',
144 'New code should not use FilePathWatcher::Delegate. Use the callback',
145 'interface instead.',
147 False,
150 'chrome::FindLastActiveWithProfile',
152 'This function is deprecated and we\'re working on removing it. Pass',
153 'more context to get a Browser*, like a WebContents, window, or session',
154 'id. Talk to robertshield@ for more information.',
156 True,
159 'browser::FindAnyBrowser',
161 'This function is deprecated and we\'re working on removing it. Pass',
162 'more context to get a Browser*, like a WebContents, window, or session',
163 'id. Talk to robertshield@ for more information.',
165 True,
168 'browser::FindOrCreateTabbedBrowser',
170 'This function is deprecated and we\'re working on removing it. Pass',
171 'more context to get a Browser*, like a WebContents, window, or session',
172 'id. Talk to robertshield@ for more information.',
174 True,
177 'browser::FindTabbedBrowserDeprecated',
179 'This function is deprecated and we\'re working on removing it. Pass',
180 'more context to get a Browser*, like a WebContents, window, or session',
181 'id. Talk to robertshield@ for more information.',
183 True,
186 'RunAllPending()',
188 'This function is deprecated and we\'re working on removing it. Rename',
189 'to RunUntilIdle',
191 True,
197 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
198 """Attempts to prevent use of functions intended only for testing in
199 non-testing code. For now this is just a best-effort implementation
200 that ignores header files and may have some false positives. A
201 better implementation would probably need a proper C++ parser.
203 # We only scan .cc files and the like, as the declaration of
204 # for-testing functions in header files are hard to distinguish from
205 # calls to such functions without a proper C++ parser.
206 platform_specifiers = r'(_(android|chromeos|gtk|mac|posix|win))?'
207 source_extensions = r'\.(cc|cpp|cxx|mm)$'
208 file_inclusion_pattern = r'.+%s' % source_extensions
209 file_exclusion_patterns = (
210 r'.*[/\\](fake_|test_|mock_).+%s' % source_extensions,
211 r'.+_test_(base|support|util)%s' % source_extensions,
212 r'.+_(api|browser|perf|unit|ui)?test%s%s' % (platform_specifiers,
213 source_extensions),
214 r'.+profile_sync_service_harness%s' % source_extensions,
216 path_exclusion_patterns = (
217 r'.*[/\\](test|tool(s)?)[/\\].*',
218 # At request of folks maintaining this folder.
219 r'chrome[/\\]browser[/\\]automation[/\\].*',
222 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
223 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
224 exclusion_pattern = input_api.re.compile(
225 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
226 base_function_pattern, base_function_pattern))
228 def FilterFile(affected_file):
229 black_list = (file_exclusion_patterns + path_exclusion_patterns +
230 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
231 return input_api.FilterSourceFile(
232 affected_file,
233 white_list=(file_inclusion_pattern, ),
234 black_list=black_list)
236 problems = []
237 for f in input_api.AffectedSourceFiles(FilterFile):
238 local_path = f.LocalPath()
239 lines = input_api.ReadFile(f).splitlines()
240 line_number = 0
241 for line in lines:
242 if (inclusion_pattern.search(line) and
243 not exclusion_pattern.search(line)):
244 problems.append(
245 '%s:%d\n %s' % (local_path, line_number, line.strip()))
246 line_number += 1
248 if problems:
249 if not input_api.is_committing:
250 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
251 else:
252 # We don't warn on commit, to avoid stopping commits going through CQ.
253 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
254 else:
255 return []
258 def _CheckNoIOStreamInHeaders(input_api, output_api):
259 """Checks to make sure no .h files include <iostream>."""
260 files = []
261 pattern = input_api.re.compile(r'^#include\s*<iostream>',
262 input_api.re.MULTILINE)
263 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
264 if not f.LocalPath().endswith('.h'):
265 continue
266 contents = input_api.ReadFile(f)
267 if pattern.search(contents):
268 files.append(f)
270 if len(files):
271 return [ output_api.PresubmitError(
272 'Do not #include <iostream> in header files, since it inserts static '
273 'initialization into every file including the header. Instead, '
274 '#include <ostream>. See http://crbug.com/94794',
275 files) ]
276 return []
279 def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
280 """Checks to make sure no source files use UNIT_TEST"""
281 problems = []
282 for f in input_api.AffectedFiles():
283 if (not f.LocalPath().endswith(('.cc', '.mm'))):
284 continue
286 for line_num, line in f.ChangedContents():
287 if 'UNIT_TEST' in line:
288 problems.append(' %s:%d' % (f.LocalPath(), line_num))
290 if not problems:
291 return []
292 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
293 '\n'.join(problems))]
296 def _CheckNoNewWStrings(input_api, output_api):
297 """Checks to make sure we don't introduce use of wstrings."""
298 problems = []
299 for f in input_api.AffectedFiles():
300 if (not f.LocalPath().endswith(('.cc', '.h')) or
301 f.LocalPath().endswith('test.cc')):
302 continue
304 allowWString = False
305 for line_num, line in f.ChangedContents():
306 if 'presubmit: allow wstring' in line:
307 allowWString = True
308 elif not allowWString and 'wstring' in line:
309 problems.append(' %s:%d' % (f.LocalPath(), line_num))
310 allowWString = False
311 else:
312 allowWString = False
314 if not problems:
315 return []
316 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
317 ' If you are calling a cross-platform API that accepts a wstring, '
318 'fix the API.\n' +
319 '\n'.join(problems))]
322 def _CheckNoDEPSGIT(input_api, output_api):
323 """Make sure .DEPS.git is never modified manually."""
324 if any(f.LocalPath().endswith('.DEPS.git') for f in
325 input_api.AffectedFiles()):
326 return [output_api.PresubmitError(
327 'Never commit changes to .DEPS.git. This file is maintained by an\n'
328 'automated system based on what\'s in DEPS and your changes will be\n'
329 'overwritten.\n'
330 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
331 'for more information')]
332 return []
335 def _CheckNoBannedFunctions(input_api, output_api):
336 """Make sure that banned functions are not used."""
337 warnings = []
338 errors = []
340 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
341 for f in input_api.AffectedFiles(file_filter=file_filter):
342 for line_num, line in f.ChangedContents():
343 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
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 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
353 for f in input_api.AffectedFiles(file_filter=file_filter):
354 for line_num, line in f.ChangedContents():
355 for func_name, message, error in _BANNED_CPP_FUNCTIONS:
356 if func_name in line:
357 problems = warnings;
358 if error:
359 problems = errors;
360 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
361 for message_line in message:
362 problems.append(' %s' % message_line)
364 result = []
365 if (warnings):
366 result.append(output_api.PresubmitPromptWarning(
367 'Banned functions were used.\n' + '\n'.join(warnings)))
368 if (errors):
369 result.append(output_api.PresubmitError(
370 'Banned functions were used.\n' + '\n'.join(errors)))
371 return result
374 def _CheckNoPragmaOnce(input_api, output_api):
375 """Make sure that banned functions are not used."""
376 files = []
377 pattern = input_api.re.compile(r'^#pragma\s+once',
378 input_api.re.MULTILINE)
379 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
380 if not f.LocalPath().endswith('.h'):
381 continue
382 contents = input_api.ReadFile(f)
383 if pattern.search(contents):
384 files.append(f)
386 if files:
387 return [output_api.PresubmitError(
388 'Do not use #pragma once in header files.\n'
389 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
390 files)]
391 return []
394 def _CheckNoTrinaryTrueFalse(input_api, output_api):
395 """Checks to make sure we don't introduce use of foo ? true : false."""
396 problems = []
397 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
398 for f in input_api.AffectedFiles():
399 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
400 continue
402 for line_num, line in f.ChangedContents():
403 if pattern.match(line):
404 problems.append(' %s:%d' % (f.LocalPath(), line_num))
406 if not problems:
407 return []
408 return [output_api.PresubmitPromptWarning(
409 'Please consider avoiding the "? true : false" pattern if possible.\n' +
410 '\n'.join(problems))]
413 def _CheckUnwantedDependencies(input_api, output_api):
414 """Runs checkdeps on #include statements added in this
415 change. Breaking - rules is an error, breaking ! rules is a
416 warning.
418 # We need to wait until we have an input_api object and use this
419 # roundabout construct to import checkdeps because this file is
420 # eval-ed and thus doesn't have __file__.
421 original_sys_path = sys.path
422 try:
423 sys.path = sys.path + [input_api.os_path.join(
424 input_api.PresubmitLocalPath(), 'tools', 'checkdeps')]
425 import checkdeps
426 from cpp_checker import CppChecker
427 from rules import Rule
428 finally:
429 # Restore sys.path to what it was before.
430 sys.path = original_sys_path
432 added_includes = []
433 for f in input_api.AffectedFiles():
434 if not CppChecker.IsCppFile(f.LocalPath()):
435 continue
437 changed_lines = [line for line_num, line in f.ChangedContents()]
438 added_includes.append([f.LocalPath(), changed_lines])
440 deps_checker = checkdeps.DepsChecker()
442 error_descriptions = []
443 warning_descriptions = []
444 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
445 added_includes):
446 description_with_path = '%s\n %s' % (path, rule_description)
447 if rule_type == Rule.DISALLOW:
448 error_descriptions.append(description_with_path)
449 else:
450 warning_descriptions.append(description_with_path)
452 results = []
453 if error_descriptions:
454 results.append(output_api.PresubmitError(
455 'You added one or more #includes that violate checkdeps rules.',
456 error_descriptions))
457 if warning_descriptions:
458 if not input_api.is_committing:
459 warning_factory = output_api.PresubmitPromptWarning
460 else:
461 # We don't want to block use of the CQ when there is a warning
462 # of this kind, so we only show a message when committing.
463 warning_factory = output_api.PresubmitNotifyResult
464 results.append(warning_factory(
465 'You added one or more #includes of files that are temporarily\n'
466 'allowed but being removed. Can you avoid introducing the\n'
467 '#include? See relevant DEPS file(s) for details and contacts.',
468 warning_descriptions))
469 return results
472 def _CheckFilePermissions(input_api, output_api):
473 """Check that all files have their permissions properly set."""
474 args = [sys.executable, 'tools/checkperms/checkperms.py', '--root',
475 input_api.change.RepositoryRoot()]
476 for f in input_api.AffectedFiles():
477 args += ['--file', f.LocalPath()]
478 errors = []
479 (errors, stderrdata) = subprocess.Popen(args).communicate()
481 results = []
482 if errors:
483 results.append(output_api.PresubmitError('checkperms.py failed.',
484 errors))
485 return results
488 def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
489 """Makes sure we don't include ui/aura/window_property.h
490 in header files.
492 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
493 errors = []
494 for f in input_api.AffectedFiles():
495 if not f.LocalPath().endswith('.h'):
496 continue
497 for line_num, line in f.ChangedContents():
498 if pattern.match(line):
499 errors.append(' %s:%d' % (f.LocalPath(), line_num))
501 results = []
502 if errors:
503 results.append(output_api.PresubmitError(
504 'Header files should not include ui/aura/window_property.h', errors))
505 return results
508 def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
509 """Checks that the lines in scope occur in the right order.
511 1. C system files in alphabetical order
512 2. C++ system files in alphabetical order
513 3. Project's .h files
516 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
517 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
518 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
520 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
522 state = C_SYSTEM_INCLUDES
524 previous_line = ''
525 previous_line_num = 0
526 problem_linenums = []
527 for line_num, line in scope:
528 if c_system_include_pattern.match(line):
529 if state != C_SYSTEM_INCLUDES:
530 problem_linenums.append((line_num, previous_line_num))
531 elif previous_line and previous_line > line:
532 problem_linenums.append((line_num, previous_line_num))
533 elif cpp_system_include_pattern.match(line):
534 if state == C_SYSTEM_INCLUDES:
535 state = CPP_SYSTEM_INCLUDES
536 elif state == CUSTOM_INCLUDES:
537 problem_linenums.append((line_num, previous_line_num))
538 elif previous_line and previous_line > line:
539 problem_linenums.append((line_num, previous_line_num))
540 elif custom_include_pattern.match(line):
541 if state != CUSTOM_INCLUDES:
542 state = CUSTOM_INCLUDES
543 elif previous_line and previous_line > line:
544 problem_linenums.append((line_num, previous_line_num))
545 else:
546 problem_linenums.append(line_num)
547 previous_line = line
548 previous_line_num = line_num
550 warnings = []
551 for (line_num, previous_line_num) in problem_linenums:
552 if line_num in changed_linenums or previous_line_num in changed_linenums:
553 warnings.append(' %s:%d' % (file_path, line_num))
554 return warnings
557 def _CheckIncludeOrderInFile(input_api, f, is_source, changed_linenums):
558 """Checks the #include order for the given file f."""
560 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
561 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
562 if_pattern = input_api.re.compile(r'\s*#if.*')
563 endif_pattern = input_api.re.compile(r'\s*#endif.*')
565 contents = f.NewContents()
566 warnings = []
567 line_num = 0
569 # Handle the special first include for source files. If the header file is
570 # some/path/file.h, the corresponding source file can be some/path/file.cc,
571 # some/other/path/file.cc, some/path/file_platform.cc etc. It's also possible
572 # that no special first include exists.
573 if is_source:
574 for line in contents:
575 line_num += 1
576 if system_include_pattern.match(line):
577 # No special first include -> process the line again along with normal
578 # includes.
579 line_num -= 1
580 break
581 match = custom_include_pattern.match(line)
582 if match:
583 match_dict = match.groupdict()
584 header_basename = input_api.os_path.basename(
585 match_dict['FILE']).replace('.h', '')
586 if header_basename not in input_api.os_path.basename(f.LocalPath()):
587 # No special first include -> process the line again along with normal
588 # includes.
589 line_num -= 1
590 break
592 # Split into scopes: Each region between #if and #endif is its own scope.
593 scopes = []
594 current_scope = []
595 for line in contents[line_num:]:
596 line_num += 1
597 if if_pattern.match(line) or endif_pattern.match(line):
598 scopes.append(current_scope)
599 current_scope = []
600 elif (system_include_pattern.match(line) or
601 custom_include_pattern.match(line)):
602 current_scope.append((line_num, line))
603 scopes.append(current_scope)
605 for scope in scopes:
606 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
607 changed_linenums))
608 return warnings
611 def _CheckIncludeOrder(input_api, output_api):
612 """Checks that the #include order is correct.
614 1. The corresponding header for source files.
615 2. C system files in alphabetical order
616 3. C++ system files in alphabetical order
617 4. Project's .h files in alphabetical order
619 Each region between #if and #endif follows these rules separately.
622 warnings = []
623 for f in input_api.AffectedFiles():
624 changed_linenums = set([line_num for line_num, _ in f.ChangedContents()])
625 if f.LocalPath().endswith('.cc'):
626 warnings.extend(_CheckIncludeOrderInFile(input_api, f, True,
627 changed_linenums))
628 elif f.LocalPath().endswith('.h'):
629 warnings.extend(_CheckIncludeOrderInFile(input_api, f, False,
630 changed_linenums))
632 results = []
633 if warnings:
634 results.append(output_api.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING,
635 warnings))
636 return results
639 def _CommonChecks(input_api, output_api):
640 """Checks common to both upload and commit."""
641 results = []
642 results.extend(input_api.canned_checks.PanProjectChecks(
643 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
644 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
645 results.extend(
646 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
647 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
648 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
649 results.extend(_CheckNoNewWStrings(input_api, output_api))
650 results.extend(_CheckNoDEPSGIT(input_api, output_api))
651 results.extend(_CheckNoBannedFunctions(input_api, output_api))
652 results.extend(_CheckNoPragmaOnce(input_api, output_api))
653 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
654 results.extend(_CheckUnwantedDependencies(input_api, output_api))
655 results.extend(_CheckFilePermissions(input_api, output_api))
656 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
657 results.extend(_CheckIncludeOrder(input_api, output_api))
659 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
660 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
661 input_api, output_api,
662 input_api.PresubmitLocalPath(),
663 whitelist=[r'.+_test\.py$']))
664 return results
667 def _CheckSubversionConfig(input_api, output_api):
668 """Verifies the subversion config file is correctly setup.
670 Checks that autoprops are enabled, returns an error otherwise.
672 join = input_api.os_path.join
673 if input_api.platform == 'win32':
674 appdata = input_api.environ.get('APPDATA', '')
675 if not appdata:
676 return [output_api.PresubmitError('%APPDATA% is not configured.')]
677 path = join(appdata, 'Subversion', 'config')
678 else:
679 home = input_api.environ.get('HOME', '')
680 if not home:
681 return [output_api.PresubmitError('$HOME is not configured.')]
682 path = join(home, '.subversion', 'config')
684 error_msg = (
685 'Please look at http://dev.chromium.org/developers/coding-style to\n'
686 'configure your subversion configuration file. This enables automatic\n'
687 'properties to simplify the project maintenance.\n'
688 'Pro-tip: just download and install\n'
689 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
691 try:
692 lines = open(path, 'r').read().splitlines()
693 # Make sure auto-props is enabled and check for 2 Chromium standard
694 # auto-prop.
695 if (not '*.cc = svn:eol-style=LF' in lines or
696 not '*.pdf = svn:mime-type=application/pdf' in lines or
697 not 'enable-auto-props = yes' in lines):
698 return [
699 output_api.PresubmitNotifyResult(
700 'It looks like you have not configured your subversion config '
701 'file or it is not up-to-date.\n' + error_msg)
703 except (OSError, IOError):
704 return [
705 output_api.PresubmitNotifyResult(
706 'Can\'t find your subversion config file.\n' + error_msg)
708 return []
711 def _CheckAuthorizedAuthor(input_api, output_api):
712 """For non-googler/chromites committers, verify the author's email address is
713 in AUTHORS.
715 # TODO(maruel): Add it to input_api?
716 import fnmatch
718 author = input_api.change.author_email
719 if not author:
720 input_api.logging.info('No author, skipping AUTHOR check')
721 return []
722 authors_path = input_api.os_path.join(
723 input_api.PresubmitLocalPath(), 'AUTHORS')
724 valid_authors = (
725 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
726 for line in open(authors_path))
727 valid_authors = [item.group(1).lower() for item in valid_authors if item]
728 if input_api.verbose:
729 print 'Valid authors are %s' % ', '.join(valid_authors)
730 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
731 return [output_api.PresubmitPromptWarning(
732 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
733 '\n'
734 'http://www.chromium.org/developers/contributing-code and read the '
735 '"Legal" section\n'
736 'If you are a chromite, verify the contributor signed the CLA.') %
737 author)]
738 return []
741 def CheckChangeOnUpload(input_api, output_api):
742 results = []
743 results.extend(_CommonChecks(input_api, output_api))
744 return results
747 def CheckChangeOnCommit(input_api, output_api):
748 results = []
749 results.extend(_CommonChecks(input_api, output_api))
750 # TODO(thestig) temporarily disabled, doesn't work in third_party/
751 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
752 # input_api, output_api, sources))
753 # Make sure the tree is 'open'.
754 results.extend(input_api.canned_checks.CheckTreeIsOpen(
755 input_api,
756 output_api,
757 json_url='http://chromium-status.appspot.com/current?format=json'))
758 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
759 output_api, 'http://codereview.chromium.org',
760 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
761 'tryserver@chromium.org'))
763 results.extend(input_api.canned_checks.CheckChangeHasBugField(
764 input_api, output_api))
765 results.extend(input_api.canned_checks.CheckChangeHasDescription(
766 input_api, output_api))
767 results.extend(_CheckSubversionConfig(input_api, output_api))
768 return results
771 def GetPreferredTrySlaves(project, change):
772 files = change.LocalPaths()
774 if not files:
775 return []
777 if all(re.search('\.(m|mm)$|(^|[/_])mac[/_.]', f) for f in files):
778 return ['mac_rel', 'mac_asan']
779 if all(re.search('(^|[/_])win[/_.]', f) for f in files):
780 return ['win_rel']
781 if all(re.search('(^|[/_])android[/_.]', f) for f in files):
782 return ['android_dbg', 'android_clang_dbg']
783 if all(re.search('^native_client_sdk', f) for f in files):
784 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
785 if all(re.search('[/_]ios[/_.]', f) for f in files):
786 return ['ios_rel_device', 'ios_dbg_simulator']
788 trybots = [
789 'android_clang_dbg',
790 'android_dbg',
791 'ios_dbg_simulator',
792 'ios_rel_device',
793 'linux_asan',
794 'linux_chromeos',
795 'linux_clang:compile',
796 'linux_rel',
797 'mac_asan',
798 'mac_rel',
799 'win_rel',
802 # Match things like path/aura/file.cc and path/file_aura.cc.
803 # Same for ash and chromeos.
804 if any(re.search('[/_](ash|aura)', f) for f in files):
805 trybots += ['linux_chromeos_clang:compile', 'win_aura',
806 'linux_chromeos_asan']
807 elif any(re.search('[/_]chromeos', f) for f in files):
808 trybots += ['linux_chromeos_clang:compile', 'linux_chromeos_asan']
810 return trybots