# 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 re
import signal
import subprocess
from mozlint
import result
here = os.path.abspath(os.path.dirname(__file__))
CONFIG_PATH = os.path.join(os.path.dirname(here),
"rumdl.toml")
# rumdl prints this plain string (not JSON) to stdout when invoked on a path
# that contains no markdown files, even with --output-format=json.
NO_MARKDOWN_OUTPUT =
"No markdown files found to check."
FIXED_RE = re.compile(r
"Fixed (\d+)/\d+ issues?")
VERSION_RE = re.compile(r
"rumdl[^\d]*([0-9][0-9.]*)")
def get_rumdl_version(binary):
try:
output = subprocess.check_output(
[binary,
"--version"],
stderr=subprocess.STDOUT,
text=
True,
)
except subprocess.CalledProcessError
as e:
output = e.output
match = VERSION_RE.search(output)
if match:
return match.group(
1)
print(f
"Error: Could not parse the version '{output}'")
def run_process(cmd, log):
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=
True
)
signal.signal(signal.SIGINT, orig)
try:
stdout, stderr = proc.communicate()
except KeyboardInterrupt:
proc.kill()
return "", -
1
for line
in stderr.splitlines():
if line:
log.debug(line)
return stdout, proc.returncode
def lint(paths, config, log, **lintargs):
if not paths:
return {
"results": [],
"fixed":
0}
log.debug(f
"rumdl version {get_rumdl_version('rumdl')}")
base_args = [
"rumdl",
"check", f
"--config={CONFIG_PATH}"]
if config.get(
"exclude"):
base_args.append(f
"--exclude={','.join(config['exclude'])}")
fixed =
0
if lintargs.get(
"fix"):
fix_args = base_args + [
"--fix"] + paths
log.debug(f
"Running --fix: {fix_args}")
output, _ = run_process(fix_args, log)
match = FIXED_RE.search(output)
if match:
fixed = int(match.group(
1))
args = base_args + [
"--output-format=json"] + paths
log.debug(f
"Running with args: {args}")
output, _ = run_process(args, log)
output = output.strip()
if not output
or output == NO_MARKDOWN_OUTPUT:
return {
"results": [],
"fixed": fixed}
try:
issues = json.loads(output)
except json.JSONDecodeError:
log.error(f
"could not parse output: {output}")
return {
"results": [],
"fixed": fixed}
results = [
result.from_config(
config,
path=issue.get(
"file"),
lineno=issue.get(
"line",
0),
column=issue.get(
"column",
0),
message=issue.get(
"message",
""),
rule=issue.get(
"rule"),
level=
"warning" if issue.get(
"severity") ==
"warning" else "error",
)
for issue
in issues
]
return {
"results": results,
"fixed": fixed}