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 re
12
import signal
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 mozprocess import ProcessHandler
21
22
from mozlint import result
23
24
ESLINT_ERROR_MESSAGE = """
25
An error occurred running eslint. Please check the following error messages:
26
27
{}
28
""".strip()
29
30
ESLINT_NOT_FOUND_MESSAGE = """
31
Could not find eslint! We looked at the --binary option, at the ESLINT
32
environment variable, and then at your local node_modules path. Please Install
33
eslint and needed plugins with:
34
35
mach eslint --setup
36
37
and try again.
38
""".strip()
39
40
41
def setup(root, **lintargs):
42
setup_helper.set_project_root(root)
43
44
if not setup_helper.check_node_executables_valid():
45
return 1
46
47
return setup_helper.eslint_maybe_setup()
48
49
50
def lint(paths, config, binary=None, fix=None, setup=None, **lintargs):
51
"""Run eslint."""
52
log = lintargs['log']
53
setup_helper.set_project_root(lintargs['root'])
54
module_path = setup_helper.get_project_root()
55
56
# Valid binaries are:
57
# - Any provided by the binary argument.
58
# - Any pointed at by the ESLINT environmental variable.
59
# - Those provided by |mach lint --setup|.
60
61
if not binary:
62
binary, _ = find_node_executable()
63
64
if not binary:
65
print(ESLINT_NOT_FOUND_MESSAGE)
66
return 1
67
68
extra_args = lintargs.get('extra_args') or []
69
exclude_args = []
70
for path in config.get('exclude', []):
71
exclude_args.extend(['--ignore-pattern', os.path.relpath(path, lintargs['root'])])
72
73
cmd_args = [binary,
74
os.path.join(module_path, "node_modules", "eslint", "bin", "eslint.js"),
75
# This keeps ext as a single argument.
76
'--ext', '[{}]'.format(','.join(config['extensions'])),
77
'--format', 'json',
78
] + extra_args + exclude_args + paths
79
log.debug("Command: {}".format(' '.join(cmd_args)))
80
81
# eslint requires that --fix be set before the --ext argument.
82
if fix:
83
cmd_args.insert(2, '--fix')
84
85
shell = False
86
if os.environ.get('MSYSTEM') in ('MINGW32', 'MINGW64'):
87
# The eslint binary needs to be run from a shell with msys
88
shell = True
89
90
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
91
proc = ProcessHandler(cmd_args, env=os.environ, stream=None,
92
shell=shell, universal_newlines=True)
93
proc.run()
94
signal.signal(signal.SIGINT, orig)
95
96
try:
97
proc.wait()
98
except KeyboardInterrupt:
99
proc.kill()
100
return []
101
102
if not proc.output:
103
return [] # no output means success
104
105
try:
106
jsonresult = json.loads(proc.output[0])
107
except ValueError:
108
output = "\n".join(proc.output)
109
if re.search(r'No files matching the pattern "(.*)" were found.', output):
110
print("warning: no files to lint (eslint)")
111
return []
112
113
print(ESLINT_ERROR_MESSAGE.format(output))
114
return 1
115
116
results = []
117
for obj in jsonresult:
118
errors = obj['messages']
119
120
for err in errors:
121
err.update({
122
'hint': err.get('fix'),
123
'level': 'error' if err['severity'] == 2 else 'warning',
124
'lineno': err.get('line') or 0,
125
'path': obj['filePath'],
126
'rule': err.get('ruleId'),
127
})
128
results.append(result.from_config(config, **err))
129
130
return results