Chromium Code Reviews| OLD | NEW | 
|---|---|
| 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 26 matching lines...) Expand all Loading... | |
| 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", | 45 "--language_in=ECMASCRIPT5_STRICT", | 
| 46 "--summary_detail_level=3", | 46 "--summary_detail_level=3", | 
| 47 '--compilation_level=WHITESPACE_ONLY' | |
| 47 ] | 48 ] | 
| 48 | 49 | 
| 49 # These are the extra flags used when compiling in 'strict' mode. | 50 # These are the extra flags used when compiling in 'strict' mode. | 
| 50 # Flags that are normally disabled are turned on for strict mode. | 51 # Flags that are normally disabled are turned on for strict mode. | 
| 51 _STRICT_CLOSURE_ARGS = [ | 52 _STRICT_CLOSURE_ARGS = [ | 
| 52 "--jscomp_error=reportUnknownTypes", | 53 "--jscomp_error=reportUnknownTypes", | 
| 53 "--jscomp_error=duplicate", | 54 "--jscomp_error=duplicate", | 
| 54 "--jscomp_error=misplacedTypeAnnotation", | 55 "--jscomp_error=misplacedTypeAnnotation", | 
| 55 ] | 56 ] | 
| 56 | 57 | 
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 errors = filter(None, errors) | 171 errors = filter(None, errors) | 
| 171 contents = "\n## ".join("\n\n".join(errors).splitlines()) | 172 contents = "\n## ".join("\n\n".join(errors).splitlines()) | 
| 172 return "## %s" % contents if contents else "" | 173 return "## %s" % contents if contents else "" | 
| 173 | 174 | 
| 174 def _create_temp_file(self, contents): | 175 def _create_temp_file(self, contents): | 
| 175 with tempfile.NamedTemporaryFile(mode="wt", delete=False) as tmp_file: | 176 with tempfile.NamedTemporaryFile(mode="wt", delete=False) as tmp_file: | 
| 176 self._temp_files.append(tmp_file.name) | 177 self._temp_files.append(tmp_file.name) | 
| 177 tmp_file.write(contents) | 178 tmp_file.write(contents) | 
| 178 return tmp_file.name | 179 return tmp_file.name | 
| 179 | 180 | 
| 180 def run_js_check(self, sources, externs=None): | 181 def run_js_check(self, sources, externs=None, out_file=None, | 
| 182 generate_output=False, create_source_map=False): | |
| 181 if not self._check_java_path(): | 183 if not self._check_java_path(): | 
| 182 return 1, "" | 184 return 1, "" | 
| 183 | 185 | 
| 184 args = ["--js=%s" % s for s in sources] | 186 args = ["--js=%s" % s for s in sources] | 
| 187 | |
| 188 if generate_output: | |
| 189 args += ["--js_output_file=%s" % out_file] | |
| 190 if create_source_map: | |
| 
 
Dan Beam
2015/03/06 02:57:28
i think we should always create source maps
 
Theresa
2015/03/06 03:07:18
Done.
 
 | |
