forked from zulip/zulip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlint
executable file
·203 lines (168 loc) · 7.05 KB
/
lint
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
194
195
196
197
198
199
200
201
202
203
#!/usr/bin/env python3
from __future__ import print_function
from __future__ import absolute_import
import logging
import os
import sys
import argparse
import subprocess
from linter_lib.printer import print_err, colors
# check for the venv
from lib import sanity_check
sanity_check.check_venv(__file__)
import lister
from typing import cast, Callable, Dict, Iterator, List
def run_parallel(lint_functions):
# type: (Dict[str, Callable[[], int]]) -> bool
pids = []
for name, func in lint_functions.items():
pid = os.fork()
if pid == 0:
logging.info("start " + name)
result = func()
logging.info("finish " + name)
sys.stdout.flush()
sys.stderr.flush()
os._exit(result)
pids.append(pid)
failed = False
for pid in pids:
(_, status) = os.waitpid(pid, 0)
if status != 0:
failed = True
return failed
def run():
# type: () -> None
parser = argparse.ArgumentParser()
parser.add_argument('--force', default=False,
action="store_true",
help='Run tests despite possible problems.')
parser.add_argument('--full',
action='store_true',
help='Check some things we typically ignore')
parser.add_argument('--no-gitlint',
action='store_true',
help='Disable gitlint')
parser.add_argument('--modified', '-m',
action='store_true',
help='Only check modified files')
parser.add_argument('--verbose', '-v',
action='store_true',
help='Print verbose timing output')
parser.add_argument('targets',
nargs='*',
help='Specify directories to check')
limited_tests_group = parser.add_mutually_exclusive_group()
limited_tests_group.add_argument('--frontend',
action='store_true',
help='Only check files relevant to frontend')
limited_tests_group.add_argument('--backend',
action='store_true',
help='Only check files relevant to backend')
args = parser.parse_args()
tools_dir = os.path.dirname(os.path.abspath(__file__))
root_dir = os.path.dirname(tools_dir)
sys.path.insert(0, root_dir)
from tools.linter_lib.custom_check import build_custom_checkers
from tools.linter_lib.exclude import EXCLUDED_FILES
from tools.linter_lib.pyflakes import check_pyflakes
from tools.linter_lib.pep8 import check_pep8
from tools.lib.test_script import (
get_provisioning_status,
)
os.chdir(root_dir)
if not args.force:
ok, msg = get_provisioning_status()
if not ok:
print(msg)
print('If you really know what you are doing, use --force to run anyway.')
sys.exit(1)
backend_file_types = ['py', 'sh', 'pp', 'json', 'md', 'txt', 'text', 'yaml', 'rst']
frontend_file_types = ['js', 'css', 'handlebars', 'html']
file_types = backend_file_types + frontend_file_types
if args.backend:
file_types = backend_file_types
if args.frontend:
file_types = frontend_file_types
by_lang = cast(Dict[str, List[str]],
lister.list_files(args.targets, modified_only=args.modified,
ftypes=file_types,
use_shebang=True, group_by_ftype=True, exclude=EXCLUDED_FILES))
# Invoke the appropriate lint checker for each language,
# and also check files for extra whitespace.
logging.basicConfig(format="%(asctime)s %(message)s")
logger = logging.getLogger()
if args.verbose:
logger.setLevel(logging.INFO)
else:
logger.setLevel(logging.WARNING)
check_custom_checks_py, check_custom_checks_nonpy = build_custom_checkers(by_lang)
lint_functions = {} # type: Dict[str, Callable[[], int]]
def lint(func):
# type: (Callable[[], int]) -> Callable[[], int]
lint_functions[func.__name__] = func
return func
def external_linter(name, command, target_langs=[]):
# type: (str, List[str], List[str]) -> None
"""Registers an external linter program to be run as part of the
linter. This program will be passed the subset of files being
linted that have extensions in target_langs. If there are no
such files, exits without doing anything.
If target_langs is empty, just runs the linter unconditionally.
"""
color = next(colors)
def run_linter():
# type: () -> int
targets = [] # type: List[str]
if len(target_langs) != 0:
targets = [target for lang in target_langs for target in by_lang[lang]]
if len(targets) == 0:
# If we this linter has a list of languages, and
# no files in those languages are to be checked,
# then we can safely return success without
# invoking the external linter.
return 0
p = subprocess.Popen(command + targets,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
assert p.stdout # use of subprocess.PIPE indicates non-None
for line in iter(p.stdout.readline, b''):
print_err(name, color, line)
return p.wait() # Linter exit code
lint_functions[name] = run_linter
external_linter('add_class', ['tools/find-add-class'], ['js'])
external_linter('css', ['tools/check-css'], ['css'])
external_linter('eslint', ['node', 'node_modules/.bin/eslint', '--quiet', '--cache'], ['js'])
external_linter('tslint', ['node', 'node_modules/.bin/tslint', '-c',
'static/ts/tslint.json'], ['ts'])
external_linter('puppet', ['puppet', 'parser', 'validate'], ['pp'])
external_linter('templates', ['tools/check-templates'], ['handlebars', 'html'])
external_linter('urls', ['tools/check-urls'], ['py'])
external_linter('swagger', ['node', 'tools/check-swagger'], ['yaml'])
# Disabled check for imperative mood until it is stabilized
if not args.no_gitlint:
external_linter('commit_messages', ['tools/commit-message-lint'])
@lint
def custom_py():
# type: () -> int
failed = check_custom_checks_py()
return 1 if failed else 0
@lint
def custom_nonpy():
# type: () -> int
failed = check_custom_checks_nonpy()
return 1 if failed else 0
@lint
def pyflakes():
# type: () -> int
failed = check_pyflakes(args, by_lang)
return 1 if failed else 0
@lint
def pep8():
# type: () -> int
failed = check_pep8(by_lang['py'])
return 1 if failed else 0
failed = run_parallel(lint_functions)
sys.exit(1 if failed else 0)
if __name__ == '__main__':
run()