Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 
      3 # Copyright 2014 The Chromium Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 '''Uses the closure compiler to check syntax and semantics of a js module
      8 with dependencies.'''
      9 
     10 import os
     11 import re
     12 import subprocess
     13 import sys
     14 
     15 _SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     16 _CHROME_SOURCE_DIR = os.path.normpath(
     17     os.path.join(
     18         _SCRIPT_DIR, *[os.path.pardir] * 6))
     19 
     20 # Compiler path.
     21 _CLOSURE_COMPILER_JAR = os.path.join(
     22     _CHROME_SOURCE_DIR, 'third_party', 'WebKit', 'Source', 'devtools',
     23     'scripts', 'closure', 'compiler.jar')
     24 
     25 # List of compilation errors to enable with the --jscomp_errors flag.
     26 _JSCOMP_ERRORS = [ 'accessControls', 'checkTypes', 'checkVars', 'invalidCasts',
     27                    'missingProperties', 'undefinedNames', 'undefinedVars',
     28                    'visibility' ]
     29 
     30 _java_executable = 'java'
     31 
     32 
     33 def _Error(msg):
     34   print >>sys.stderr, msg
     35   sys.exit(1)
     36 
     37 
     38 def _ExecuteCommand(args, ignore_exit_status=False):
     39   try:
     40     return subprocess.check_output(args, stderr=subprocess.STDOUT)
     41   except subprocess.CalledProcessError as e:
     42     if ignore_exit_status and e.returncode > 0:
     43       return e.output
     44     _Error('%s\nCommand \'%s\' returned non-zero exit status %d' %
     45            (e.output, ' '.join(e.cmd), e.returncode))
     46   except (OSError, IOError) as e:
     47     _Error('Error executing %s: %s' % (_java_executable, str(e)))
     48 
     49 
     50 def _CheckJava():
     51   global _java_executable
     52   java_home = os.environ.get('JAVAHOME')
     53   if java_home is not None:
     54     _java_executable = os.path.join(java_home, 'bin', 'java')
     55   output = _ExecuteCommand([_java_executable, '-version'])
     56   match = re.search(r'version "(?:\d+)\.(\d+)', output)
     57   if match is None or int(match.group(1)) < 7:
     58     _error('Java 7 or later is required: \n%s' % output)
     59 
     60 _CheckJava()
     61 
     62 
     63 def RunCompiler(js_files, externs=[]):
     64   args = [_java_executable, '-jar', _CLOSURE_COMPILER_JAR]
     65   args.extend(['--compilation_level', 'SIMPLE_OPTIMIZATIONS'])
     66   args.extend(['--jscomp_error=%s' % error for error in _JSCOMP_ERRORS])
     67   args.extend(['--externs=%s' % extern for extern in externs])
     68   args.extend(['--js=%s' % js for js in js_files])
     69   args.extend(['--js_output_file', '/dev/null'])
     70   output = _ExecuteCommand(args, ignore_exit_status=True)
     71   success = len(output) == 0
     72   return success, output
     73