Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: third_party/closure_compiler/checker.py

Issue 436843006: Closure compile JS files with GYP. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rename to compile_js.gypi Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/python
1 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 4 # found in the LICENSE file.
4 5
5 from collections import defaultdict 6 import argparse
6 import os 7 import os
8 import processor
7 import re 9 import re
8 import subprocess 10 import subprocess
9 import sys 11 import sys
10 import tempfile 12 import tempfile
11 13
12 14
13
14 class LineNumber(object):
15 def __init__(self, file, line_number):
16 self.file = file
17 self.line_number = int(line_number)
18
19
20 class FileCache(object):
21 _cache = defaultdict(str)
22
23 def _read(self, file):
24 file = os.path.abspath(file)
25 self._cache[file] = self._cache[file] or open(file, "r").read()
26 return self._cache[file]
27
28 @staticmethod
29 def read(file):
30 return FileCache()._read(file)
31
32
33 class Flattener(object):
34 _IF_TAGS_REG = "</?if[^>]*?>"
35 _INCLUDE_REG = "<include[^>]+src=['\"]([^>]*)['\"]>"
36
37 def __init__(self, file):
38 self.index = 0
39 self.lines = self._get_file(file)
40
41 while self.index < len(self.lines):
42 current_line = self.lines[self.index]
43 match = re.search(self._INCLUDE_REG, current_line[2])
44 if match:
45 file_dir = os.path.dirname(current_line[0])
46 self._inline_file(os.path.join(file_dir, match.group(1)))
47 else:
48 self.index += 1
49
50 # Replace every occurrence of tags like <if expr="..."> and </if>
51 # with an empty string.
52 for i, line in enumerate(self.lines):
53 self.lines[i] = line[:2] + (re.sub(self._IF_TAGS_REG, "", line[2]),)
54
55 self.contents = "\n".join(l[2] for l in self.lines)
56
57 # Returns a list of tuples in the format: (file, line number, line contents).
58 def _get_file(self, file):
59 lines = FileCache.read(file).splitlines()
60 return [(file, lnum + 1, line) for lnum, line in enumerate(lines)]
61
62 def _inline_file(self, file):
63 lines = self._get_file(file)
64 self.lines = self.lines[:self.index] + lines + self.lines[self.index + 1:]
65
66 def get_file_from_line(self, line_number):
67 line_number = int(line_number) - 1
68 return LineNumber(self.lines[line_number][0], self.lines[line_number][1])
69
70
71 class Checker(object): 15 class Checker(object):
72 _common_closure_args = [ 16 _common_closure_args = [
73 "--accept_const_keyword", 17 "--accept_const_keyword",
74 "--language_in=ECMASCRIPT5", 18 "--language_in=ECMASCRIPT5",
75 "--summary_detail_level=3", 19 "--summary_detail_level=3",
76 "--warning_level=VERBOSE", 20 "--warning_level=VERBOSE",
77 "--jscomp_error=accessControls", 21 "--jscomp_error=accessControls",
78 "--jscomp_error=ambiguousFunctionDecl", 22 "--jscomp_error=ambiguousFunctionDecl",
79 "--jscomp_error=checkStructDictInheritance", 23 "--jscomp_error=checkStructDictInheritance",
80 "--jscomp_error=checkTypes", 24 "--jscomp_error=checkTypes",
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 else: 93 else:
150 self._error("Cannot find java (`which java` => %s)" % proc.returncode) 94 self._error("Cannot find java (`which java` => %s)" % proc.returncode)
151 95
152 return self._found_java 96 return self._found_java
153 97
154 def _run_jar(self, jar, args=[]): 98 def _run_jar(self, jar, args=[]):
155 self._check_java_path() 99 self._check_java_path()
156 return self._run_command(self._jar_command + [jar] + args) 100 return self._run_command(self._jar_command + [jar] + args)
157 101
158 def _fix_line_number(self, match): 102 def _fix_line_number(self, match):
159 real_file = self._flattener.get_file_from_line(match.group(1)) 103 real_file = self._processor.get_file_from_line(match.group(1))
160 return "%s:%d" % (os.path.abspath(real_file.file), real_file.line_number) 104 return "%s:%d" % (os.path.abspath(real_file.file), real_file.line_number)
161 105
162 def _fix_up_error(self, error): 106 def _fix_up_error(self, error):
163 if " first declared in " in error: 107 if " first declared in " in error:
164 # Ignore "Variable x first declared in /same/file". 108 # Ignore "Variable x first declared in /same/file".
165 return "" 109 return ""
166 110
167 file = self._expanded_file 111 file = self._expanded_file
168 fixed = re.sub("%s:(\d+)" % file, self._fix_line_number, error) 112 fixed = re.sub("%s:(\d+)" % file, self._fix_line_number, error)
169 return fixed.replace(file, os.path.abspath(self._file_arg)) 113 return fixed.replace(file, os.path.abspath(self._file_arg))
170 114
171 def _format_errors(self, errors): 115 def _format_errors(self, errors):
172 errors = filter(None, errors) 116 errors = filter(None, errors)
173 contents = ("\n" + "## ").join("\n\n".join(errors).splitlines()) 117 contents = ("\n" + "## ").join("\n\n".join(errors).splitlines())
174 return "## " + contents if contents else "" 118 return "## " + contents if contents else ""
175 119
176 def _create_temp_file(self, contents): 120 def _create_temp_file(self, contents):
177 with tempfile.NamedTemporaryFile(mode='wt', delete=False) as tmp_file: 121 with tempfile.NamedTemporaryFile(mode="wt", delete=False) as tmp_file:
178 self._temp_files.append(tmp_file.name) 122 self._temp_files.append(tmp_file.name)
179 tmp_file.write(contents) 123 tmp_file.write(contents)
180 return tmp_file.name 124 return tmp_file.name
181 125
182 def check(self, file, depends=[], externs=[]): 126 def check(self, file, depends=[], externs=[]):
183 if not self._check_java_path(): 127 if not self._check_java_path():
184 return 1, "" 128 return 1, ""
185 129
186 self._debug("FILE: " + file) 130 self._debug("FILE: " + file)
187 131
188 if file.endswith("_externs.js"): 132 if file.endswith("_externs.js"):
189 self._debug("Skipping externs: " + file) 133 self._debug("Skipping externs: " + file)
190 return 134 return
191 135
192 self._file_arg = file 136 self._file_arg = file
193 137
194 tmp_dir = tempfile.gettempdir() 138 tmp_dir = tempfile.gettempdir()
195 rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f) 139 rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f)
196 140
197 contents = ['<include src="%s">' % rel_path(f) for f in depends + [file]] 141 contents = ['<include src="%s">' % rel_path(f) for f in depends + [file]]
198 meta_file = self._create_temp_file("\n".join(contents)) 142 meta_file = self._create_temp_file("\n".join(contents))
199 self._debug("Meta file: " + meta_file) 143 self._debug("Meta file: " + meta_file)
200 144
201 self._flattener = Flattener(meta_file) 145 self._processor = processor.Processor(meta_file)
202 self._expanded_file = self._create_temp_file(self._flattener.contents) 146 self._expanded_file = self._create_temp_file(self._processor.contents)
203 self._debug("Expanded file: " + self._expanded_file) 147 self._debug("Expanded file: " + self._expanded_file)
204 148
205 args = ["--js=" + self._expanded_file] + ["--externs=" + e for e in externs] 149 args = ["--js=" + self._expanded_file] + ["--externs=" + e for e in externs]
206 args_file_content = " " + " ".join(self._common_closure_args + args) 150 args_file_content = " " + " ".join(self._common_closure_args + args)
207 self._debug("Args: " + args_file_content.strip()) 151 self._debug("Args: " + args_file_content.strip())
208 152
209 args_file = self._create_temp_file(args_file_content) 153 args_file = self._create_temp_file(args_file_content)
210 self._debug("Args file: " + args_file) 154 self._debug("Args file: " + args_file)
211 155
212 runner_args = ["--compiler-args-file=" + args_file] 156 runner_args = ["--compiler-args-file=" + args_file]
213 runner_cmd = self._run_jar(self._runner_jar, args=runner_args) 157 runner_cmd = self._run_jar(self._runner_jar, args=runner_args)
214 (_, stderr) = runner_cmd.communicate() 158 (_, stderr) = runner_cmd.communicate()
215 159
216 errors = stderr.strip().split("\n\n") 160 errors = stderr.strip().split("\n\n")
217 self._debug("Summary: " + errors.pop()) 161 self._debug("Summary: " + errors.pop())
218 162
219 output = self._format_errors(map(self._fix_up_error, errors)) 163 output = self._format_errors(map(self._fix_up_error, errors))
220 if runner_cmd.returncode: 164 if runner_cmd.returncode:
221 self._error("Error in: " + file + ("\n" + output if output else "")) 165 self._error("Error in: " + file + ("\n" + output if output else ""))
222 elif output: 166 elif output:
223 self._debug("Output: " + output) 167 self._debug("Output: " + output)
224 168
225 self._clean_up() 169 self._clean_up()
226 170
227 return runner_cmd.returncode, output 171 return runner_cmd.returncode, output
172
173
174 if __name__ == "__main__":
175 parser = argparse.ArgumentParser(
176 description="Typecheck JavaScript using Closure compiler")
177 parser.add_argument("sources", nargs=argparse.ONE_OR_MORE,
178 help="Path to a source file to typecheck")
179 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE)
180 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE)
181 parser.add_argument("-o", "--out_file", help="A place to output results")
182 parser.add_argument("-v", "--verbose", action="store_true",
183 help="Show more information as this script runs")
184 opts = parser.parse_args()
185
186 checker = Checker(verbose=opts.verbose)
187 for source in opts.sources:
188 if not checker.check(source, depends=opts.depends, externs=opts.externs):
189 sys.exit(1)
190
191 if opts.out_file:
192 out_dir = os.path.dirname(opts.out_file)
193 if not os.path.exists(out_dir):
194 os.makedirs(out_dir)
195 # TODO(dbeam): write compiled file to |opts.out_file|.
196 open(opts.out_file, "w").write("")
OLDNEW
« no previous file with comments | « third_party/closure_compiler/build/outputs.py ('k') | third_party/closure_compiler/checker_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698