forked from mirrors/gecko-dev
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D162660
133 lines
3.7 KiB
Python
133 lines
3.7 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import json
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
|
|
from mach.site import InstallPipRequirementsException
|
|
from mozlint import result
|
|
from mozlint.pathutils import expand_exclusions
|
|
from mozprocess import ProcessHandler
|
|
|
|
here = os.path.abspath(os.path.dirname(__file__))
|
|
PYLINT_REQUIREMENTS_PATH = os.path.join(here, "pylint_requirements.txt")
|
|
|
|
PYLINT_NOT_FOUND = """
|
|
Could not find pylint! Install pylint and try again.
|
|
|
|
$ pip install -U --require-hashes -r {}
|
|
""".strip().format(
|
|
PYLINT_REQUIREMENTS_PATH
|
|
)
|
|
|
|
|
|
PYLINT_INSTALL_ERROR = """
|
|
Unable to install correct version of pylint
|
|
Try to install it manually with:
|
|
$ pip install -U --require-hashes -r {}
|
|
""".strip().format(
|
|
PYLINT_REQUIREMENTS_PATH
|
|
)
|
|
|
|
|
|
class PylintProcess(ProcessHandler):
|
|
def __init__(self, config, *args, **kwargs):
|
|
self.config = config
|
|
kwargs["stream"] = False
|
|
kwargs["universal_newlines"] = True
|
|
ProcessHandler.__init__(self, *args, **kwargs)
|
|
|
|
def run(self, *args, **kwargs):
|
|
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
ProcessHandler.run(self, *args, **kwargs)
|
|
signal.signal(signal.SIGINT, orig)
|
|
|
|
|
|
def setup(root, **lintargs):
|
|
virtualenv_manager = lintargs["virtualenv_manager"]
|
|
try:
|
|
virtualenv_manager.install_pip_requirements(
|
|
PYLINT_REQUIREMENTS_PATH,
|
|
quiet=True,
|
|
)
|
|
except (subprocess.CalledProcessError, InstallPipRequirementsException):
|
|
print(PYLINT_INSTALL_ERROR)
|
|
return 1
|
|
|
|
|
|
def get_pylint_binary():
|
|
return "pylint"
|
|
|
|
|
|
def run_process(config, cmd):
|
|
proc = PylintProcess(config, cmd)
|
|
proc.run()
|
|
try:
|
|
proc.wait()
|
|
except KeyboardInterrupt:
|
|
proc.kill()
|
|
|
|
return proc.output
|
|
|
|
|
|
def parse_issues(log, config, issues_json, path):
|
|
results = []
|
|
|
|
try:
|
|
issues = json.loads(issues_json)
|
|
except json.decoder.JSONDecodeError:
|
|
log.debug("Could not parse the output:")
|
|
log.debug("pylint output: {}".format(issues_json))
|
|
return []
|
|
|
|
for issue in issues:
|
|
res = {
|
|
"path": issue["path"],
|
|
"level": issue["type"],
|
|
"lineno": issue["line"],
|
|
"column": issue["column"],
|
|
"message": issue["message"],
|
|
"rule": issue["message-id"],
|
|
}
|
|
results.append(result.from_config(config, **res))
|
|
return results
|
|
|
|
|
|
def get_pylint_version(binary):
|
|
return subprocess.check_output(
|
|
[binary, "--version"],
|
|
universal_newlines=True,
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
|
|
|
|
def lint(paths, config, **lintargs):
|
|
log = lintargs["log"]
|
|
|
|
binary = get_pylint_binary()
|
|
|
|
log = lintargs["log"]
|
|
paths = list(expand_exclusions(paths, config, lintargs["root"]))
|
|
|
|
cmd_args = [binary]
|
|
results = []
|
|
|
|
# list from https://code.visualstudio.com/docs/python/linting#_pylint
|
|
# And ignore a bit more elements
|
|
cmd_args += [
|
|
"-fjson",
|
|
"--disable=all",
|
|
"--enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode,no-else-return", # NOQA: E501
|
|
"--disable=import-error,no-member",
|
|
]
|
|
|
|
base_command = cmd_args + paths
|
|
log.debug("Command: {}".format(" ".join(cmd_args)))
|
|
log.debug("pylint version: {}".format(get_pylint_version(binary)))
|
|
output = " ".join(run_process(config, base_command))
|
|
results = parse_issues(log, config, str(output), [])
|
|
|
|
return results
|