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