| """Script that lints a list of changed files then outputs a list of comments.""" |
| |
| from __future__ import absolute_import |
| import collections |
| import logging |
| import os |
| import re |
| import subprocess |
| |
| # path/to/file.py:27: [E1234(error-name), Text] Error message is here |
| LINT_WARNING_PATTERN = (r'^(?P<filename>[^:]+):(?P<line_num>\d+): ' |
| r'\[(?P<error_code>\w+)\((?P<error_name>.*)\).*\] ' |
| r'(?P<error_msg>.*)$') |
| |
| |
| class PylintError(Exception): |
| """Error for the pylint module.""" |
| |
| |
| def RunPylint(changed_files, pylintrc_file=None, cwd=None, executor=None): |
| """Runs pylint on a list of changed files. |
| |
| Args: |
| changed_files: List of files to lint. |
| pylintrc_file: Path to a pylintrc file to use with pylint (or None to use |
| the default pylintrc from depot_tools). |
| cwd: If provided, cwd in which to run pylint. |
| executor: If provided, object with which to invoke pylint. |
| |
| Returns: |
| stdout of the pylint command. |
| |
| Raises: |
| PylintError: if pylint cannot be found. |
| """ |
| if not changed_files: |
| return '' |
| |
| pylint = os.path.expanduser('~/depot_tools/pylint') |
| if not os.path.exists(pylint): |
| logging.error('pylint not installed in expected location: %s', pylint) |
| raise PylintError('Could not find pylint.') |
| |
| command = [pylint, '--output-format=parseable', '--disable=I'] |
| if pylintrc_file: |
| command += ['--rcfile={}'.format(pylintrc_file)] |
| command += changed_files |
| if executor: |
| _, stdout, _ = executor.exec_subprocess(command, cwd=cwd) |
| return stdout |
| |
| return subprocess.check_output(command, cwd=cwd) |
| |
| |
| def ParseLint(lines, cwd=None): |
| """Reads lines from lint output and inserts them into comments. |
| |
| Args: |
| lines: List of lint output lines to parse. |
| cwd: Base path relative to which parsed paths should be resolved. |
| Returns: |
| comments dictionary. |
| """ |
| comments = collections.defaultdict(list) |
| for line in lines: |
| match = re.match(LINT_WARNING_PATTERN, line) |
| if match: |
| warning = { |
| 'line': |
| match.group('line_num'), |
| 'message': |
| '{} [{}]'.format( |
| match.group('error_msg'), match.group('error_name')) |
| } |
| if cwd: |
| filename = os.path.relpath(match.group('filename'), cwd) |
| else: |
| filename = match.group('filename') |
| comments[filename].append(warning) |
| |
| return comments |