16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#!/usr/bin/python 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# found in the LICENSE file. 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)"""Runs Closure compiler on a JavaScript file to check for errors.""" 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import argparse 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import os 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import re 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import subprocess 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import sys 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import tempfile 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import processor 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class Checker(object): 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Runs the Closure compiler on a given source file and returns the 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) success/errors.""" 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) _COMMON_CLOSURE_ARGS = [ 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--accept_const_keyword", 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=accessControls", 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=ambiguousFunctionDecl", 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=checkStructDictInheritance", 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=checkTypes", 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=checkVars", 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=constantProperty", 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=deprecated", 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=externsValidation", 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=globalThis", 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=invalidCasts", 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=misplacedTypeAnnotation", 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=missingProperties", 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=missingReturn", 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=nonStandardJsDocs", 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=suspiciousCode", 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=undefinedNames", 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=undefinedVars", 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=unknownDefines", 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=uselessCode", 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_error=visibility", 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # TODO(dbeam): happens when the same file is <include>d multiple times. 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "--jscomp_off=duplicate", 4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) "--language_in=ECMASCRIPT5_STRICT", 4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) "--summary_detail_level=3", 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ] 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) _JAR_COMMAND = [ 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "java", 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "-jar", 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "-Xms1024m", 5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) "-client", 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "-XX:+TieredCompilation" 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ] 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) _found_java = False 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def __init__(self, verbose=False): 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_dir = os.path.join(os.path.dirname(__file__)) 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._compiler_jar = os.path.join(current_dir, "lib", "compiler.jar") 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._runner_jar = os.path.join(current_dir, "runner", "runner.jar") 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._temp_files = [] 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._verbose = verbose 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _clean_up(self): 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if not self._temp_files: 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Deleting temporary files: %s" % ", ".join(self._temp_files)) 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for f in self._temp_files: 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) os.remove(f) 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._temp_files = [] 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _debug(self, msg, error=False): 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if self._verbose: 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) print "(INFO) %s" % msg 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _error(self, msg): 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) print >> sys.stderr, "(ERROR) %s" % msg 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._clean_up() 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _run_command(self, cmd): 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Runs a shell command. 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Args: 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) cmd: A list of tokens to be joined into a shell command. 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Return: 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) True if the exit code was 0, else False. 916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """ 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cmd_str = " ".join(cmd) 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Running command: %s" % cmd_str) 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) devnull = open(os.devnull, "w") 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return subprocess.Popen( 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cmd_str, stdout=devnull, stderr=subprocess.PIPE, shell=True) 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _check_java_path(self): 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Checks that `java` is on the system path.""" 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if not self._found_java: 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) proc = self._run_command(["which", "java"]) 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) proc.communicate() 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if proc.returncode == 0: 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._found_java = True 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else: 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._error("Cannot find java (`which java` => %s)" % proc.returncode) 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return self._found_java 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def _run_jar(self, jar, args=None): 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args = args or [] 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._check_java_path() 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return self._run_command(self._JAR_COMMAND + [jar] + args) 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _fix_line_number(self, match): 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Changes a line number from /tmp/file:300 to /orig/file:100. 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Args: 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) match: A re.MatchObject from matching against a line number regex. 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Returns: 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) The fixed up /file and :line number. 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """ 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) real_file = self._processor.get_file_from_line(match.group(1)) 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return "%s:%d" % (os.path.abspath(real_file.file), real_file.line_number) 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _fix_up_error(self, error): 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Filter out irrelevant errors or fix line numbers. 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Args: 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) error: A Closure compiler error (2 line string with error and source). 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Return: 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) The fixed up erorr string (blank if it should be ignored). 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """ 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if " first declared in " in error: 1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # Ignore "Variable x first declared in /same/file". 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return "" 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) expanded_file = self._expanded_file 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) fixed = re.sub("%s:(\d+)" % expanded_file, self._fix_line_number, error) 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return fixed.replace(expanded_file, os.path.abspath(self._file_arg)) 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _format_errors(self, errors): 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Formats Closure compiler errors to easily spot compiler output.""" 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) errors = filter(None, errors) 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) contents = "\n## ".join("\n\n".join(errors).splitlines()) 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return "## %s" % contents if contents else "" 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def _create_temp_file(self, contents): 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) with tempfile.NamedTemporaryFile(mode="wt", delete=False) as tmp_file: 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._temp_files.append(tmp_file.name) 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) tmp_file.write(contents) 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return tmp_file.name 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def check(self, source_file, depends=None, externs=None): 1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """Closure compile a file and check for errors. 1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Args: 1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) source_file: A file to check. 1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) depends: Other files that would be included with a <script> earlier in 1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) the page. 1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) externs: @extern files that inform the compiler about custom globals. 1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Returns: 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) (exitcode, output) The exit code of the Closure compiler (as a number) 1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) and its output (as a string). 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) """ 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) depends = depends or [] 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) externs = externs or [] 1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if not self._check_java_path(): 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 1, "" 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("FILE: %s" % source_file) 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if source_file.endswith("_externs.js"): 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Skipping externs: %s" % source_file) 1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._file_arg = source_file 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) tmp_dir = tempfile.gettempdir() 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f) 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) includes = [rel_path(f) for f in depends + [source_file]] 1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) contents = ['<include src="%s">' % i for i in includes] 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) meta_file = self._create_temp_file("\n".join(contents)) 1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Meta file: %s" % meta_file) 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._processor = processor.Processor(meta_file) 1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._expanded_file = self._create_temp_file(self._processor.contents) 1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Expanded file: %s" % self._expanded_file) 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args = ["--js=%s" % self._expanded_file] 1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args += ["--externs=%s" % e for e in externs] 1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args_file_content = " %s" % " ".join(self._COMMON_CLOSURE_ARGS + args) 1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Args: %s" % args_file_content.strip()) 2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) args_file = self._create_temp_file(args_file_content) 2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Args file: %s" % args_file) 2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) runner_args = ["--compiler-args-file=%s" % args_file] 2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) runner_cmd = self._run_jar(self._runner_jar, args=runner_args) 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (_, stderr) = runner_cmd.communicate() 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) errors = stderr.strip().split("\n\n") 2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Summary: %s" % errors.pop()) 2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) output = self._format_errors(map(self._fix_up_error, errors)) 2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if runner_cmd.returncode: 2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._error("Error in: %s%s" % (source_file, "\n" + output if output else "")) 2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) elif output: 2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._debug("Output: %s" % output) 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._clean_up() 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return runner_cmd.returncode, output 2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)if __name__ == "__main__": 2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser = argparse.ArgumentParser( 2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) description="Typecheck JavaScript using Closure compiler") 2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_argument("sources", nargs=argparse.ONE_OR_MORE, 2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) help="Path to a source file to typecheck") 2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE) 2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE) 2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_argument("-o", "--out_file", help="A place to output results") 2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_argument("-v", "--verbose", action="store_true", 2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) help="Show more information as this script runs") 2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) opts = parser.parse_args() 2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) checker = Checker(verbose=opts.verbose) 2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for source in opts.sources: 23603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) exit, _ = checker.check(source, depends=opts.depends, externs=opts.externs) 23703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if exit != 0: 23803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) sys.exit(exit) 2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if opts.out_file: 2416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) out_dir = os.path.dirname(opts.out_file) 2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if not os.path.exists(out_dir): 2436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) os.makedirs(out_dir) 2446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) # TODO(dbeam): write compiled file to |opts.out_file|. 2456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) open(opts.out_file, "w").write("") 246