Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: third_party/closure_linter/closure_linter/gjslint.py

Issue 2592193002: Remove closure_linter from Chrome (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2007 The Closure Linter Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS-IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """Checks JavaScript files for common style guide violations.
17
18 gjslint.py is designed to be used as a PRESUBMIT script to check for javascript
19 style guide violations. As of now, it checks for the following violations:
20
21 * Missing and extra spaces
22 * Lines longer than 80 characters
23 * Missing newline at end of file
24 * Missing semicolon after function declaration
25 * Valid JsDoc including parameter matching
26
27 Someday it will validate to the best of its ability against the entirety of the
28 JavaScript style guide.
29
30 This file is a front end that parses arguments and flags. The core of the code
31 is in tokenizer.py and checker.py.
32 """
33
34 __author__ = ('robbyw@google.com (Robert Walker)',
35 'ajp@google.com (Andy Perelson)',
36 'nnaze@google.com (Nathan Naze)',)
37
38 import errno
39 import itertools
40 import os
41 import platform
42 import re
43 import sys
44 import time
45
46 import gflags as flags
47
48 from closure_linter import errorrecord
49 from closure_linter import runner
50 from closure_linter.common import erroraccumulator
51 from closure_linter.common import simplefileflags as fileflags
52
53 # Attempt import of multiprocessing (should be available in Python 2.6 and up).
54 try:
55 # pylint: disable=g-import-not-at-top
56 import multiprocessing
57 except ImportError:
58 multiprocessing = None
59
60 FLAGS = flags.FLAGS
61 flags.DEFINE_boolean('unix_mode', False,
62 'Whether to emit warnings in standard unix format.')
63 flags.DEFINE_boolean('beep', True, 'Whether to beep when errors are found.')
64 flags.DEFINE_boolean('time', False, 'Whether to emit timing statistics.')
65 flags.DEFINE_boolean('quiet', False, 'Whether to minimize logged messages. '
66 'Most useful for per-file linting, such as that performed '
67 'by the presubmit linter service.')
68 flags.DEFINE_boolean('check_html', False,
69 'Whether to check javascript in html files.')
70 flags.DEFINE_boolean('summary', False,
71 'Whether to show an error count summary.')
72 flags.DEFINE_list('additional_extensions', None, 'List of additional file '
73 'extensions (not js) that should be treated as '
74 'JavaScript files.')
75 flags.DEFINE_boolean('multiprocess',
76 platform.system() is 'Linux' and bool(multiprocessing),
77 'Whether to attempt parallelized linting using the '
78 'multiprocessing module. Enabled by default on Linux '
79 'if the multiprocessing module is present (Python 2.6+). '
80 'Otherwise disabled by default. '
81 'Disabling may make debugging easier.')
82 flags.ADOPT_module_key_flags(fileflags)
83 flags.ADOPT_module_key_flags(runner)
84
85
86 GJSLINT_ONLY_FLAGS = ['--unix_mode', '--beep', '--nobeep', '--time',
87 '--check_html', '--summary', '--quiet']
88
89
90
91 def _MultiprocessCheckPaths(paths):
92 """Run _CheckPath over mutltiple processes.
93
94 Tokenization, passes, and checks are expensive operations. Running in a
95 single process, they can only run on one CPU/core. Instead,
96 shard out linting over all CPUs with multiprocessing to parallelize.
97
98 Args:
99 paths: paths to check.
100
101 Yields:
102 errorrecord.ErrorRecords for any found errors.
103 """
104
105 pool = multiprocessing.Pool()
106
107 path_results = pool.imap(_CheckPath, paths)
108 for results in path_results:
109 for result in results:
110 yield result
111
112 # Force destruct before returning, as this can sometimes raise spurious
113 # "interrupted system call" (EINTR), which we can ignore.
114 try:
115 pool.close()
116 pool.join()
117 del pool
118 except OSError as err:
119 if err.errno is not errno.EINTR:
120 raise err
121
122
123 def _CheckPaths(paths):
124 """Run _CheckPath on all paths in one thread.
125
126 Args:
127 paths: paths to check.
128
129 Yields:
130 errorrecord.ErrorRecords for any found errors.
131 """
132
133 for path in paths:
134 results = _CheckPath(path)
135 for record in results:
136 yield record
137
138
139 def _CheckPath(path):
140 """Check a path and return any errors.
141
142 Args:
143 path: paths to check.
144
145 Returns:
146 A list of errorrecord.ErrorRecords for any found errors.
147 """
148
149 error_handler = erroraccumulator.ErrorAccumulator()
150 runner.Run(path, error_handler)
151
152 make_error_record = lambda err: errorrecord.MakeErrorRecord(path, err)
153 return map(make_error_record, error_handler.GetErrors())
154
155
156 def _GetFilePaths(argv):
157 suffixes = ['.js']
158 if FLAGS.additional_extensions:
159 suffixes += ['.%s' % ext for ext in FLAGS.additional_extensions]
160 if FLAGS.check_html:
161 suffixes += ['.html', '.htm']
162 return fileflags.GetFileList(argv, 'JavaScript', suffixes)
163
164
165 # Error printing functions
166
167
168 def _PrintFileSummary(paths, records):
169 """Print a detailed summary of the number of errors in each file."""
170
171 paths = list(paths)
172 paths.sort()
173
174 for path in paths:
175 path_errors = [e for e in records if e.path == path]
176 print '%s: %d' % (path, len(path_errors))
177
178
179 def _PrintFileSeparator(path):
180 print '----- FILE : %s -----' % path
181
182
183 def _PrintSummary(paths, error_records):
184 """Print a summary of the number of errors and files."""
185
186 error_count = len(error_records)
187 all_paths = set(paths)
188 all_paths_count = len(all_paths)
189
190 if error_count is 0:
191 print '%d files checked, no errors found.' % all_paths_count
192
193 new_error_count = len([e for e in error_records if e.new_error])
194
195 error_paths = set([e.path for e in error_records])
196 error_paths_count = len(error_paths)
197 no_error_paths_count = all_paths_count - error_paths_count
198
199 if (error_count or new_error_count) and not FLAGS.quiet:
200 error_noun = 'error' if error_count == 1 else 'errors'
201 new_error_noun = 'error' if new_error_count == 1 else 'errors'
202 error_file_noun = 'file' if error_paths_count == 1 else 'files'
203 ok_file_noun = 'file' if no_error_paths_count == 1 else 'files'
204 print ('Found %d %s, including %d new %s, in %d %s (%d %s OK).' %
205 (error_count,
206 error_noun,
207 new_error_count,
208 new_error_noun,
209 error_paths_count,
210 error_file_noun,
211 no_error_paths_count,
212 ok_file_noun))
213
214
215 def _PrintErrorRecords(error_records):
216 """Print error records strings in the expected format."""
217
218 current_path = None
219 for record in error_records:
220
221 if current_path != record.path:
222 current_path = record.path
223 if not FLAGS.unix_mode:
224 _PrintFileSeparator(current_path)
225
226 print record.error_string
227
228
229 def _FormatTime(t):
230 """Formats a duration as a human-readable string.
231
232 Args:
233 t: A duration in seconds.
234
235 Returns:
236 A formatted duration string.
237 """
238 if t < 1:
239 return '%dms' % round(t * 1000)
240 else:
241 return '%.2fs' % t
242
243
244
245
246 def main(argv=None):
247 """Main function.
248
249 Args:
250 argv: Sequence of command line arguments.
251 """
252 if argv is None:
253 argv = flags.FLAGS(sys.argv)
254
255 if FLAGS.time:
256 start_time = time.time()
257
258 # Emacs sets the environment variable INSIDE_EMACS in the subshell.
259 # Request Unix mode as emacs will expect output to be in Unix format
260 # for integration.
261 # See https://www.gnu.org/software/emacs/manual/html_node/emacs/
262 # Interactive-Shell.html
263 if 'INSIDE_EMACS' in os.environ:
264 FLAGS.unix_mode = True
265
266 suffixes = ['.js']
267 if FLAGS.additional_extensions:
268 suffixes += ['.%s' % ext for ext in FLAGS.additional_extensions]
269 if FLAGS.check_html:
270 suffixes += ['.html', '.htm']
271 paths = fileflags.GetFileList(argv, 'JavaScript', suffixes)
272
273 if FLAGS.multiprocess:
274 records_iter = _MultiprocessCheckPaths(paths)
275 else:
276 records_iter = _CheckPaths(paths)
277
278 records_iter, records_iter_copy = itertools.tee(records_iter, 2)
279 _PrintErrorRecords(records_iter_copy)
280
281 error_records = list(records_iter)
282 _PrintSummary(paths, error_records)
283
284 exit_code = 0
285
286 # If there are any errors
287 if error_records:
288 exit_code += 1
289
290 # If there are any new errors
291 if [r for r in error_records if r.new_error]:
292 exit_code += 2
293
294 if exit_code:
295 if FLAGS.summary:
296 _PrintFileSummary(paths, error_records)
297
298 if FLAGS.beep:
299 # Make a beep noise.
300 sys.stdout.write(chr(7))
301
302 # Write out instructions for using fixjsstyle script to fix some of the
303 # reported errors.
304 fix_args = []
305 for flag in sys.argv[1:]:
306 for f in GJSLINT_ONLY_FLAGS:
307 if flag.startswith(f):
308 break
309 else:
310 fix_args.append(flag)
311
312 if not FLAGS.quiet:
313 print """
314 Some of the errors reported by GJsLint may be auto-fixable using the script
315 fixjsstyle. Please double check any changes it makes and report any bugs. The
316 script can be run by executing:
317
318 fixjsstyle %s """ % ' '.join(fix_args)
319
320 if FLAGS.time:
321 print 'Done in %s.' % _FormatTime(time.time() - start_time)
322
323 sys.exit(exit_code)
324
325
326 if __name__ == '__main__':
327 main()
OLDNEW
« no previous file with comments | « third_party/closure_linter/closure_linter/full_test.py ('k') | third_party/closure_linter/closure_linter/indentation.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698