Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / third_party / closure_compiler / compile_modules.py
blobb81f486615c58e479d5e95f414bb4689d4dcd139
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
6 import argparse
7 from checker import Checker as Checker
8 import os
9 import sys
11 try:
12 import json
13 except:
14 import simplejson as json
17 class Module(object):
18 def __init__(self, name, sources, depends=[], externs=[]):
19 self.name = name
20 self.sources = sources
21 # TODO(dbeam): support depending on other modules/dependency flattening.
22 self.depends = depends
23 self.externs = externs
25 @staticmethod
26 def from_dict(d):
27 keys = d.keys()
29 required = ["name", "sources"]
30 assert all(r in keys for r in required), "Module missing name or sources"
32 allowed = required + ["depends", "externs"]
33 assert all(k in allowed for k in keys), "Module has unknown key"
35 depends = d["depends"] if "depends" in d else []
36 externs = d["externs"] if "externs" in d else []
37 return Module(d["name"], d["sources"], depends=depends, externs=externs)
40 # TODO(dbeam): should ModuleParser be internal to ModuleCompiler or should we
41 # pass Modules into ModuleCompiler.compile()? Maybe this is fine?
42 class ModuleParser(object):
43 _cache = {}
45 def __init__(self, verbose=False):
46 self._verbose = verbose
48 def parse(self, file_path):
49 if file_path in self._cache:
50 print "(INFO) Found module file %s in the cache" % file_path
51 return self._cache[file_path]
53 file = open(file_path, "r")
54 data = json.load(file)
55 file.close()
57 if self._verbose:
58 pretty_json = json.dumps(data, indent=2, separators=(',', ': ')).strip()
59 print "(INFO) Layout: " + os.linesep + pretty_json + os.linesep
61 self._cache[file_path] = [Module.from_dict(m) for m in data]
62 return self._cache[file_path]
65 class ModuleCompiler(object):
66 _checker = None
67 _parser = None
69 def __init__(self, verbose=False):
70 self._verbose = verbose
72 def _debug(self, msg, prefix="(INFO) ", suffix=""):
73 if self._verbose:
74 print prefix + msg.strip() + suffix
76 def compile(self, module_file):
77 self._debug("MODULE FILE: " + module_file, prefix="")
79 # NOTE: It's possible but unlikely that |_checker| or |_parser|'s verbosity
80 # isn't the same as |self._verbose| due to this class being called with
81 # verbose=False then verbose=True in the same program.
82 self._parser = self._parser or ModuleParser(verbose=self._verbose)
83 self._checker = self._checker or Checker(verbose=self._verbose)
85 current_dir = os.getcwd()
86 module_dir = os.path.dirname(module_file)
87 rel_path = lambda f: f
89 if current_dir and module_dir:
90 here_to_module_dir = os.path.relpath(module_dir, current_dir)
91 if here_to_module_dir:
92 rel_path = lambda f: os.path.join(here_to_module_dir, f)
94 modules = self._parser.parse(module_file)
96 for m in modules:
97 self._debug("MODULE: " + m.name, prefix="", suffix=os.linesep)
99 for s in m.sources:
100 depends = [rel_path(d) for d in m.depends]
101 externs = [rel_path(e) for e in m.externs]
102 exit_code, _ = self._checker.check(rel_path(s), depends=depends,
103 externs=externs)
104 if exit_code:
105 sys.exit(exit_code)
107 if s != m.sources[-1]:
108 self._debug(os.linesep, prefix="")
110 if m != modules[-1]:
111 self._debug(os.linesep, prefix="")
114 def main(opts):
115 module_compiler = ModuleCompiler(verbose=opts.verbose)
116 for module_file in opts.module_file:
117 module_compiler.compile(module_file)
120 if __name__ == "__main__":
121 parser = argparse.ArgumentParser(
122 description="Typecheck JavaScript using Closure compiler")
123 parser.add_argument("-v", "--verbose", action="store_true",
124 help="Show more information as this script runs")
125 parser.add_argument("module_file", nargs=argparse.ONE_OR_MORE,
126 help="Path to a modules file to check")
127 main(parser.parse_args())