# 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 os
import re
import subprocess
from mozfile
import which
from mozlint
import result
from mozlint.pathutils
import expand_exclusions
# Error Levels
# (0, 'debug')
# (1, 'info')
# (2, 'warning')
# (3, 'error')
# (4, 'severe')
abspath = os.path.abspath(os.path.dirname(__file__))
rstcheck_requirements_file = os.path.join(abspath,
"requirements.txt")
results = []
RSTCHECK_NOT_FOUND =
"""
Could
not find rstcheck! Install rstcheck
and try again.
$ pip install -U --require-hashes -r {}
""".strip().format(
rstcheck_requirements_file
)
RSTCHECK_INSTALL_ERROR =
"""
Unable to install required version of rstcheck
Try to install it manually
with:
$ pip install -U --require-hashes -r {}
""".strip().format(
rstcheck_requirements_file
)
RSTCHECK_FORMAT_REGEX = re.compile(r
"(.*):(.*): \(.*/([0-9]*)\) (.*)$")
def get_rstcheck_binary():
"""
Returns the path of the first rstcheck binary available
if not found returns
None
"""
binary = os.environ.get(
"RSTCHECK")
if binary:
return binary
return which(
"rstcheck")
def parse_with_split(errors):
match = RSTCHECK_FORMAT_REGEX.match(errors)
if not match:
return None
filename, lineno, level, message = match.groups()
return filename, lineno, level, message
def lint(files, config, **lintargs):
log = lintargs[
"log"]
config[
"root"] = lintargs[
"root"]
paths = expand_exclusions(files, config, config[
"root"])
paths = list(paths)
chunk_size = 50
binary = get_rstcheck_binary()
while paths:
# Config for rstcheck is stored in `/.rstcheck.cfg`.
cmdargs = [which(
"python"), binary] + paths[:chunk_size]
log.debug(
"Command: {}".format(
" ".join(cmdargs)))
proc = subprocess.Popen(
cmdargs,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=os.environ,
universal_newlines=
True,
)
all_errors = proc.communicate()[1]
for errors
in all_errors.split(
"\n"):
if len(errors) > 1:
split_result = parse_with_split(errors)
if split_result:
filename, lineno, level, message = split_result
res = {
"path": filename,
"message": message,
"lineno": lineno,
"level":
"error" if int(level) >= 2
else "warning",
}
results.append(result.from_config(config, **res))
paths = paths[chunk_size:]
return results