Source code

Revision control

Other Tools

1
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
2
# vim: set filetype=python:
3
# This Source Code Form is subject to the terms of the Mozilla Public
4
# License, v. 2.0. If a copy of the MPL was not distributed with this
5
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
from __future__ import absolute_import, print_function
8
9
import json
10
import os
11
import signal
12
import subprocess
13
import sys
14
15
sys.path.append(os.path.join(os.path.dirname(__file__), "eslint"))
16
from eslint import setup_helper
17
18
from mozbuild.nodeutil import find_node_executable
19
20
from mozlint import result
21
22
ESLINT_ERROR_MESSAGE = """
23
An error occurred running eslint. Please check the following error messages:
24
25
{}
26
""".strip()
27
28
ESLINT_NOT_FOUND_MESSAGE = """
29
Could not find eslint! We looked at the --binary option, at the ESLINT
30
environment variable, and then at your local node_modules path. Please Install
31
eslint and needed plugins with:
32
33
mach eslint --setup
34
35
and try again.
36
""".strip()
37
38
39
def setup(root, **lintargs):
40
setup_helper.set_project_root(root)
41
42
if not setup_helper.check_node_executables_valid():
43
return 1
44
45
return setup_helper.eslint_maybe_setup()
46
47
48
def lint(paths, config, binary=None, fix=None, setup=None, **lintargs):
49
"""Run eslint."""
50
log = lintargs['log']
51
setup_helper.set_project_root(lintargs['root'])
52
module_path = setup_helper.get_project_root()
53
54
# Valid binaries are:
55
# - Any provided by the binary argument.
56
# - Any pointed at by the ESLINT environmental variable.
57
# - Those provided by |mach lint --setup|.
58
59
if not binary:
60
binary, _ = find_node_executable()
61
62
if not binary:
63
print(ESLINT_NOT_FOUND_MESSAGE)
64
return 1
65
66
extra_args = lintargs.get('extra_args') or []
67
exclude_args = []
68
for path in config.get('exclude', []):
69
exclude_args.extend(['--ignore-pattern', os.path.relpath(path, lintargs['root'])])
70
71
cmd_args = [binary,
72
os.path.join(module_path, "node_modules", "eslint", "bin", "eslint.js"),
73
# This keeps ext as a single argument.
74
'--ext', '[{}]'.format(','.join(config['extensions'])),
75
'--format', 'json',
76
'--no-error-on-unmatched-pattern',
77
] + extra_args + exclude_args + paths
78
log.debug("Command: {}".format(' '.join(cmd_args)))
79
80
# eslint requires that --fix be set before the --ext argument.
81
if fix:
82
cmd_args.insert(2, '--fix')
83
84
shell = False
85
if os.environ.get('MSYSTEM') in ('MINGW32', 'MINGW64'):
86
# The eslint binary needs to be run from a shell with msys
87
shell = True
88
encoding = 'utf-8'
89
90
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
91
proc = subprocess.Popen(cmd_args,
92
shell=shell,
93
stdout=subprocess.PIPE,
94
stderr=subprocess.PIPE)
95
signal.signal(signal.SIGINT, orig)
96
97
try:
98
output, errors = proc.communicate()
99
except KeyboardInterrupt:
100
proc.kill()
101
return []
102
103
if errors:
104
errors = errors.decode(encoding, "replace")
105
print(ESLINT_ERROR_MESSAGE.format(errors))
106
107
if proc.returncode >= 2:
108
return 1
109
110
if not output:
111
return [] # no output means success
112
output = output.decode(encoding, "replace")
113
try:
114
jsonresult = json.loads(output)
115
except ValueError:
116
print(ESLINT_ERROR_MESSAGE.format(output))
117
return 1
118
119
results = []
120
for obj in jsonresult:
121
errors = obj['messages']
122
123
for err in errors:
124
err.update({
125
'hint': err.get('fix'),
126
'level': 'error' if err['severity'] == 2 else 'warning',
127
'lineno': err.get('line') or 0,
128
'path': obj['filePath'],
129
'rule': err.get('ruleId'),
130
})
131
results.append(result.from_config(config, **err))
132
133
return results