OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Generic presubmit checks that can be reused by other presubmit checks.""" | 5 """Generic presubmit checks that can be reused by other presubmit checks.""" |
6 | 6 |
7 import os as _os | 7 import os as _os |
8 _HERE = _os.path.dirname(_os.path.abspath(__file__)) | 8 _HERE = _os.path.dirname(_os.path.abspath(__file__)) |
9 | 9 |
10 | 10 |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 if cr_files: | 220 if cr_files: |
221 outputs.append(output_api.PresubmitPromptWarning( | 221 outputs.append(output_api.PresubmitPromptWarning( |
222 'Found a CR character in these files:', items=cr_files)) | 222 'Found a CR character in these files:', items=cr_files)) |
223 if eof_files: | 223 if eof_files: |
224 outputs.append(output_api.PresubmitPromptWarning( | 224 outputs.append(output_api.PresubmitPromptWarning( |
225 'These files should end in one (and only one) newline character:', | 225 'These files should end in one (and only one) newline character:', |
226 items=eof_files)) | 226 items=eof_files)) |
227 return outputs | 227 return outputs |
228 | 228 |
229 | 229 |
230 def _ReportErrorFileAndLine(filename, line_num, line): | 230 def _ReportErrorFileAndLine(filename, line_num, dummy_line): |
231 """Default error formatter for _FindNewViolationsOfRule.""" | 231 """Default error formatter for _FindNewViolationsOfRule.""" |
232 return '%s, line %s' % (filename, line_num) | 232 return '%s, line %s' % (filename, line_num) |
233 | 233 |
234 | 234 |
235 def _FindNewViolationsOfRule(callable_rule, input_api, source_file_filter=None, | 235 def _FindNewViolationsOfRule(callable_rule, input_api, source_file_filter=None, |
236 error_formatter=_ReportErrorFileAndLine): | 236 error_formatter=_ReportErrorFileAndLine): |
237 """Find all newly introduced violations of a per-line rule (a callable). | 237 """Find all newly introduced violations of a per-line rule (a callable). |
238 | 238 |
239 Arguments: | 239 Arguments: |
240 callable_rule: a callable taking a file extension and line of input and | 240 callable_rule: a callable taking a file extension and line of input and |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 filepath = input_api.os_path.join(dirpath, item)[path_len + 1:] | 615 filepath = input_api.os_path.join(dirpath, item)[path_len + 1:] |
616 if Find(filepath, white_list) and not Find(filepath, black_list): | 616 if Find(filepath, white_list) and not Find(filepath, black_list): |
617 files.append(filepath) | 617 files.append(filepath) |
618 return files | 618 return files |
619 | 619 |
620 | 620 |
621 def RunPylint(input_api, output_api, white_list=None, black_list=None, | 621 def RunPylint(input_api, output_api, white_list=None, black_list=None, |
622 disabled_warnings=None): | 622 disabled_warnings=None): |
623 """Run pylint on python files. | 623 """Run pylint on python files. |
624 | 624 |
625 The default white_list enforces looking only a *.py files. | 625 The default white_list enforces looking only at *.py files. |
626 """ | 626 """ |
627 white_list = tuple(white_list or ('.*\.py$',)) | 627 white_list = tuple(white_list or ('.*\.py$',)) |
628 black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) | 628 black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) |
629 if input_api.is_committing: | 629 if input_api.is_committing: |
630 error_type = output_api.PresubmitError | 630 error_type = output_api.PresubmitError |
631 else: | 631 else: |
632 error_type = output_api.PresubmitPromptWarning | 632 error_type = output_api.PresubmitPromptWarning |
633 | 633 |
634 # Only trigger if there is at least one python file affected. | 634 # Only trigger if there is at least one python file affected. |
635 src_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list) | 635 src_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list) |
636 if not input_api.AffectedSourceFiles(src_filter): | 636 if not input_api.AffectedSourceFiles(src_filter): |
637 return [] | 637 return [] |
638 | 638 |
639 extra_args = ['--rcfile=%s' % input_api.os_path.join(_HERE, 'pylintrc')] | 639 extra_args = ['--rcfile=%s' % input_api.os_path.join(_HERE, 'pylintrc')] |
640 if disabled_warnings: | 640 if disabled_warnings: |
641 extra_args.extend(['-d', ','.join(disabled_warnings)]) | 641 extra_args.extend(['-d', ','.join(disabled_warnings)]) |
642 | 642 |
643 # On certain pylint/python version combination, running pylint throws a lot of | 643 files = _FetchAllFiles(input_api, white_list, black_list) |
644 # warning messages. | 644 if not files: |
645 import warnings | 645 return [] |
646 warnings.filterwarnings('ignore', category=DeprecationWarning) | 646 |
647 try: | 647 # Copy the system path to the environment so pylint can find the right |
648 files = _FetchAllFiles(input_api, white_list, black_list) | 648 # imports. |
649 if not files: | 649 env = input_api.environ.copy() |
650 return [] | 650 import sys |
651 # Now that at least one python file was modified and all the python files | 651 env['PYTHONPATH'] = input_api.os_path.pathsep.join(sys.path) |
652 # were listed, try to run pylint. | 652 |
| 653 def run_lint(files): |
| 654 # We can't import pylint directly due to licensing issues, so we run |
| 655 # it in another process. Windows needs help running python files so we |
| 656 # explicitly specify the interpreter to use. |
| 657 command = [input_api.python_executable, |
| 658 input_api.os_path.join(_HERE, 'third_party', 'pylint.py')] |
653 try: | 659 try: |
654 from pylint import lint | 660 return input_api.subprocess.call(command + files + extra_args) |
655 from pylint.utils import UnknownMessage | 661 except OSError: |
656 input_api.logging.debug( | 662 return 'Pylint failed!' |
657 'Using pylint v%s from %s' % (lint.version, lint.__file__)) | |
658 except ImportError: | |
659 if input_api.platform == 'win32': | |
660 return [output_api.PresubmitNotifyResult( | |
661 'Warning: Can\'t run pylint because it is not installed. Please ' | |
662 'install manually\n' | |
663 'Cannot do static analysis of python files.')] | |
664 return [output_api.PresubmitError( | |
665 'Please install pylint with "sudo apt-get install python-setuptools; ' | |
666 'sudo easy_install pylint"\n' | |
667 'or visit http://pypi.python.org/pypi/setuptools.\n' | |
668 'Cannot do static analysis of python files.')] | |
669 | 663 |
670 def run_lint(files): | 664 result = None |
671 try: | 665 if not input_api.verbose: |
672 lint.Run(files + extra_args) | 666 result = run_lint(sorted(files)) |
673 assert False | 667 else: |
674 except SystemExit, e: | 668 for filename in sorted(files): |
675 # pylint has the bad habit of calling sys.exit(), trap it here. | 669 print('Running pylint on %s' % filename) |
676 return e.code | 670 result = run_lint([filename]) or result |
677 except UnknownMessage, e: | 671 if isinstance(result, basestring): |
678 return 'Please upgrade pylint: %s' % e | 672 return [error_type(result)] |
679 | 673 elif result: |
680 result = None | 674 return [error_type('Fix pylint errors first.')] |
681 if not input_api.verbose: | 675 return [] |
682 result = run_lint(sorted(files)) | |
683 else: | |
684 for filename in sorted(files): | |
685 print('Running pylint on %s' % filename) | |
686 result = run_lint([filename]) or result | |
687 if isinstance(result, basestring): | |
688 return [error_type(result)] | |
689 elif result: | |
690 return [error_type('Fix pylint errors first.')] | |
691 return [] | |
692 finally: | |
693 warnings.filterwarnings('default', category=DeprecationWarning) | |
694 | 676 |
695 | 677 |
696 # TODO(dpranke): Get the host_url from the input_api instead | 678 # TODO(dpranke): Get the host_url from the input_api instead |
697 def CheckRietveldTryJobExecution(input_api, output_api, host_url, platforms, | 679 def CheckRietveldTryJobExecution(dummy_input_api, dummy_output_api, |
698 owner): | 680 dummy_host_url, dummy_platforms, |
| 681 dummy_owner): |
699 # Temporarily 'fix' the check while the Rietveld API is being upgraded to | 682 # Temporarily 'fix' the check while the Rietveld API is being upgraded to |
700 # something sensible. | 683 # something sensible. |
701 return [] | 684 return [] |
702 | 685 |
703 | 686 |
704 def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings, | 687 def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings, |
705 ignored): | 688 ignored): |
706 try: | 689 try: |
707 connection = input_api.urllib2.urlopen(url) | 690 connection = input_api.urllib2.urlopen(url) |
708 raw_data = connection.read() | 691 raw_data = connection.read() |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( | 932 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( |
950 input_api, output_api)) | 933 input_api, output_api)) |
951 snapshot("checking license") | 934 snapshot("checking license") |
952 results.extend(input_api.canned_checks.CheckLicense( | 935 results.extend(input_api.canned_checks.CheckLicense( |
953 input_api, output_api, license_header, source_file_filter=sources)) | 936 input_api, output_api, license_header, source_file_filter=sources)) |
954 snapshot("checking was uploaded") | 937 snapshot("checking was uploaded") |
955 results.extend(input_api.canned_checks.CheckChangeWasUploaded( | 938 results.extend(input_api.canned_checks.CheckChangeWasUploaded( |
956 input_api, output_api)) | 939 input_api, output_api)) |
957 snapshot("done") | 940 snapshot("done") |
958 return results | 941 return results |
OLD | NEW |