1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 from mozfile
import which
10 from mozlint
import result
11 from mozlint
.pathutils
import expand_exclusions
20 abspath
= os
.path
.abspath(os
.path
.dirname(__file__
))
21 rstcheck_requirements_file
= os
.path
.join(abspath
, "requirements.txt")
25 RSTCHECK_NOT_FOUND
= """
26 Could not find rstcheck! Install rstcheck and try again.
28 $ pip install -U --require-hashes -r {}
30 rstcheck_requirements_file
33 RSTCHECK_INSTALL_ERROR
= """
34 Unable to install required version of rstcheck
35 Try to install it manually with:
36 $ pip install -U --require-hashes -r {}
38 rstcheck_requirements_file
41 RSTCHECK_FORMAT_REGEX
= re
.compile(r
"(.*):(.*): \(.*/([0-9]*)\) (.*)$")
42 IGNORE_NOT_REF_LINK_UPSTREAM_BUG
= re
.compile(
43 r
"Hyperlink target (.*) is not referenced."
47 def setup(root
, **lintargs
):
48 virtualenv_manager
= lintargs
["virtualenv_manager"]
50 virtualenv_manager
.install_pip_requirements(
51 rstcheck_requirements_file
, quiet
=True
53 except subprocess
.CalledProcessError
:
54 print(RSTCHECK_INSTALL_ERROR
)
58 def get_rstcheck_binary():
60 Returns the path of the first rstcheck binary available
61 if not found returns None
63 binary
= os
.environ
.get("RSTCHECK")
67 return which("rstcheck")
70 def parse_with_split(errors
):
71 match
= RSTCHECK_FORMAT_REGEX
.match(errors
)
72 filename
, lineno
, level
, message
= match
.groups()
74 return filename
, lineno
, level
, message
77 def lint(files
, config
, **lintargs
):
79 config
["root"] = lintargs
["root"]
80 paths
= expand_exclusions(files
, config
, config
["root"])
83 binary
= get_rstcheck_binary()
85 "--ignore-language=cpp,json",
86 "--ignore-roles=searchfox",
90 cmdargs
= [which("python"), binary
] + rstcheck_options
+ paths
[:chunk_size
]
91 log
.debug("Command: {}".format(" ".join(cmdargs
)))
93 proc
= subprocess
.Popen(
95 stdout
=subprocess
.PIPE
,
96 stderr
=subprocess
.PIPE
,
98 universal_newlines
=True,
100 all_errors
= proc
.communicate()[1]
101 for errors
in all_errors
.split("\n"):
103 filename
, lineno
, level
, message
= parse_with_split(errors
)
104 if not IGNORE_NOT_REF_LINK_UPSTREAM_BUG
.match(message
):
105 # Ignore an upstream bug
106 # https://github.com/myint/rstcheck/issues/19
111 "level": "error" if int(level
) >= 2 else "warning",
113 results
.append(result
.from_config(config
, **res
))
114 paths
= paths
[chunk_size
:]