| 191 args += ["--source_map_format=V3"] | |
| 192 args += ["--create_source_map=%s.map" % out_file] | |
| 193 | |
| 185 if externs: | 194 if externs: | 
| 186 args += ["--externs=%s" % e for e in externs] | 195 args += ["--externs=%s" % e for e in externs] | 
| 187 args_file_content = " %s" % " ".join(self._common_args() + args) | 196 args_file_content = " %s" % " ".join(self._common_args() + args) | 
| 188 self._debug("Args: %s" % args_file_content.strip()) | 197 self._debug("Args: %s" % args_file_content.strip()) | 
| 189 | 198 | 
| 190 args_file = self._create_temp_file(args_file_content) | 199 args_file = self._create_temp_file(args_file_content) | 
| 191 self._debug("Args file: %s" % args_file) | 200 self._debug("Args file: %s" % args_file) | 
| 192 | 201 | 
| 193 runner_args = ["--compiler-args-file=%s" % args_file] | 202 runner_args = ["--compiler-args-file=%s" % args_file] | 
| 194 runner_cmd = self._run_jar(self._runner_jar, args=runner_args) | 203 runner_cmd = self._run_jar(self._runner_jar, args=runner_args) | 
| 195 _, stderr = runner_cmd.communicate() | 204 _, stderr = runner_cmd.communicate() | 
| 196 | 205 | 
| 197 errors = stderr.strip().split("\n\n") | 206 errors = stderr.strip().split("\n\n") | 
| 198 self._debug("Summary: %s" % errors.pop()) | 207 self._debug("Summary: %s" % errors.pop()) | 
| 199 | 208 | 
| 200 self._clean_up() | 209 self._clean_up() | 
| 201 | 210 | 
| 202 return errors, stderr | 211 return errors, stderr | 
| 203 | 212 | 
| 204 def check(self, source_file, depends=None, externs=None): | 213 def check(self, source_file, depends=None, externs=None, | 
| 214 out_file=None, generate_output=False, create_source_map=False): | |
| 205 """Closure compile a file and check for errors. | 215 """Closure compile a file and check for errors. | 
| 206 | 216 | 
| 207 Args: | 217 Args: | 
| 208 source_file: A file to check. | 218 source_file: A file to check. | 
| 209 depends: Other files that would be included with a <script> earlier in | 219 depends: Other files that would be included with a <script> earlier in | 
| 210 the page. | 220 the page. | 
| 211 externs: @extern files that inform the compiler about custom globals. | 221 externs: @extern files that inform the compiler about custom globals. | 
| 212 | 222 | 
| 213 Returns: | 223 Returns: | 
| 214 (has_errors, output) A boolean indicating if there were errors and the | 224 (has_errors, output) A boolean indicating if there were errors and the | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 233 | 243 | 
| 234 includes = [rel_path(f) for f in depends + [source_file]] | 244 includes = [rel_path(f) for f in depends + [source_file]] | 
| 235 contents = ['<include src="%s">' % i for i in includes] | 245 contents = ['<include src="%s">' % i for i in includes] | 
| 236 meta_file = self._create_temp_file("\n".join(contents)) | 246 meta_file = self._create_temp_file("\n".join(contents)) | 
| 237 self._debug("Meta file: %s" % meta_file) | 247 self._debug("Meta file: %s" % meta_file) | 
| 238 | 248 | 
| 239 self._processor = processor.Processor(meta_file) | 249 self._processor = processor.Processor(meta_file) | 
| 240 self._expanded_file = self._create_temp_file(self._processor.contents) | 250 self._expanded_file = self._create_temp_file(self._processor.contents) | 
| 241 self._debug("Expanded file: %s" % self._expanded_file) | 251 self._debug("Expanded file: %s" % self._expanded_file) | 
| 242 | 252 | 
| 243 errors, stderr = self.run_js_check([self._expanded_file], externs) | 253 errors, stderr = self.run_js_check([self._expanded_file], externs, | 
| 254 out_file, generate_output, create_source_ map) | |
| 244 | 255 | 
| 245 # Filter out false-positive promise chain errors. | 256 # Filter out false-positive promise chain errors. | 
| 246 # See https://github.com/google/closure-compiler/issues/715 for details. | 257 # See https://github.com/google/closure-compiler/issues/715 for details. | 
| 247 errors = self._error_filter.filter(errors); | 258 errors = self._error_filter.filter(errors); | 
| 248 | 259 | 
| 249 output = self._format_errors(map(self._fix_up_error, errors)) | 260 output = self._format_errors(map(self._fix_up_error, errors)) | 
| 250 if errors: | 261 if errors: | 
| 251 prefix = "\n" if output else "" | 262 prefix = "\n" if output else "" | 
| 252 self._error("Error in: %s%s%s" % (source_file, prefix, output)) | 263 self._error("Error in: %s%s%s" % (source_file, prefix, output)) | 
| 253 elif output: | 264 elif output: | 
| (...skipping 23 matching lines...) Expand all Loading... | |
| 277 single_file_group = parser.add_mutually_exclusive_group() | 288 single_file_group = parser.add_mutually_exclusive_group() | 
| 278 single_file_group.add_argument("--single-file", dest="single_file", | 289 single_file_group.add_argument("--single-file", dest="single_file", | 
| 279 action="store_true", | 290 action="store_true", | 
| 280 help="Process each source file individually") | 291 help="Process each source file individually") | 
| 281 single_file_group.add_argument("--no-single-file", dest="single_file", | 292 single_file_group.add_argument("--no-single-file", dest="single_file", | 
| 282 action="store_false", | 293 action="store_false", | 
| 283 help="Process all source files as a group") | 294 help="Process all source files as a group") | 
| 284 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE) | 295 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE) | 
| 285 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE) | 296 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE) | 
| 286 parser.add_argument("-o", "--out_file", help="A place to output results") | 297 parser.add_argument("-o", "--out_file", help="A place to output results") | 
| 298 parser.add_argument("-g", "--generate_output", | |
| 299 help="Whether or not an output file should be generated") | |
| 300 parser.add_argument("-c", "--configuration_name", | |
| 301 help="The build configuration") | |
| 287 parser.add_argument("-v", "--verbose", action="store_true", | 302 parser.add_argument("-v", "--verbose", action="store_true", | 
| 288 help="Show more information as this script runs") | 303 help="Show more information as this script runs") | 
| 289 parser.add_argument("--strict", action="store_true", | 304 parser.add_argument("--strict", action="store_true", | 
| 290 help="Enable strict type checking") | 305 help="Enable strict type checking") | 
| 291 parser.add_argument("--success-stamp", | 306 parser.add_argument("--success-stamp", | 
| 292 help="Timestamp file to update upon success") | 307 help="Timestamp file to update upon success") | 
| 293 | 308 | 
| 294 parser.set_defaults(single_file=True, strict=False) | 309 parser.set_defaults(single_file=True, strict=False) | 
| 295 opts = parser.parse_args() | 310 opts = parser.parse_args() | 
| 296 | 311 | 
| 297 depends = opts.depends or [] | 312 depends = opts.depends or [] | 
| 298 externs = opts.externs or set() | 313 externs = opts.externs or set() | 
| 299 | 314 | 
| 315 generate_output = False if (opts.generate_output == '0') else True | |
| 316 create_source_map = True | |
| 317 if opts.configuration_name == 'Release' or not generate_output: | |
| 318 create_source_map = False | |
| 319 | |
| 320 # Clean up intermediate folders that get created by output.py or create the di rs if needed | |
| 321 out_dir = os.path.dirname(opts.out_file) | |
| 322 if not generate_output: | |
| 323 if os.path.exists(out_dir) and os.listdir(out_dir) == []: | |
| 324 os.removedirs(out_dir) | |
| 325 else: | |
| 326 if not os.path.exists(out_dir): | |
| 327 os.makedirs(out_dir) | |
| 328 | |
| 300 checker = Checker(verbose=opts.verbose, strict=opts.strict) | 329 checker = Checker(verbose=opts.verbose, strict=opts.strict) | 
| 301 if opts.single_file: | 330 if opts.single_file: | 
| 302 for source in opts.sources: | 331 for source in opts.sources: | 
| 303 depends, externs = build.inputs.resolve_recursive_dependencies( | 332 depends, externs = build.inputs.resolve_recursive_dependencies( | 
| 304 source, | 333 source, | 
| 305 depends, | 334 depends, | 
| 306 externs) | 335 externs) | 
| 307 has_errors, _ = checker.check(source, depends=depends, externs=externs) | 336 has_errors, _ = checker.check(source, depends=depends, externs=externs, | 
| 337 out_file=opts.out_file, generate_output=gene rate_output, | |
| 338 create_source_map=create_source_map) | |
| 308 if has_errors: | 339 if has_errors: | 
| 309 sys.exit(1) | 340 sys.exit(1) | 
| 310 | 341 | 
| 311 if opts.out_file: | |
| 312 out_dir = os.path.dirname(opts.out_file) | |
| 313 if not os.path.exists(out_dir): | |
| 314 os.makedirs(out_dir) | |
| 315 # TODO(dbeam): write compiled file to |opts.out_file|. | |
| 316 open(opts.out_file, "w").write("") | |
| 317 else: | 342 else: | 
| 318 has_errors, errors = checker.check_multiple(opts.sources) | 343 has_errors, errors = checker.check_multiple(opts.sources) | 
| 319 if has_errors: | 344 if has_errors: | 
| 320 print errors | 345 print errors | 
| 321 sys.exit(1) | 346 sys.exit(1) | 
| 322 | 347 | 
| 323 if opts.success_stamp: | 348 if opts.success_stamp: | 
| 324 with open(opts.success_stamp, 'w'): | 349 with open(opts.success_stamp, 'w'): | 
| 325 os.utime(opts.success_stamp, None) | 350 os.utime(opts.success_stamp, None) | 
| OLD | NEW |