check_chromevox.py revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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 the ChromeVox javascript files. 8 9With no arguments, checks all ChromeVox scripts. If any arguments are 10specified, only scripts that include any of the specified files will be 11compiled. A useful argument list is the output of the command 12'git diff --name-only --relative'. 13''' 14 15import optparse 16import os 17import re 18import sys 19 20from multiprocessing import pool 21 22from jsbundler import Bundle, CalcDeps, ReadSources 23from jscompilerwrapper import RunCompiler 24 25_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 26_CHROME_SOURCE_DIR = os.path.normpath( 27 os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6)) 28 29 30def CVoxPath(path='.'): 31 '''Converts a path relative to the top-level chromevox directory to a 32 path relative to the current directory. 33 ''' 34 return os.path.relpath(os.path.join(_SCRIPT_DIR, '..', path)) 35 36 37# Externs common to many ChromeVox scripts. 38_COMMON_EXTERNS = [ 39 CVoxPath('common/externs.js'), 40 CVoxPath('common/chrome_extension_externs.js'), 41 CVoxPath('chromevox/background/externs.js'), 42 CVoxPath('chromevox/injected/externs.js'), 43 CVoxPath('liblouis_nacl/externs.js'), 44 CVoxPath('host/chrome/externs.js')] 45 46# List of top-level scripts and externs that we can check. 47_TOP_LEVEL_SCRIPTS = [ 48 [[CVoxPath('chromevox/background/kbexplorer_loader.js')], 49 [CVoxPath('common/chrome_extension_externs.js')]], 50 [[CVoxPath('chromevox/background/loader.js')], _COMMON_EXTERNS], 51 [[CVoxPath('chromevox/background/options_loader.js')], _COMMON_EXTERNS], 52 [[CVoxPath('chromevox/injected/loader.js')], _COMMON_EXTERNS], 53 ] 54 55 56def _Compile(js_files, externs): 57 try: 58 return RunCompiler(js_files, externs) 59 except KeyboardInterrupt: 60 return (False, 'KeyboardInterrupt') 61 62 63def CheckChromeVox(changed_files=None): 64 if changed_files is not None: 65 changed_files_set = frozenset( 66 (os.path.relpath(path) for path in changed_files)) 67 if len(changed_files_set) == 0: 68 return (True, '') 69 else: 70 changed_files_set = None 71 ret_success = True 72 ret_output = '' 73 roots = [CVoxPath(), 74 os.path.relpath( 75 os.path.join( 76 _CHROME_SOURCE_DIR, 77 'chrome/third_party/chromevox/third_party/closure-library/' 78 'closure/goog'))] 79 sources = ReadSources(roots, need_source_text=True, 80 exclude=[re.compile('testing')]) 81 work_pool = pool.Pool(len(_TOP_LEVEL_SCRIPTS)) 82 try: 83 results = [] 84 for top_level in _TOP_LEVEL_SCRIPTS: 85 tl_files, externs = top_level 86 bundle = Bundle() 87 CalcDeps(bundle, sources, tl_files) 88 bundle.Add((sources[name] for name in tl_files)) 89 ordered_paths = list(bundle.GetInPaths()) 90 if (changed_files_set is not None and 91 changed_files_set.isdisjoint(ordered_paths + externs)): 92 continue 93 print 'Compiling %s' % ','.join(tl_files) 94 results.append([tl_files, 95 work_pool.apply_async( 96 _Compile, 97 args=[ordered_paths, externs])]) 98 for result in results: 99 tl_files = result[0] 100 success, output = result[1].get() 101 if not success: 102 ret_output += '\nFrom compiling %s:\n%s\n' % (','.join(tl_files), 103 output) 104 ret_success = False 105 work_pool.close() 106 except: 107 work_pool.terminate() 108 raise 109 finally: 110 work_pool.join() 111 return (ret_success, ret_output) 112 113 114def main(): 115 parser = optparse.OptionParser(description=__doc__) 116 parser.usage = '%prog [<changed_file>...]' 117 _, args = parser.parse_args() 118 119 changed_paths = None 120 if len(args) > 0: 121 changed_paths = (os.path.relpath(p) for p in args) 122 success, output = CheckChromeVox(changed_paths) 123 if len(output) > 0: 124 print output 125 return int(not success) 126 127 128if __name__ == '__main__': 129 sys.exit(main()) 130