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

Side by Side Diff: third_party/closure_compiler/checker.py

Issue 803653004: Update Chromoting to use /third_party/closure_compiler. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove unused types Created 5 years, 11 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
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Runs Closure compiler on a JavaScript file to check for errors.""" 6 """Runs Closure compiler on a JavaScript file to check for errors."""
7 7
8 import argparse 8 import argparse
9 import os 9 import os
10 import re 10 import re
(...skipping 24 matching lines...) Expand all
35 "--jscomp_error=invalidCasts", 35 "--jscomp_error=invalidCasts",
36 "--jscomp_error=missingProperties", 36 "--jscomp_error=missingProperties",
37 "--jscomp_error=missingReturn", 37 "--jscomp_error=missingReturn",
38 "--jscomp_error=nonStandardJsDocs", 38 "--jscomp_error=nonStandardJsDocs",
39 "--jscomp_error=suspiciousCode", 39 "--jscomp_error=suspiciousCode",
40 "--jscomp_error=undefinedNames", 40 "--jscomp_error=undefinedNames",
41 "--jscomp_error=undefinedVars", 41 "--jscomp_error=undefinedVars",
42 "--jscomp_error=unknownDefines", 42 "--jscomp_error=unknownDefines",
43 "--jscomp_error=uselessCode", 43 "--jscomp_error=uselessCode",
44 "--jscomp_error=visibility", 44 "--jscomp_error=visibility",
45 "--language_in=ECMASCRIPT5_STRICT",
46 "--summary_detail_level=3",
47 ]
48
49 # These are the extra flags used when compiling in 'strict' mode.
50 # Flags that are normally disabled are turned on for strict mode.
51 _STRICT_CLOSURE_ARGS = [
52 "--jscomp_error=reportUnknownTypes",
Tyler Breisacher (Chromium) 2015/01/12 20:35:15 We generally don't recommend people use this flag.
Jamie 2015/01/12 20:45:09 We took a decision back at the start of the projec
53 "--jscomp_error=duplicate",
54 "--jscomp_error=misplacedTypeAnnotation",
55 ]
56
57 _DISABLED_CLOSURE_ARGS = [
45 # TODO(dbeam): happens when the same file is <include>d multiple times. 58 # TODO(dbeam): happens when the same file is <include>d multiple times.
46 "--jscomp_off=duplicate", 59 "--jscomp_off=duplicate",
47 # TODO(fukino): happens when cr.defineProperty() has a type annotation. 60 # TODO(fukino): happens when cr.defineProperty() has a type annotation.
48 # Avoiding parse-time warnings needs 2 pass compiling. crbug.com/421562. 61 # Avoiding parse-time warnings needs 2 pass compiling. crbug.com/421562.
49 "--jscomp_off=misplacedTypeAnnotation", 62 "--jscomp_off=misplacedTypeAnnotation",
50 "--language_in=ECMASCRIPT5_STRICT",
51 "--summary_detail_level=3",
52 ] 63 ]
53 64
54 _JAR_COMMAND = [ 65 _JAR_COMMAND = [
55 "java", 66 "java",
56 "-jar", 67 "-jar",
57 "-Xms1024m", 68 "-Xms1024m",
58 "-client", 69 "-client",
59 "-XX:+TieredCompilation" 70 "-XX:+TieredCompilation"
60 ] 71 ]
61 72
62 _found_java = False 73 _found_java = False
63 74
64 def __init__(self, verbose=False): 75 def __init__(self, verbose=False, strict=False):
65 current_dir = os.path.join(os.path.dirname(__file__)) 76 current_dir = os.path.join(os.path.dirname(__file__))
66 self._compiler_jar = os.path.join(current_dir, "lib", "compiler.jar")
67 self._runner_jar = os.path.join(current_dir, "runner", "runner.jar") 77 self._runner_jar = os.path.join(current_dir, "runner", "runner.jar")
68 self._temp_files = [] 78 self._temp_files = []
69 self._verbose = verbose 79 self._verbose = verbose
80 self._strict = strict
70 self._error_filter = error_filter.PromiseErrorFilter() 81 self._error_filter = error_filter.PromiseErrorFilter()
71 82
72 def _clean_up(self): 83 def _clean_up(self):
73 if not self._temp_files: 84 if not self._temp_files:
74 return 85 return
75 86
76 self._debug("Deleting temporary files: %s" % ", ".join(self._temp_files)) 87 self._debug("Deleting temporary files: %s" % ", ".join(self._temp_files))
77 for f in self._temp_files: 88 for f in self._temp_files:
78 os.remove(f) 89 os.remove(f)
79 self._temp_files = [] 90 self._temp_files = []
80 91
81 def _debug(self, msg, error=False): 92 def _debug(self, msg, error=False):
82 if self._verbose: 93 if self._verbose:
83 print "(INFO) %s" % msg 94 print "(INFO) %s" % msg
84 95
85 def _error(self, msg): 96 def _error(self, msg):
86 print >> sys.stderr, "(ERROR) %s" % msg 97 print >> sys.stderr, "(ERROR) %s" % msg
87 self._clean_up() 98 self._clean_up()
88 99
100 def _common_args(self):
101 """Returns an array of the common closure compiler args."""
102 if self._strict:
103 return self._COMMON_CLOSURE_ARGS + self._STRICT_CLOSURE_ARGS
104 return self._COMMON_CLOSURE_ARGS + self._DISABLED_CLOSURE_ARGS
105
89 def _run_command(self, cmd): 106 def _run_command(self, cmd):
90 """Runs a shell command. 107 """Runs a shell command.
91 108
92 Args: 109 Args:
93 cmd: A list of tokens to be joined into a shell command. 110 cmd: A list of tokens to be joined into a shell command.
94 111
95 Return: 112 Return:
96 True if the exit code was 0, else False. 113 True if the exit code was 0, else False.
97 """ 114 """
98 cmd_str = " ".join(cmd) 115 cmd_str = " ".join(cmd)
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 errors = filter(None, errors) 170 errors = filter(None, errors)
154 contents = "\n## ".join("\n\n".join(errors).splitlines()) 171 contents = "\n## ".join("\n\n".join(errors).splitlines())
155 return "## %s" % contents if contents else "" 172 return "## %s" % contents if contents else ""
156 173
157 def _create_temp_file(self, contents): 174 def _create_temp_file(self, contents):
158 with tempfile.NamedTemporaryFile(mode="wt", delete=False) as tmp_file: 175 with tempfile.NamedTemporaryFile(mode="wt", delete=False) as tmp_file:
159 self._temp_files.append(tmp_file.name) 176 self._temp_files.append(tmp_file.name)
160 tmp_file.write(contents) 177 tmp_file.write(contents)
161 return tmp_file.name 178 return tmp_file.name
162 179
163 def check(self, source_file, depends=None, externs=None): 180 def check(self, source_file, depends=None, externs=None):
Tyler Breisacher (Chromium) 2015/01/12 20:35:15 Would it make sense for check() to just call check
garykac 2015/01/13 00:28:39 The single-file code path does a bunch of stuff: *
164 """Closure compile a file and check for errors. 181 """Closure compile a file and check for errors.
165 182
166 Args: 183 Args:
167 source_file: A file to check. 184 source_file: A file to check.
168 depends: Other files that would be included with a <script> earlier in 185 depends: Other files that would be included with a <script> earlier in
169 the page. 186 the page.
170 externs: @extern files that inform the compiler about custom globals. 187 externs: @extern files that inform the compiler about custom globals.
171 188
172 Returns: 189 Returns:
173 (exitcode, output) The exit code of the Closure compiler (as a number) 190 (has_errors, output) A boolean indicating if there were errors and the
174 and its output (as a string). 191 Closure compiler output (as a string).
175 """ 192 """
176 depends = depends or [] 193 depends = depends or []
177 externs = externs or set() 194 externs = externs or set()
178 195
179 if not self._check_java_path(): 196 if not self._check_java_path():
180 return 1, "" 197 return 1, ""
181 198
182 self._debug("FILE: %s" % source_file) 199 self._debug("FILE: %s" % source_file)
183 200
184 if source_file.endswith("_externs.js"): 201 if source_file.endswith("_externs.js"):
185 self._debug("Skipping externs: %s" % source_file) 202 self._debug("Skipping externs: %s" % source_file)
186 return 203 return
187 204
188 self._file_arg = source_file 205 self._file_arg = source_file
189 206
190 tmp_dir = tempfile.gettempdir() 207 tmp_dir = tempfile.gettempdir()
191 rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f) 208 rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f)
192 209
193 includes = [rel_path(f) for f in depends + [source_file]] 210 includes = [rel_path(f) for f in depends + [source_file]]
194 contents = ['<include src="%s">' % i for i in includes] 211 contents = ['<include src="%s">' % i for i in includes]
195 meta_file = self._create_temp_file("\n".join(contents)) 212 meta_file = self._create_temp_file("\n".join(contents))
196 self._debug("Meta file: %s" % meta_file) 213 self._debug("Meta file: %s" % meta_file)
197 214
198 self._processor = processor.Processor(meta_file) 215 self._processor = processor.Processor(meta_file)
199 self._expanded_file = self._create_temp_file(self._processor.contents) 216 self._expanded_file = self._create_temp_file(self._processor.contents)
200 self._debug("Expanded file: %s" % self._expanded_file) 217 self._debug("Expanded file: %s" % self._expanded_file)
201 218
202 args = ["--js=%s" % self._expanded_file] 219 args = ["--js=%s" % self._expanded_file]
203 args += ["--externs=%s" % e for e in externs] 220 args += ["--externs=%s" % e for e in externs]
204 args_file_content = " %s" % " ".join(self._COMMON_CLOSURE_ARGS + args) 221 args_file_content = " %s" % " ".join(self._common_args() + args)
205 self._debug("Args: %s" % args_file_content.strip()) 222 self._debug("Args: %s" % args_file_content.strip())
206 223
207 args_file = self._create_temp_file(args_file_content) 224 args_file = self._create_temp_file(args_file_content)
208 self._debug("Args file: %s" % args_file) 225 self._debug("Args file: %s" % args_file)
209 226
210 runner_args = ["--compiler-args-file=%s" % args_file] 227 runner_args = ["--compiler-args-file=%s" % args_file]
211 runner_cmd = self._run_jar(self._runner_jar, args=runner_args) 228 runner_cmd = self._run_jar(self._runner_jar, args=runner_args)
212 (_, stderr) = runner_cmd.communicate() 229 (_, stderr) = runner_cmd.communicate()
213 230
214 errors = stderr.strip().split("\n\n") 231 errors = stderr.strip().split("\n\n")
215 232
216 # Filter out false-positive promise chain errors. 233 # Filter out false-positive promise chain errors.
217 # See https://github.com/google/closure-compiler/issues/715 for details. 234 # See https://github.com/google/closure-compiler/issues/715 for details.
218 errors = self._error_filter.filter(errors); 235 errors = self._error_filter.filter(errors);
219 236
220 self._debug("Summary: %s" % errors.pop()) 237 self._debug("Summary: %s" % errors.pop())
221 238
222 output = self._format_errors(map(self._fix_up_error, errors)) 239 output = self._format_errors(map(self._fix_up_error, errors))
223 if errors: 240 if errors:
224 prefix = "\n" if output else "" 241 prefix = "\n" if output else ""
225 self._error("Error in: %s%s%s" % (source_file, prefix, output)) 242 self._error("Error in: %s%s%s" % (source_file, prefix, output))
226 elif output: 243 elif output:
227 self._debug("Output: %s" % output) 244 self._debug("Output: %s" % output)
228 245
229 self._clean_up() 246 self._clean_up()
230 247
231 return bool(errors), output 248 return bool(errors), output
232 249
250 def check_multiple(self, sources):
251 """Closure compile a set of files and check for errors.
252
253 Args:
254 sources: An array of files to check.
255
256 Returns:
257 (has_errors, output) A boolean indicating if there were errors and the
258 Closure compiler output (as a string).
259 """
260
261 if not self._check_java_path():
262 return 1, ""
263
264 args = ["--js=%s" % s for s in sources]
265 args_file_content = " %s" % " ".join(self._common_args() + args)
266 self._debug("Args: %s" % args_file_content.strip())
267
268 args_file = self._create_temp_file(args_file_content)
269 self._debug("Args file: %s" % args_file)
270
271 runner_args = ["--compiler-args-file=%s" % args_file]
272 runner_cmd = self._run_jar(self._runner_jar, args=runner_args)
273 (_, stderr) = runner_cmd.communicate()
274
275 errors = stderr.strip().split("\n\n")
276 self._debug("Summary: %s" % errors.pop())
277
278 return bool(errors), stderr
233 279
234 if __name__ == "__main__": 280 if __name__ == "__main__":
235 parser = argparse.ArgumentParser( 281 parser = argparse.ArgumentParser(
236 description="Typecheck JavaScript using Closure compiler") 282 description="Typecheck JavaScript using Closure compiler")
237 parser.add_argument("sources", nargs=argparse.ONE_OR_MORE, 283 parser.add_argument("sources", nargs=argparse.ONE_OR_MORE,
238 help="Path to a source file to typecheck") 284 help="Path to a source file to typecheck")
285 single_file_group = parser.add_mutually_exclusive_group()
286 single_file_group.add_argument("--single-file", dest="single_file",
287 action="store_true",
288 help="Process each source file individually")
289 single_file_group.add_argument("--no-single-file", dest="single_file",
290 action="store_false",
291 help="Process all source files as a group")
239 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE) 292 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE)
240 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE) 293 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE)
241 parser.add_argument("-o", "--out_file", help="A place to output results") 294 parser.add_argument("-o", "--out_file", help="A place to output results")
242 parser.add_argument("-v", "--verbose", action="store_true", 295 parser.add_argument("-v", "--verbose", action="store_true",
243 help="Show more information as this script runs") 296 help="Show more information as this script runs")
297 parser.add_argument("--strict", action="store_true",
298 help="Enable strict type checking")
299 parser.add_argument("--success-stamp",
300 help="Timestamp file to update upon success")
301
302 parser.set_defaults(single_file=True, strict=False)
244 opts = parser.parse_args() 303 opts = parser.parse_args()
245 304
246 checker = Checker(verbose=opts.verbose) 305 depends = opts.depends or []
247 for source in opts.sources: 306 externs = opts.externs or set()
248 depends, externs = build.inputs.resolve_recursive_dependencies( 307
249 source, 308 checker = Checker(verbose=opts.verbose, strict=opts.strict)
250 opts.depends, 309 if opts.single_file:
251 opts.externs) 310 for source in opts.sources:
252 exit, _ = checker.check(source, depends=depends, externs=externs) 311 depends, externs = build.inputs.resolve_recursive_dependencies(
253 if exit != 0: 312 source,
313 depends,
314 externs)
315 has_errors, _ = checker.check(source, depends=depends, externs=externs)
316 if has_errors:
317 sys.exit(exit)
Tyler Breisacher (Chromium) 2015/01/12 20:35:15 It looks like 'exit' is no longer defined. Maybe j
garykac 2015/01/13 00:28:39 Done.
318
319 if opts.out_file:
320 out_dir = os.path.dirname(opts.out_file)
321 if not os.path.exists(out_dir):
322 os.makedirs(out_dir)
323 # TODO(dbeam): write compiled file to |opts.out_file|.
324 open(opts.out_file, "w").write("")
325 else:
326 has_errors, _ = checker.check_multiple(opts.sources)
327 if has_errors:
328 print _
254 sys.exit(exit) 329 sys.exit(exit)
255 330
256 if opts.out_file: 331 if opts.success_stamp:
257 out_dir = os.path.dirname(opts.out_file) 332 with open(opts.success_stamp, 'w'):
258 if not os.path.exists(out_dir): 333 os.utime(opts.success_stamp, None)
259 os.makedirs(out_dir)
260 # TODO(dbeam): write compiled file to |opts.out_file|.
261 open(opts.out_file, "w").write("")
OLDNEW
« remoting/webapp/crd/js/smart_reconnector.js ('K') | « remoting/webapp/js_proto/remoting_proto.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698