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 mach
.decorators
import Command
, CommandArgument
10 from mozbuild
.base
import BuildEnvironmentNotFoundException
11 from mozbuild
.base
import MachCommandConditions
as conditions
13 here
= os
.path
.abspath(os
.path
.dirname(__file__
))
15 os
.path
.join("tools", "rewriting", "Generated.txt"),
16 os
.path
.join("tools", "rewriting", "ThirdPartyPaths.txt"),
19 EXCLUSION_FILES_OPTIONAL
= []
20 thunderbird_excludes
= os
.path
.join("comm", "tools", "lint", "GlobalExclude.txt")
21 if os
.path
.exists(thunderbird_excludes
):
22 EXCLUSION_FILES_OPTIONAL
.append(thunderbird_excludes
)
24 GLOBAL_EXCLUDES
= ["**/node_modules", "tools/lint/test/files", ".hg", ".git"]
26 VALID_FORMATTERS
= {"black", "clang-format", "rustfmt"}
27 VALID_ANDROID_FORMATTERS
= {"android-format"}
29 # Code-review bot must index issues from the whole codebase when pushing
30 # to autoland or try repositories. In such cases, output warnings in the
31 # task's JSON artifact but do not fail if only warnings are found.
32 REPORT_WARNINGS
= os
.environ
.get("GECKO_HEAD_REPOSITORY", "").rstrip("/") in (
33 "https://hg.mozilla.org/mozilla-central",
34 "https://hg.mozilla.org/integration/autoland",
35 "https://hg.mozilla.org/try",
39 def setup_argument_parser():
40 from mozlint
import cli
42 return cli
.MozlintParser()
45 def get_global_excludes(**lintargs
):
47 excludes
= GLOBAL_EXCLUDES
[:]
48 topsrcdir
= lintargs
["root"]
50 # exclude top level paths that look like objdirs
54 for name
in os
.listdir(topsrcdir
)
55 if name
.startswith("obj") and os
.path
.isdir(name
)
59 if lintargs
.get("include_third-party"):
60 # For some linters, we want to include the thirdparty code too.
61 # Example: trojan-source linter should run also on third party code.
64 for path
in EXCLUSION_FILES
+ EXCLUSION_FILES_OPTIONAL
:
65 with
open(os
.path
.join(topsrcdir
, path
), "r") as fh
:
66 excludes
.extend([f
.strip() for f
in fh
.readlines()])
74 description
="Run linters.",
75 parser
=setup_argument_parser
,
76 virtualenv_name
="lint",
78 def lint(command_context
, *runargs
, **lintargs
):
80 command_context
.activate_virtualenv()
81 from mozlint
import cli
, parser
85 buildargs
["substs"] = copy
.deepcopy(dict(command_context
.substs
))
86 buildargs
["defines"] = copy
.deepcopy(dict(command_context
.defines
))
87 buildargs
["topobjdir"] = command_context
.topobjdir
88 lintargs
.update(buildargs
)
89 except BuildEnvironmentNotFoundException
:
92 lintargs
.setdefault("root", command_context
.topsrcdir
)
93 lintargs
["exclude"] = get_global_excludes(**lintargs
)
94 lintargs
["config_paths"].insert(0, here
)
95 lintargs
["virtualenv_bin_path"] = command_context
.virtualenv_manager
.bin_path
96 lintargs
["virtualenv_manager"] = command_context
.virtualenv_manager
97 if REPORT_WARNINGS
and lintargs
.get("show_warnings") is None:
98 lintargs
["show_warnings"] = "soft"
99 for path
in EXCLUSION_FILES
:
100 parser
.GLOBAL_SUPPORT_FILES
.append(
101 os
.path
.join(command_context
.topsrcdir
, path
)
104 "mach_command_context": command_context
,
106 return cli
.run(*runargs
, setupargs
=setupargs
, **lintargs
)
112 description
="Run eslint or help configure eslint for optimal development.",
118 help="Paths to file or directories to lint, like "
119 "'browser/' Defaults to the "
120 "current directory if not given.",
127 help="Configure eslint for optimal development.",
129 @CommandArgument("-b", "--binary", default
=None, help="Path to eslint binary.")
134 help="Request that eslint automatically fix errors, where possible.",
141 help="Specify an additional rule for ESLint to run, e.g. 'no-new-object: error'",
145 nargs
=argparse
.REMAINDER
,
146 help="Extra args that will be forwarded to eslint.",
148 def eslint(command_context
, paths
, extra_args
=[], **kwargs
):
149 command_context
._mach
_context
.commands
.dispatch(
151 command_context
._mach
_context
,
162 description
="Format files, alternative to 'lint --fix' ",
163 parser
=setup_argument_parser
,
165 def format_files(command_context
, paths
, extra_args
=[], **kwargs
):
166 linters
= kwargs
["linters"]
168 formatters
= VALID_FORMATTERS
169 if conditions
.is_android(command_context
):
170 formatters |
= VALID_ANDROID_FORMATTERS
175 invalid_linters
= set(linters
) - formatters
178 "error: One or more linters passed are not valid formatters. "
179 "Note that only the following linters are valid formatters:"
181 print("\n".join(sorted(formatters
)))
184 kwargs
["linters"] = list(linters
)
187 command_context
._mach
_context
.commands
.dispatch(
188 "lint", command_context
._mach
_context
, paths
=paths
, argv
=extra_args
, **kwargs