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

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

Issue 476453002: Python readability review for dbeam@. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 6 years 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 #!/usr/bin/python
rothwell 2014/12/18 22:30:47 are there unittests for this file?
Dan Beam 2015/02/25 03:36:49 this file mainly just runs a .jar file. the major
2 # Copyright 2014 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Runs Closure compiler on a JavaScript file to check for errors.""" 6 """Runs Closure compiler on a JavaScript file to check for errors."""
7 7
8 import argparse 8 import argparse
9 import os 9 import os
10 import re 10 import re
11 import subprocess 11 import subprocess
12 import sys 12 import sys
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 ] 52 ]
53 53
54 _JAR_COMMAND = [ 54 _JAR_COMMAND = [
55 "java", 55 "java",
56 "-jar", 56 "-jar",
57 "-Xms1024m", 57 "-Xms1024m",
58 "-client", 58 "-client",
59 "-XX:+TieredCompilation" 59 "-XX:+TieredCompilation"
60 ] 60 ]
61 61
62 _found_java = False 62 _found_java = False
rothwell 2014/12/18 22:30:47 why is this a class variable and not an instance v
rothwell 2014/12/18 22:30:47 add a comment?
Dan Beam 2015/02/25 03:36:49 I've just removed checking for java on the user's
63 63
64 def __init__(self, verbose=False): 64 def __init__(self, verbose=False):
rothwell 2014/12/18 22:30:47 no docstring?
Dan Beam 2015/02/25 03:36:48 Done.
65 current_dir = os.path.join(os.path.dirname(__file__)) 65 current_dir = os.path.join(os.path.dirname(__file__))
66 self._compiler_jar = os.path.join(current_dir, "lib", "compiler.jar") 66 self._compiler_jar = os.path.join(current_dir, "lib", "compiler.jar")
67 self._runner_jar = os.path.join(current_dir, "runner", "runner.jar") 67 self._runner_jar = os.path.join(current_dir, "runner", "runner.jar")
68 self._temp_files = [] 68 self._temp_files = []
69 self._verbose = verbose 69 self._verbose = verbose
70 self._error_filter = error_filter.PromiseErrorFilter() 70 self._error_filter = error_filter.PromiseErrorFilter()
71 71
72 def _clean_up(self): 72 def _clean_up(self):
73 if not self._temp_files: 73 if not self._temp_files:
74 return 74 return
75 75
76 self._debug("Deleting temporary files: %s" % ", ".join(self._temp_files)) 76 self._debug("Deleting temporary files: %s" % ", ".join(self._temp_files))
77 for f in self._temp_files: 77 for f in self._temp_files:
78 os.remove(f) 78 os.remove(f)
79 self._temp_files = [] 79 self._temp_files = []
80 80
81 def _debug(self, msg, error=False): 81 def _debug(self, msg, error=False):
82 if self._verbose: 82 if self._verbose:
83 print "(INFO) %s" % msg 83 print "(INFO) %s" % msg
rothwell 2014/12/18 22:30:48 there's no logging module that you could/should be
Dan Beam 2015/02/25 03:36:49 this CL is getting kinda big. can I do this separ
84 84
85 def _error(self, msg): 85 def _error(self, msg):
rothwell 2014/12/18 22:30:47 maybe this should be called _log_error - I would e
Dan Beam 2015/02/25 03:36:49 Done.
86 print >> sys.stderr, "(ERROR) %s" % msg 86 print >> sys.stderr, "(ERROR) %s" % msg
87 self._clean_up() 87 self._clean_up()
rothwell 2014/12/18 22:30:47 this seems like a confusing side effect of this me
Dan Beam 2015/02/25 03:36:48 This originally had a reason to be here, but now I
88 88
89 def _run_command(self, cmd): 89 def _run_command(self, cmd):
90 """Runs a shell command. 90 """Runs a shell command.
91 91
92 Args: 92 Args:
93 cmd: A list of tokens to be joined into a shell command. 93 cmd: A list of tokens to be joined into a shell command.
rothwell 2014/12/18 22:30:47 minor nit but indention here differs from google3
Dan Beam 2015/02/25 03:36:49 Done.
94 94
95 Return: 95 Return:
96 True if the exit code was 0, else False. 96 True if the exit code was 0, else False.
rothwell 2014/12/18 22:30:47 this doesn't look correct - it appears to return t
Dan Beam 2015/02/25 03:36:49 Done.
97 """ 97 """
98 cmd_str = " ".join(cmd) 98 cmd_str = " ".join(cmd)
99 self._debug("Running command: %s" % cmd_str) 99 self._debug("Running command: %s" % cmd_str)
100 100
101 devnull = open(os.devnull, "w") 101 devnull = open(os.devnull, "w")
102 return subprocess.Popen( 102 return subprocess.Popen(
103 cmd_str, stdout=devnull, stderr=subprocess.PIPE, shell=True) 103 cmd_str, stdout=devnull, stderr=subprocess.PIPE, shell=True)
104 104
105 def _check_java_path(self): 105 def _check_java_path(self):
rothwell 2014/12/18 22:30:47 maybe this should be a classmethod as it modifies
Dan Beam 2015/02/25 03:36:49 Removed.
106 """Checks that `java` is on the system path.""" 106 """Checks that `java` is on the system path."""
107 if not self._found_java: 107 if not self._found_java:
108 proc = self._run_command(["which", "java"]) 108 proc = self._run_command(["which", "java"])
109 proc.communicate() 109 proc.communicate()
110 if proc.returncode == 0: 110 if proc.returncode == 0:
111 self._found_java = True 111 self._found_java = True
112 else: 112 else:
113 self._error("Cannot find java (`which java` => %s)" % proc.returncode) 113 self._error("Cannot find java (`which java` => %s)" % proc.returncode)
114 114
115 return self._found_java 115 return self._found_java
116 116
117 def _run_jar(self, jar, args=None): 117 def _run_jar(self, jar, args=None):
118 args = args or [] 118 args = args or []
119 self._check_java_path() 119 self._check_java_path()
120 return self._run_command(self._JAR_COMMAND + [jar] + args) 120 return self._run_command(self._JAR_COMMAND + [jar] + args)
121 121
122 def _fix_line_number(self, match): 122 def _fix_line_number(self, match):
123 """Changes a line number from /tmp/file:300 to /orig/file:100. 123 """Changes a line number from /tmp/file:300 to /orig/file:100.
rothwell 2014/12/18 22:30:47 maybe elaborate on why this conversion is necessar
Dan Beam 2015/02/25 03:36:48 Done.
124 124
125 Args: 125 Args:
126 match: A re.MatchObject from matching against a line number regex. 126 match: A re.MatchObject from matching against a line number regex.
127 127
128 Returns: 128 Returns:
129 The fixed up /file and :line number. 129 The fixed up /file and :line number.
130 """ 130 """
131 real_file = self._processor.get_file_from_line(match.group(1)) 131 real_file = self._processor.get_file_from_line(match.group(1))
132 return "%s:%d" % (os.path.abspath(real_file.file), real_file.line_number) 132 return "%s:%d" % (os.path.abspath(real_file.file), real_file.line_number)
133 133
(...skipping 29 matching lines...) Expand all
163 def check(self, source_file, depends=None, externs=None): 163 def check(self, source_file, depends=None, externs=None):
164 """Closure compile a file and check for errors. 164 """Closure compile a file and check for errors.
165 165
166 Args: 166 Args:
167 source_file: A file to check. 167 source_file: A file to check.
168 depends: Other files that would be included with a <script> earlier in 168 depends: Other files that would be included with a <script> earlier in
169 the page. 169 the page.
170 externs: @extern files that inform the compiler about custom globals. 170 externs: @extern files that inform the compiler about custom globals.
171 171
172 Returns: 172 Returns:
173 (exitcode, output) The exit code of the Closure compiler (as a number) 173 (exitcode, output) The exit code of the Closure compiler (as a number)
rothwell 2014/12/18 22:30:47 is exitcode useful to the caller? I would expect a
Dan Beam 2015/02/25 03:36:49 Done.
174 and its output (as a string). 174 and its output (as a string).
175 """ 175 """
176 depends = depends or [] 176 depends = depends or []
177 externs = externs or set() 177 externs = externs or set()
178 178
179 if not self._check_java_path(): 179 if not self._check_java_path():
180 return 1, "" 180 return 1, ""
181 181
182 self._debug("FILE: %s" % source_file) 182 self._debug("FILE: %s" % source_file)
183 183
184 if source_file.endswith("_externs.js"): 184 if source_file.endswith("_externs.js"):
185 self._debug("Skipping externs: %s" % source_file) 185 self._debug("Skipping externs: %s" % source_file)
186 return 186 return
rothwell 2014/12/18 22:30:47 this return code doesn't match your stated API
Dan Beam 2015/02/25 03:36:48 Done.
187 187
188 self._file_arg = source_file 188 self._file_arg = source_file
189 189
190 tmp_dir = tempfile.gettempdir() 190 tmp_dir = tempfile.gettempdir()
191 rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f) 191 rel_path = lambda f: os.path.join(os.path.relpath(os.getcwd(), tmp_dir), f)
rothwell 2014/12/18 22:30:47 not sure this lambda is buying you much, I would j
Dan Beam 2015/02/25 03:36:49 I find: includes = [rel_path(f) for f in depend
rothwell 2015/03/20 19:24:31 defer to your preference
192 192
193 includes = [rel_path(f) for f in depends + [source_file]] 193 includes = [rel_path(f) for f in depends + [source_file]]
194 contents = ['<include src="%s">' % i for i in includes] 194 contents = ['<include src="%s">' % i for i in includes]
195 meta_file = self._create_temp_file("\n".join(contents)) 195 meta_file = self._create_temp_file("\n".join(contents))
196 self._debug("Meta file: %s" % meta_file) 196 self._debug("Meta file: %s" % meta_file)
197 197
198 self._processor = processor.Processor(meta_file) 198 self._processor = processor.Processor(meta_file)
199 self._expanded_file = self._create_temp_file(self._processor.contents) 199 self._expanded_file = self._create_temp_file(self._processor.contents)
200 self._debug("Expanded file: %s" % self._expanded_file) 200 self._debug("Expanded file: %s" % self._expanded_file)
201 201
(...skipping 19 matching lines...) Expand all
221 221
222 output = self._format_errors(map(self._fix_up_error, errors)) 222 output = self._format_errors(map(self._fix_up_error, errors))
223 if errors: 223 if errors:
224 prefix = "\n" if output else "" 224 prefix = "\n" if output else ""
225 self._error("Error in: %s%s%s" % (source_file, prefix, output)) 225 self._error("Error in: %s%s%s" % (source_file, prefix, output))
226 elif output: 226 elif output:
227 self._debug("Output: %s" % output) 227 self._debug("Output: %s" % output)
228 228
229 self._clean_up() 229 self._clean_up()
230 230
231 return bool(errors), output 231 return bool(errors), output
rothwell 2014/12/18 22:30:47 your API says you will return an integer, this is
Dan Beam 2015/02/25 03:36:49 Done.
232 232
233 233
234 if __name__ == "__main__": 234 if __name__ == "__main__":
235 parser = argparse.ArgumentParser( 235 parser = argparse.ArgumentParser(
236 description="Typecheck JavaScript using Closure compiler") 236 description="Typecheck JavaScript using Closure compiler")
237 parser.add_argument("sources", nargs=argparse.ONE_OR_MORE, 237 parser.add_argument("sources", nargs=argparse.ONE_OR_MORE,
238 help="Path to a source file to typecheck") 238 help="Path to a source file to typecheck")
239 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE) 239 parser.add_argument("-d", "--depends", nargs=argparse.ZERO_OR_MORE)
240 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE) 240 parser.add_argument("-e", "--externs", nargs=argparse.ZERO_OR_MORE)
241 parser.add_argument("-o", "--out_file", help="A place to output results") 241 parser.add_argument("-o", "--out_file", help="A place to output results")
242 parser.add_argument("-v", "--verbose", action="store_true", 242 parser.add_argument("-v", "--verbose", action="store_true",
243 help="Show more information as this script runs") 243 help="Show more information as this script runs")
244 opts = parser.parse_args() 244 opts = parser.parse_args()
245 245
246 checker = Checker(verbose=opts.verbose) 246 checker = Checker(verbose=opts.verbose)
247 for source in opts.sources: 247 for source in opts.sources:
248 depends, externs = build.inputs.resolve_recursive_dependencies( 248 depends, externs = build.inputs.resolve_recursive_dependencies(
249 source, 249 source,
250 opts.depends, 250 opts.depends,
251 opts.externs) 251 opts.externs)
252 exit, _ = checker.check(source, depends=depends, externs=externs) 252 exit, _ = checker.check(source, depends=depends, externs=externs)
rothwell 2014/12/18 22:30:48 why return an error string if it's just going to b
Dan Beam 2015/02/25 03:36:49 it is used here: https://code.google.com/p/chromiu
253 if exit != 0: 253 if exit != 0:
254 sys.exit(exit) 254 sys.exit(exit)
255 255
256 if opts.out_file: 256 if opts.out_file:
257 out_dir = os.path.dirname(opts.out_file) 257 out_dir = os.path.dirname(opts.out_file)
258 if not os.path.exists(out_dir): 258 if not os.path.exists(out_dir):
259 os.makedirs(out_dir) 259 os.makedirs(out_dir)
260 # TODO(dbeam): write compiled file to |opts.out_file|. 260 # TODO(dbeam): write compiled file to |opts.out_file|.
261 open(opts.out_file, "w").write("") 261 open(opts.out_file, "w").write("")
rothwell 2014/12/18 22:30:47 it seems confusing to write an empty file - should
Dan Beam 2015/02/25 03:36:49 this empty file is used by the build system for in
OLDNEW
« no previous file with comments | « no previous file | third_party/closure_compiler/processor.py » ('j') | third_party/closure_compiler/processor.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698