1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
# 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 https://mozilla.org/MPL/2.0/.
import json
import os
import signal
import subprocess
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "eslint"))
from eslint import setup_helper
from mozbuild.nodeutil import check_node_executables_valid, find_node_executable
from mozlint import result
from mozlint.pathutils import expand_exclusions
here = os.path.abspath(os.path.dirname(__file__))
topsrcdir = os.path.join(here, "..", "..", "..")
NODE_LICENSES_ERROR_MESSAGE = """
An error occurred running license-checker. Please check the following error messages:
{}
""".strip()
NODE_LICENSES_NOT_FOUND_MESSAGE = """
Could not find license-checker! We looked at the --binary option and at your
local node_modules path. Please install license checker and needed plugins with:
mach lint -l license-checker --setup
and try again.
""".strip()
def setup(root, **lintargs):
setup_helper.set_project_root(root)
if not check_node_executables_valid():
return 1
return setup_helper.eslint_maybe_setup()
def lint(paths, config, binary=None, skip_reinstall=False, **lintargs):
setup_helper.set_project_root(lintargs["root"])
paths = list(expand_exclusions(paths, config, lintargs["root"]))
issues = []
for path in paths:
dirname = os.path.dirname(path)
# Always ensure node_modules for the directory is up to date, so that we
# are checking against the package-lock versions. Note that the checker
# will not report if node_modules is missing.
# We skip the setup in a few scenarios:
# - For tests (skip_reinstall=True)
# - In automation, because the node_modules are installed from the
# toolchains.
# - When the package is the top-level package.json, because the top level
# node_modules is looked after by the setup, and we don't want to be
# removing it from underneath ourselves.
if (
not skip_reinstall
and not os.environ.get("MOZ_AUTOMATION")
and dirname != lintargs["root"]
):
status = setup_helper.package_setup(
dirname, os.path.basename(dirname), skip_logging=True
)
if status:
issues.append(
result.from_config(
config,
**{
"path": path,
"message": "Unable to install node_modules for this package, try running 'npm ci' in the directory to debug",
"level": "error",
},
)
)
output = run_license_checker(binary, path, lintargs)
if output == 1:
return output
def check_license(package, license):
if not is_acceptable(config, package, license):
res = {
"path": path,
"message": "Included (sub-)dependency "
+ package
+ " needs license "
+ license
+ " checking for acceptability",
"level": "error",
}
issues.append(result.from_config(config, **res))
for package in output:
if type(output[package]["licenses"]) is list:
for license in output[package]["licenses"]:
check_license(package, license)
else:
check_license(package, output[package]["licenses"])
return {"results": issues, "fixed": 0}
def run_license_checker(binary, path, lintargs):
log = lintargs["log"]
module_path = setup_helper.get_project_root()
if not binary:
binary, _ = find_node_executable()
if not binary:
log.error(NODE_LICENSES_NOT_FOUND_MESSAGE)
return 1
extra_args = lintargs.get("extra_args") or []
cmd_args = [
binary,
os.path.join(
module_path,
"node_modules",
"license-checker-rseidelsohn",
"bin",
"license-checker-rseidelsohn",
),
"--json",
"--start",
os.path.dirname(path),
"--excludePrivatePackages",
] + extra_args
log.debug("license-checker command: {}".format(" ".join(cmd_args)))
shell = False
if is_windows():
# The license checker binary needs to be run from a shell with msys
shell = True
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
proc = subprocess.run(
cmd_args, shell=shell, capture_output=True, text=True, check=False
)
signal.signal(signal.SIGINT, orig)
errors = proc.stderr
if proc.returncode != 0 or (errors and "An error has occurred:" in errors):
print("license-checker reported an issue.")
print(errors)
return 1
output = proc.stdout
if not output:
print("license-checker reported no output.")
return 1
try:
jsonresult = json.loads(output)
except ValueError:
print(NODE_LICENSES_ERROR_MESSAGE.format(output))
return 1
return jsonresult
def is_acceptable(config, package, licenses):
if licenses in config["accepted-test-licenses"]:
return True
package_name = package.split("@")[0]
if package_name in config["known-packages"]:
if config["known-packages"][package_name] == licenses:
return True
return False
def is_windows():
return (
os.environ.get("MSYSTEM") in ("MINGW32", "MINGW64")
or "MOZILLABUILD" in os.environ
)
|