100 lines
3.3 KiB
Python
100 lines
3.3 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 bisect
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from mozlint import result
|
|
from mozlint.pathutils import expand_exclusions
|
|
|
|
|
|
def in_sorted_list(l, x):
|
|
i = bisect.bisect_left(l, x)
|
|
return i < len(l) and l[i] == x
|
|
|
|
|
|
def handle_clippy_msg(config, line, log, base_path, files):
|
|
try:
|
|
detail = json.loads(line)
|
|
if "message" in detail:
|
|
p = detail["target"]["src_path"]
|
|
detail = detail["message"]
|
|
if "level" in detail:
|
|
if (
|
|
detail["level"] == "error" or detail["level"] == "failure-note"
|
|
) and not detail["code"]:
|
|
log.debug(
|
|
"Error outside of clippy."
|
|
"This means that the build failed. Therefore, skipping this"
|
|
)
|
|
log.debug("File = {} / Detail = {}".format(p, detail))
|
|
return
|
|
# We are in a clippy warning
|
|
if len(detail["spans"]) == 0:
|
|
# For some reason, at the end of the summary, we can
|
|
# get the following line
|
|
# {'rendered': 'warning: 5 warnings emitted\n\n', 'children':
|
|
# [], 'code': None, 'level': 'warning', 'message':
|
|
# '5 warnings emitted', 'spans': []}
|
|
# if this is the case, skip it
|
|
log.debug(
|
|
"Skipping the summary line {} for file {}".format(detail, p)
|
|
)
|
|
return
|
|
|
|
l = detail["spans"][0]
|
|
if not in_sorted_list(files, p):
|
|
return
|
|
p = os.path.join(base_path, l["file_name"])
|
|
res = {
|
|
"path": p,
|
|
"level": detail["level"],
|
|
"lineno": l["line_start"],
|
|
"column": l["column_start"],
|
|
"message": detail["message"],
|
|
"hint": detail["rendered"],
|
|
"rule": detail["code"]["code"],
|
|
"lineoffset": l["line_end"] - l["line_start"],
|
|
}
|
|
return result.from_config(config, **res)
|
|
|
|
except json.decoder.JSONDecodeError:
|
|
log.debug("Could not parse the output:")
|
|
log.debug("clippy output: {}".format(line))
|
|
return
|
|
|
|
|
|
def lint(paths, config, fix=None, **lintargs):
|
|
files = list(expand_exclusions(paths, config, lintargs["root"]))
|
|
files.sort()
|
|
log = lintargs["log"]
|
|
results = []
|
|
mach_path = lintargs["root"] + "/mach"
|
|
march_cargo_process = subprocess.Popen(
|
|
[
|
|
sys.executable,
|
|
mach_path,
|
|
"--log-no-times",
|
|
"cargo",
|
|
"clippy",
|
|
"--",
|
|
"--message-format=json",
|
|
],
|
|
stdout=subprocess.PIPE,
|
|
text=True,
|
|
)
|
|
for l in march_cargo_process.stdout:
|
|
r = handle_clippy_msg(config, l, log, lintargs["root"], files)
|
|
if r is not None:
|
|
results.append(r)
|
|
march_cargo_process.wait()
|
|
|
|
if fix:
|
|
log.error("Rust linting in mach does not support --fix")
|
|
|
|
return results
|