Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 4 # for details. All rights reserved. Use of this source code is governed by a | 4 # for details. All rights reserved. Use of this source code is governed by a |
| 5 # BSD-style license that can be found in the LICENSE file. | 5 # BSD-style license that can be found in the LICENSE file. |
| 6 # | 6 # |
| 7 | 7 |
| 8 """ | 8 """ |
| 9 Generates an html file (frogpad.html) that can be used to execute the frog | 9 Generates an html file (frogpad.html) that can be used to execute the frog |
| 10 compiler in a web browser or DumpRenderTree, | 10 compiler in a web browser or DumpRenderTree, |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 <body> | 84 <body> |
| 85 <h1>Frogpad</h1> | 85 <h1>Frogpad</h1> |
| 86 <div class="label">Input:</div> | 86 <div class="label">Input:</div> |
| 87 <textarea id="input"></textarea> | 87 <textarea id="input"></textarea> |
| 88 <div class="label">Compiler Messages:</div> | 88 <div class="label">Compiler Messages:</div> |
| 89 <pre id="warnings"></pre> | 89 <pre id="warnings"></pre> |
| 90 <div class="label">Timing:</div> | 90 <div class="label">Timing:</div> |
| 91 <pre id="timing"></pre> | 91 <pre id="timing"></pre> |
| 92 <div class="label">Output:</div> | 92 <div class="label">Output:</div> |
| 93 <pre id="output"></pre> | 93 <pre id="output"></pre> |
| 94 <script type="text/javascript" src={{FROGPAD_JS}} ></script> | 94 <script type="text/javascript"> |
| 95 {{FROGPAD_JS}} | |
|
Siggi Cherem (dart-lang)
2012/02/23 16:43:26
note that this approach works ok on any code that
| |
| 96 </script> | |
| 95 </body> | 97 </body> |
| 96 </html> | 98 </html> |
| 97 """ | 99 """ |
| 98 | 100 |
| 99 # We use "application/inert" here to make the browser ignore the | 101 # We use "application/inert" here to make the browser ignore the |
| 100 # these script tags. (frogpad.dart will fish out the contents as needed.) | 102 # these script tags. (frogpad.dart will fish out the contents as needed.) |
| 101 # | 103 # |
| 102 SCRIPT_TAG = """<script type="application/inert" id="{{id}}"> | 104 SCRIPT_TAG = """<script type="application/inert" id="{{id}}"> |
| 103 {{contents}} | 105 {{contents}} |
| 104 </script> | 106 </script> |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 126 class Pad(object): | 128 class Pad(object): |
| 127 """ | 129 """ |
| 128 Accumulates all source files that are needed to compile a dart program, | 130 Accumulates all source files that are needed to compile a dart program, |
| 129 and places them in <script> tags on an html page. | 131 and places them in <script> tags on an html page. |
| 130 """ | 132 """ |
| 131 | 133 |
| 132 def __init__(self, argv): | 134 def __init__(self, argv): |
| 133 parser = optparse.OptionParser() | 135 parser = optparse.OptionParser() |
| 134 parser.add_option("-r", "--rebuild", action="store_true", | 136 parser.add_option("-r", "--rebuild", action="store_true", |
| 135 help="forces rebuild of frogpad_js") | 137 help="forces rebuild of frogpad_js") |
| 138 parser.add_option("-o", "--out", | |
| 139 help="name of javascript output file") | |
| 136 (options, args) = parser.parse_args(argv) | 140 (options, args) = parser.parse_args(argv) |
| 137 | 141 |
| 138 if len(args) < 2: | 142 if len(args) < 2: |
| 139 usage() | 143 usage() |
| 140 | 144 |
| 141 self.main_file = os.path.abspath(args[1]) | 145 self.main_file = os.path.abspath(args[1]) |
| 142 | 146 |
| 143 # directory of this script | 147 # directory of this script |
| 144 self.frogpad_dir = os.path.abspath(os.path.dirname(argv[0])) | 148 self.frogpad_dir = os.path.abspath(os.path.dirname(argv[0])) |
| 145 | 149 |
| 146 # root of dart source repo | 150 # root of dart source repo |
| 147 self.dart_dir = os.path.dirname(os.path.dirname(os.path.dirname( | 151 self.dart_dir = os.path.dirname(os.path.dirname(os.path.dirname( |
| 148 self.frogpad_dir))) | 152 self.frogpad_dir))) |
| 149 | 153 |
| 150 # directory of frog compiler source code | 154 # directory of frog compiler source code |
| 151 self.frog_dir = os.path.join(self.dart_dir, "frog") | 155 self.frog_dir = os.path.join(self.dart_dir, "frog") |
| 152 | 156 |
| 153 logging.debug("dartdir_dir: '%s'" % self.dart_dir) | 157 logging.debug("dartdir_dir: '%s'" % self.dart_dir) |
| 154 logging.debug("frog_dir: '%s'" % self.frog_dir) | 158 logging.debug("frog_dir: '%s'" % self.frog_dir) |
| 155 logging.debug("frogpad_dir: '%s'" % self.frogpad_dir) | 159 logging.debug("frogpad_dir: '%s'" % self.frogpad_dir) |
| 156 | 160 |
| 157 # name of frogpad_js file | 161 # name of frogpad_js file |
| 158 self.frogpad_js = os.path.join(self.frogpad_dir, FROGPAD_JS) | 162 self.frogpad_js = os.path.join(self.frogpad_dir, FROGPAD_JS) |
| 159 | 163 |
| 160 html_file = self.main_file + ".frogpad.html" | 164 if options.out: |
| 165 # user has specified an output file | |
| 166 self.js_file = os.path.abspath(options.out) | |
| 167 else: | |
| 168 # user didn't specify an output file, so base the name on the | |
| 169 # input file | |
| 170 self.js_file = self.main_file + ".frogpad.js" | |
| 171 | |
| 172 logging.debug("js_file: '%s" % self.js_file) | |
| 173 | |
| 174 # this is the html file that we pass to DumpRenderTree | |
| 175 self.html_file = self.js_file + ".frogpad.html" | |
| 176 logging.debug("html_file: '%s'" % self.html_file) | |
| 161 | 177 |
| 162 # map from file name to File object (contains entries for all corelib | 178 # map from file name to File object (contains entries for all corelib |
| 163 # and all other dart files needed to compile main_file) | 179 # and all other dart files needed to compile main_file) |
| 164 self.name_to_file = {} | 180 self.name_to_file = {} |
| 165 | 181 |
| 166 # map from script tag id to File object | 182 # map from script tag id to File object |
| 167 self.id_to_file = {} | 183 self.id_to_file = {} |
| 168 | 184 |
| 169 if not os.path.exists(self.frogpad_js): | 185 if not os.path.exists(self.frogpad_js): |
| 170 options.rebuild = True | 186 options.rebuild = True |
| 171 | 187 |
| 172 if options.rebuild: | 188 if options.rebuild: |
| 173 self.build_frogpad_js() | 189 self.build_frogpad_js() |
| 174 | 190 |
| 175 self.load_libraries() | 191 self.load_libraries() |
| 176 self.load_file(self.main_file) | 192 self.load_file(self.main_file) |
| 177 | 193 |
| 178 html = self.generate_html() | 194 html = self.generate_html() |
| 195 write_file(self.html_file, html) | |
| 179 | 196 |
| 180 with open(html_file, "w") as output: | 197 js = self.generate_js() |
| 181 output.write(html) | 198 logging.debug("found javascript in drt output (%d lines)", |
| 182 logging.info("generated '%s' (%d bytes)" % (html_file, len(html))) | 199 len(js.splitlines())) |
| 183 | 200 write_file(self.js_file, js) |
| 201 logging.info("generated '%s'", self.js_file) | |
| 184 | 202 |
| 185 def build_frogpad_js(self): | 203 def build_frogpad_js(self): |
| 186 dart_vm = os.path.join(self.dart_dir, "out/Release_ia32/dart") | 204 dart_vm = os.path.join(self.dart_dir, "out/Release_ia32/dart") |
| 187 check_exists(dart_vm) | 205 check_exists(dart_vm) |
| 188 | 206 |
| 189 frogc_dart = os.path.join(self.frog_dir, "frogc.dart") | 207 frogc_dart = os.path.join(self.frog_dir, "frogc.dart") |
| 190 frogpad_dart = os.path.join(self.frogpad_dir, "frogpad.dart") | 208 frogpad_dart = os.path.join(self.frogpad_dir, "frogpad.dart") |
| 191 check_exists(frogc_dart) | 209 check_exists(frogc_dart) |
| 192 check_exists(frogpad_dart) | 210 check_exists(frogpad_dart) |
| 193 | 211 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 216 | 234 |
| 217 run_command(args) | 235 run_command(args) |
| 218 check_exists(self.frogpad_js) | 236 check_exists(self.frogpad_js) |
| 219 | 237 |
| 220 def generate_html(self): | 238 def generate_html(self): |
| 221 tags = [] | 239 tags = [] |
| 222 for f in self.id_to_file.values(): | 240 for f in self.id_to_file.values(): |
| 223 tags.append(self._create_tag(f.id, f.contents)) | 241 tags.append(self._create_tag(f.id, f.contents)) |
| 224 tags.append(self._create_tag(MAIN_ID, self.main_file)) | 242 tags.append(self._create_tag(MAIN_ID, self.main_file)) |
| 225 html = HTML.replace("{{script_tags}}", "".join(tags)) | 243 html = HTML.replace("{{script_tags}}", "".join(tags)) |
| 226 html = html.replace("{{FROGPAD_JS}}", FROGPAD_JS) | 244 html = html.replace("{{FROGPAD_JS}}", read_file(self.frogpad_js)) |
| 227 return html | 245 return html |
| 228 | 246 |
| 247 def generate_js(self): | |
| 248 drt = os.path.join(self.dart_dir, "client/tests/drt/DumpRenderTree") | |
| 249 check_exists(drt) | |
| 250 args = [] | |
|
Jennifer Messerly
2012/02/23 03:24:49
args = [drt, self.html_file]
or just:
stdout = r
mattsh
2012/02/23 04:13:03
Actually I think I kind of like it this way in cas
Siggi Cherem (dart-lang)
2012/02/23 16:43:26
a pattern I've seen so far is to use inline lists
| |
| 251 args.append(drt) | |
| 252 args.append(self.html_file) | |
| 253 | |
| 254 stdout = run_command(args) | |
| 255 match = re.match("(?s).*Output:(.*)#EOF", stdout) | |
|
Siggi Cherem (dart-lang)
2012/02/23 16:43:26
I think it is better to check that 'Output:' is at
Emily Fortuna
2012/02/23 21:38:50
+1
| |
| 256 if not match: | |
| 257 raise Exception("can't find regex in DumpRenderTree output") | |
|
Emily Fortuna
2012/02/23 21:38:50
Possibly print the regex you were looking for in t
| |
| 258 return match.group(1) | |
| 259 | |
| 229 @staticmethod | 260 @staticmethod |
| 230 def _create_tag(id, contents): | 261 def _create_tag(id, contents): |
| 231 s = SCRIPT_TAG | 262 s = SCRIPT_TAG |
| 232 s = s.replace("{{id}}", id) | 263 s = s.replace("{{id}}", id) |
| 233 s = s.replace("{{contents}}", contents) | 264 s = s.replace("{{contents}}", contents) |
| 234 return s | 265 return s |
| 235 | 266 |
| 236 def dart_library(self, name): | 267 def dart_library(self, name): |
| 237 path = DART_LIBRARIES[name] | 268 path = DART_LIBRARIES[name] |
| 238 if not path: | 269 if not path: |
| 239 raise Exception("unrecognized 'dart:%s'", name) | 270 raise Exception("unrecognized 'dart:%s'", name) |
| 240 return os.path.join(self.frog_dir, path) | 271 return os.path.join(self.frog_dir, path) |
| 241 | 272 |
| 242 def load_libraries(self): | 273 def load_libraries(self): |
| 243 for name in DART_LIBRARIES: | 274 for name in DART_LIBRARIES: |
| 244 self.load_file(self.dart_library(name)) | 275 self.load_file(self.dart_library(name)) |
| 245 | 276 |
| 246 def load_file(self, name): | 277 def load_file(self, name): |
| 247 logging.debug("load_file " + name) | |
| 248 name = os.path.abspath(name) | 278 name = os.path.abspath(name) |
| 249 if name in self.name_to_file: | 279 if name in self.name_to_file: |
| 250 logging.debug("already loaded %s, skipping" % name) | |
| 251 return | 280 return |
| 252 f = File(self, name) | 281 f = File(self, name) |
| 253 self.name_to_file[f.name] = f | 282 self.name_to_file[f.name] = f |
| 254 if f.id in self.id_to_file: | 283 if f.id in self.id_to_file: |
| 255 raise Exception("ambiguous id '%s'" % f.id) | 284 raise Exception("ambiguous id '%s'" % f.id) |
| 256 self.id_to_file[f.id] = f | 285 self.id_to_file[f.id] = f |
| 257 f.directives() | 286 f.directives() |
| 258 | 287 |
| 259 class File(object): | 288 class File(object): |
| 260 def __init__(self, pad, name): | 289 def __init__(self, pad, name): |
| 261 self.pad = pad | 290 self.pad = pad |
| 262 self.name = name | 291 self.name = name |
| 263 self.id = self._make_id() | 292 self.id = self._make_id() |
| 264 check_exists(name) | 293 check_exists(name) |
| 265 with open(self.name, "r") as f: | 294 with open(self.name, "r") as f: |
| 266 self.contents = f.read() | 295 self.contents = f.read() |
| 267 logging.debug("creating File '%s' (%d lines)" % | |
| 268 (self.name, len(self.contents))) | |
| 269 | 296 |
| 270 def _make_id(self): | 297 def _make_id(self): |
| 271 """ | 298 """ |
| 272 Generates an id (based on the file name) for the <script> tag that will | 299 Generates an id (based on the file name) for the <script> tag that will |
| 273 hold the contents of this file. | 300 hold the contents of this file. |
| 274 """ | 301 """ |
| 275 (dirname, name) = os.path.split(self.name) | 302 (dirname, name) = os.path.split(self.name) |
| 276 dirname = os.path.basename(dirname) | 303 dirname = os.path.basename(dirname) |
| 277 name = name.replace(".", "_") | 304 name = name.replace(".", "_") |
| 278 return dirname + "_" + name | 305 return dirname + "_" + name |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 289 match = DIRECTIVE_RE.match(line) | 316 match = DIRECTIVE_RE.match(line) |
| 290 if not match: | 317 if not match: |
| 291 return | 318 return |
| 292 url = match.group(2) | 319 url = match.group(2) |
| 293 if url.startswith("dart:"): | 320 if url.startswith("dart:"): |
| 294 path = self.pad.dart_library(url[len("dart:"):]) | 321 path = self.pad.dart_library(url[len("dart:"):]) |
| 295 else: | 322 else: |
| 296 path = os.path.join(os.path.dirname(self.name), url) | 323 path = os.path.join(os.path.dirname(self.name), url) |
| 297 self.pad.load_file(path) | 324 self.pad.load_file(path) |
| 298 | 325 |
| 326 def read_file(file_name): | |
| 327 check_exists(file_name) | |
| 328 with open(file_name, "r") as input: | |
| 329 contents = input.read() | |
| 330 logging.debug("read_file '%s' (%d bytes)" % (file_name, len(contents))) | |
| 331 return contents | |
| 332 | |
| 333 def write_file(file_name, contents): | |
| 334 with open(file_name, "w") as output: | |
| 335 output.write(contents) | |
| 336 | |
| 337 check_exists(file_name) | |
| 338 logging.debug("write_file '%s' (%d bytes)" % (file_name, len(contents))) | |
| 339 | |
| 299 | 340 |
| 300 def check_exists(file_name): | 341 def check_exists(file_name): |
| 301 if not os.path.exists(file_name): | 342 if not os.path.exists(file_name): |
| 302 raise FileNotFoundException(file_name) | 343 raise FileNotFoundException(file_name) |
| 303 | 344 |
| 304 | 345 |
| 305 def format_command(args): | 346 def format_command(args): |
| 306 return ' '.join(args) | 347 return ' '.join(args) |
| 307 | 348 |
| 308 | 349 |
| 309 def run_command(args): | 350 def run_command(args): |
| 310 """ | 351 """ |
| 311 Args: | 352 Args: |
| 312 command: comamnd with arguments to exec | 353 command: comamnd with arguments to exec |
| 354 Returns: | |
| 355 all output that this command sent to stdout | |
| 313 """ | 356 """ |
| 314 | 357 |
| 315 command = format_command(args) | 358 command = format_command(args) |
| 316 logging.info("RUNNING " + command) | 359 logging.debug("RUNNING " + command) |
| 317 proc = subprocess.Popen(args) | 360 child = subprocess.Popen(args, |
| 318 exit_code = proc.wait() | 361 stdout=subprocess.PIPE, |
| 319 | 362 stderr=subprocess.PIPE, |
| 320 if exit_code: | 363 close_fds=True) |
| 364 (stdout, stderr) = child.communicate() | |
| 365 for line in stderr.splitlines(): | |
| 366 logging.info(level, '%s: %s', args[0], line) | |
| 367 exitcode = child.wait() | |
| 368 if exitcode: | |
| 321 msg = "FAILURE (exit_code=%d): '%s'" % (exit_code, command) | 369 msg = "FAILURE (exit_code=%d): '%s'" % (exit_code, command) |
| 322 logging.error(msg) | 370 logging.error(msg) |
| 323 raise CommandFailedException(msg) | 371 raise CommandFailedException(msg) |
| 324 | 372 logging.debug("SUCCEEDED (%d bytes)" % len(stdout)) |
| 325 logging.debug("SUCCEEDED " + command) | 373 return stdout |
| 326 | 374 |
| 327 | 375 |
| 328 def usage(): | 376 def usage(): |
| 329 print(""" | 377 print(""" |
| 330 Usage: | 378 Usage: |
| 331 frogpad.py hello.dart | 379 frogpad.py --out hello.js hello.dart |
| 332 """) | 380 """) |
| 333 sys.exit(1) | 381 sys.exit(1) |
| 334 | 382 |
| 335 | 383 |
| 336 def main(argv): | 384 def main(argv): |
| 337 logging.basicConfig(level=logging.INFO) | 385 logging.basicConfig(level=logging.INFO) |
| 338 Pad(argv) | 386 Pad(argv) |
| 339 | 387 |
| 340 if __name__ == "__main__": | 388 if __name__ == "__main__": |
| 341 sys.exit(main(sys.argv)) | 389 sys.exit(main(sys.argv)) |
| OLD | NEW |