| OLD | NEW |
| 1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 # for details. All rights reserved. Use of this source code is governed by a | 2 # for details. All rights reserved. Use of this source code is governed by a |
| 3 # BSD-style license that can be found in the LICENSE file. | 3 # BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #!/usr/bin/env python | 5 #!/usr/bin/env python |
| 6 # | 6 # |
| 7 | 7 |
| 8 """Rewrites HTML files, converting Dart script sections into JavaScript. | 8 """Rewrites HTML files, converting Dart script sections into JavaScript. |
| 9 | 9 |
| 10 Process HTML files, and internally changes script sections that use Dart code | 10 Process HTML files, and internally changes script sections that use Dart code |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 sys.path.append(TOOLS_PATH) | 24 sys.path.append(TOOLS_PATH) |
| 25 import utils | 25 import utils |
| 26 | 26 |
| 27 DART_MIME_TYPE = "application/dart" | 27 DART_MIME_TYPE = "application/dart" |
| 28 LIBRARY_PATTERN = "^#library\(.*\);" | 28 LIBRARY_PATTERN = "^#library\(.*\);" |
| 29 IMPORT_SOURCE_MATCHER = re.compile( | 29 IMPORT_SOURCE_MATCHER = re.compile( |
| 30 r"^ *(#import|#source)(\(['\"])([^'\"]*)(.*\);)", re.MULTILINE) | 30 r"^ *(#import|#source)(\(['\"])([^'\"]*)(.*\);)", re.MULTILINE) |
| 31 DOM_IMPORT_MATCHER = re.compile( | 31 DOM_IMPORT_MATCHER = re.compile( |
| 32 r"^#import\(['\"]dart\:dom['\"].*\);", re.MULTILINE) | 32 r"^#import\(['\"]dart\:dom['\"].*\);", re.MULTILINE) |
| 33 HTML_NO_PREFIX_IMPORT_MATCHER = re.compile( | 33 HTML_IMPORT_MATCHER = re.compile( |
| 34 r"^#import.*(dart:html|html.dart)['\"]\);", re.MULTILINE) | 34 r"^#import\(['\"]dart\:html['\"].*\);", re.MULTILINE) |
| 35 JSON_IMPORT_MATCHER = re.compile( | |
| 36 r"^#import\(['\"]dart:json['\"].*\);", re.MULTILINE) | |
| 37 | |
| 38 DARTC_NOT_FOUND_ERROR = ( | |
| 39 """Couldn't find compiler: please run the following commands: | |
| 40 $ cd %s | |
| 41 $ ./tools/build.py --arch=ia32""") | |
| 42 | 35 |
| 43 FROG_NOT_FOUND_ERROR = ( | 36 FROG_NOT_FOUND_ERROR = ( |
| 44 """Couldn't find compiler: please run the following commands: | 37 """Couldn't find compiler: please run the following commands: |
| 45 $ cd %s/frog | 38 $ cd %s/frog |
| 46 $ ./tools/build.py -m release""") | 39 $ ./tools/build.py -m release""") |
| 47 | 40 |
| 48 ENTRY_POINT = """ | 41 ENTRY_POINT_DOM = """ |
| 49 #library('entry'); | 42 #library('entry'); |
| 50 #import('dart:dom'); | 43 #import('dart:dom'); |
| 51 #import('%s', prefix: 'original'); | 44 #import('%s', prefix: 'original'); |
| 52 main() { | 45 main() { |
| 53 window.addEventListener('DOMContentLoaded', (e) => original.main(), false); | 46 window.addEventListener('DOMContentLoaded', (e) => original.main(), false); |
| 54 } | 47 } |
| 55 """ | 48 """ |
| 56 | 49 |
| 50 ENTRY_POINT_HTML = """ |
| 51 #library('entry'); |
| 52 #import('dart:html'); |
| 53 #import('%s', prefix: 'original'); |
| 54 main() { |
| 55 window.on.contentLoaded.add((e) => original.main()); |
| 56 } |
| 57 """ |
| 58 |
| 57 CSS_TEMPLATE = '<style type="text/css">%s</style>' | 59 CSS_TEMPLATE = '<style type="text/css">%s</style>' |
| 58 CHROMIUM_SCRIPT_TEMPLATE = '<script type="application/javascript">%s</script>' | 60 CHROMIUM_SCRIPT_TEMPLATE = '<script type="application/javascript">%s</script>' |
| 59 | 61 |
| 60 DARTIUM_TO_JS_SCRIPT = """ | 62 DARTIUM_TO_JS_SCRIPT = """ |
| 61 <script type="text/javascript"> | 63 <script type="text/javascript"> |
| 62 (function() { | 64 (function() { |
| 63 // Let the user know that Dart is required. | 65 // Let the user know that Dart is required. |
| 64 if (!document.implementation.hasFeature('Dart')) { | 66 if (!window.navigator.webkitStartDart) { |
| 65 if (confirm( | 67 if (confirm( |
| 66 "You are trying to run Dart code on a browser " + | 68 "You are trying to run Dart code on a browser " + |
| 67 "that doesn't support Dart. Do you want to redirect to " + | 69 "that doesn't support Dart. Do you want to redirect to " + |
| 68 "a version compiled to JavaScript instead?")) { | 70 "a version compiled to JavaScript instead?")) { |
| 69 var addr = window.location; | 71 var addr = window.location; |
| 70 window.location = addr.toString().replace('-dart.html', '-js.html'); | 72 window.location = addr.toString().replace('-dart.html', '-js.html'); |
| 71 } | 73 } |
| 74 } else { |
| 75 window.navigator.webkitStartDart(); |
| 72 } | 76 } |
| 73 })(); | 77 })(); |
| 74 </script> | 78 </script> |
| 75 """ | 79 """ |
| 76 | 80 |
| 77 def adjustImports(contents): | 81 def adjustImports(contents): |
| 78 def repl(matchobj): | 82 def repl(matchobj): |
| 79 path = matchobj.group(3) | 83 path = matchobj.group(3) |
| 80 if not path.startswith('dart:'): | 84 if not path.startswith('dart:'): |
| 81 path = abspath(path) | 85 path = abspath(path) |
| 82 return (matchobj.group(1) + matchobj.group(2) + path + matchobj.group(4)) | 86 return (matchobj.group(1) + matchobj.group(2) + path + matchobj.group(4)) |
| 83 return IMPORT_SOURCE_MATCHER.sub(repl, contents) | 87 return IMPORT_SOURCE_MATCHER.sub(repl, contents) |
| 84 | 88 |
| 85 class DartCompiler(object): | 89 class DartCompiler(object): |
| 86 """ Common code for compiling Dart script tags in an HTML file. """ | 90 """ Common code for compiling Dart script tags in an HTML file. """ |
| 87 | 91 |
| 88 def __init__(self, optimize=False, use_frog=False, verbose=False, | 92 def __init__(self, verbose=False, |
| 89 extra_flags=""): | 93 extra_flags=""): |
| 90 self.optimize = optimize | |
| 91 self.verbose = verbose | 94 self.verbose = verbose |
| 92 self.extra_flags = extra_flags | 95 self.extra_flags = extra_flags |
| 93 self.use_frog = use_frog | |
| 94 | 96 |
| 95 def compileCode(self, src=None, body=None): | 97 def compileCode(self, src=None, body=None): |
| 96 """ Compile the given source code. | 98 """ Compile the given source code. |
| 97 | 99 |
| 98 Either the script tag has a src attribute or a non-empty body (one of the | 100 Either the script tag has a src attribute or a non-empty body (one of the |
| 99 arguments will be none, the other is not). | 101 arguments will be none, the other is not). |
| 100 | 102 |
| 101 Args: | 103 Args: |
| 102 src: a string pointing to a Dart script file. | 104 src: a string pointing to a Dart script file. |
| 103 body: a string containing Dart code. | 105 body: a string containing Dart code. |
| 104 """ | 106 """ |
| 105 | 107 |
| 106 outdir = tempfile.mkdtemp() | 108 outdir = tempfile.mkdtemp() |
| 107 indir = None | 109 indir = None |
| 110 useDartHtml = False |
| 108 if src is not None: | 111 if src is not None: |
| 109 if body is not None and body.strip() != '': | 112 if body is not None and body.strip() != '': |
| 110 raise ConverterException( | 113 raise ConverterException( |
| 111 "The script body should be empty if src is specified") | 114 "The script body should be empty if src is specified") |
| 112 elif src.endswith('.dart'): | 115 elif src.endswith('.dart'): |
| 113 indir = tempfile.mkdtemp() | 116 indir = tempfile.mkdtemp() |
| 114 inputfile = abspath(src) | 117 inputfile = abspath(src) |
| 115 with open(inputfile, 'r') as f: | 118 with open(inputfile, 'r') as f: |
| 116 contents = f.read(); | 119 contents = f.read(); |
| 117 | 120 |
| 121 if HTML_IMPORT_MATCHER.search(contents): |
| 122 useDartHtml = True |
| 123 |
| 118 # We will import the source file to emulate in JS that code is run after | 124 # We will import the source file to emulate in JS that code is run after |
| 119 # DOMContentLoaded. We need a #library to ensure #import won't fail: | 125 # DOMContentLoaded. We need a #library to ensure #import won't fail: |
| 120 if not re.search(LIBRARY_PATTERN, contents, re.MULTILINE): | 126 if not re.search(LIBRARY_PATTERN, contents, re.MULTILINE): |
| 121 inputfile = join(indir, 'code.dart') | 127 inputfile = join(indir, 'code.dart') |
| 122 with open(inputfile, 'w') as f: | 128 with open(inputfile, 'w') as f: |
| 123 f.write("#library('code');") | 129 f.write("#library('code');") |
| 124 f.write(adjustImports(contents)) | 130 f.write(adjustImports(contents)) |
| 125 | 131 |
| 126 else: | 132 else: |
| 127 raise ConverterException("invalid file type:" + src) | 133 raise ConverterException("invalid file type:" + src) |
| 128 else: | 134 else: |
| 129 if body is None or body.strip() == '': | 135 if body is None or body.strip() == '': |
| 130 # nothing to do | 136 # nothing to do |
| 131 print 'Warning: empty script tag with no src attribute' | 137 print 'Warning: empty script tag with no src attribute' |
| 132 return '' | 138 return '' |
| 133 | 139 |
| 134 indir = tempfile.mkdtemp() | 140 indir = tempfile.mkdtemp() |
| 135 # eliminate leading spaces in front of directives | 141 # eliminate leading spaces in front of directives |
| 136 body = adjustImports(body) | 142 body = adjustImports(body) |
| 137 | 143 |
| 144 if HTML_IMPORT_MATCHER.search(body): |
| 145 useDartHtml = True |
| 146 |
| 138 inputfile = join(indir, 'code.dart') | 147 inputfile = join(indir, 'code.dart') |
| 139 with open(inputfile, 'w') as f: | 148 with open(inputfile, 'w') as f: |
| 140 f.write("#library('inlinedcode');\n") | 149 f.write("#library('inlinedcode');\n") |
| 141 # dom and json are added by default | |
| 142 if not DOM_IMPORT_MATCHER.search(body): | |
| 143 f.write("#import('dart:dom');\n") | |
| 144 if not JSON_IMPORT_MATCHER.search(body): | |
| 145 f.write("#import('dart:json');\n") | |
| 146 # html import will conflict with DOM import | |
| 147 if HTML_NO_PREFIX_IMPORT_MATCHER.search(body): | |
| 148 raise ConverterException( | |
| 149 'Can\'t import "dom:html" or "html.dart" from scripts inlined ' + | |
| 150 'in the page without a prefix. This import conflicts with an ' + | |
| 151 ' import of "dart:dom" that is injected automatically.') | |
| 152 f.write(body) | 150 f.write(body) |
| 153 | 151 |
| 152 if useDartHtml: |
| 153 entryPoint = ENTRY_POINT_HTML |
| 154 else: |
| 155 entryPoint = ENTRY_POINT_DOM |
| 156 |
| 154 wrappedfile = join(indir, 'entry.dart') | 157 wrappedfile = join(indir, 'entry.dart') |
| 155 with open(wrappedfile, 'w') as f: | 158 with open(wrappedfile, 'w') as f: |
| 156 f.write(ENTRY_POINT % inputfile) | 159 f.write(entryPoint % inputfile) |
| 157 | 160 |
| 158 status, out, err = execute(self.compileCommand(wrappedfile, outdir), | 161 status, out, err = execute(self.compileCommand(wrappedfile, outdir), |
| 159 self.verbose) | 162 self.verbose) |
| 160 if status: | 163 if status: |
| 161 raise ConverterException('compilation errors found by dartc') | 164 raise ConverterException('compilation errors') |
| 162 | 165 |
| 163 # Inline the compiled code in the page | 166 # Inline the compiled code in the page |
| 164 with open(self.outputFileName(wrappedfile, outdir), 'r') as f: | 167 with open(self.outputFileName(wrappedfile, outdir), 'r') as f: |
| 165 res = f.read() | 168 res = f.read() |
| 166 | 169 |
| 167 # Cleanup | 170 # Cleanup |
| 168 if indir is not None: | 171 if indir is not None: |
| 169 shutil.rmtree(indir) | 172 shutil.rmtree(indir) |
| 170 shutil.rmtree(outdir) | 173 shutil.rmtree(outdir) |
| 171 return CHROMIUM_SCRIPT_TEMPLATE % res | 174 return CHROMIUM_SCRIPT_TEMPLATE % res |
| 172 | 175 |
| 173 def compileCommand(self, inputfile, outdir): | 176 def compileCommand(self, inputfile, outdir): |
| 174 if not self.use_frog: | 177 binary = abspath(join(DART_PATH, |
| 175 binary = abspath(join(DART_PATH, | 178 utils.GetBuildRoot(utils.GuessOS(), |
| 176 # TODO(sigmund): support also mode = release | 179 'release', 'ia32'), |
| 177 utils.GetBuildRoot(utils.GuessOS(), 'debug', 'ia32'), | 180 'frog', 'bin', 'frogsh')) |
| 178 'dartc')) | 181 if not exists(binary): |
| 179 if not exists(binary): | 182 raise ConverterException(FROG_NOT_FOUND_ERROR % DART_PATH) |
| 180 raise ConverterException(DARTC_NOT_FOUND_ERROR % DART_PATH) | 183 |
| 181 cmd = [binary, | 184 cmd = [binary, '--compile-only', |
| 182 '-noincremental', | 185 '--libdir=' + join(DART_PATH, 'frog', 'lib'), |
| 183 '--work', outdir, | 186 '--out=' + self.outputFileName(inputfile, outdir)] |
| 184 '--out', self.outputFileName(inputfile, outdir)] | |
| 185 if self.optimize: | |
| 186 cmd.append('--optimize') | |
| 187 else: | |
| 188 binary = abspath(join(DART_PATH, | |
| 189 utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32'), | |
| 190 'frog', 'bin', 'frogsh')) | |
| 191 if not exists(binary): | |
| 192 raise ConverterException(FROG_NOT_FOUND_ERROR % DART_PATH) | |
| 193 cmd = [binary, '--compile-only', | |
| 194 '--libdir=' + join(DART_PATH, 'frog', 'lib'), | |
| 195 '--out=' + self.outputFileName(inputfile, outdir)] | |
| 196 if self.extra_flags != "": | 187 if self.extra_flags != "": |
| 197 cmd.append(self.extra_flags); | 188 cmd.append(self.extra_flags); |
| 198 cmd.append(inputfile) | 189 cmd.append(inputfile) |
| 199 return cmd | 190 return cmd |
| 200 | 191 |
| 201 def outputFileName(self, inputfile, outdir): | 192 def outputFileName(self, inputfile, outdir): |
| 202 return join(outdir, basename(inputfile) + '.js') | 193 return join(outdir, basename(inputfile) + '.js') |
| 203 | 194 |
| 204 def execute(cmd, verbose=False): | 195 def execute(cmd, verbose=False): |
| 205 """Execute a command in a subprocess. """ | 196 """Execute a command in a subprocess. """ |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 if not exists(dirname): | 466 if not exists(dirname): |
| 476 raise | 467 raise |
| 477 | 468 |
| 478 class ConverterException(Exception): | 469 class ConverterException(Exception): |
| 479 """ An exception encountered during the convertion process """ | 470 """ An exception encountered during the convertion process """ |
| 480 pass | 471 pass |
| 481 | 472 |
| 482 def Flags(): | 473 def Flags(): |
| 483 """ Constructs a parser for extracting flags from the command line. """ | 474 """ Constructs a parser for extracting flags from the command line. """ |
| 484 result = optparse.OptionParser() | 475 result = optparse.OptionParser() |
| 485 result.add_option("--optimize", | |
| 486 help="Use optimizer in dartc", | |
| 487 default=False, | |
| 488 action="store_true") | |
| 489 result.add_option("--frog", | |
| 490 help="Use the frog compiler", | |
| 491 default=False, | |
| 492 action="store_true") | |
| 493 result.add_option("--verbose", | 476 result.add_option("--verbose", |
| 494 help="Print verbose output", | 477 help="Print verbose output", |
| 495 default=False, | 478 default=False, |
| 496 action="store_true") | 479 action="store_true") |
| 497 result.add_option("-o", "--out", | 480 result.add_option("-o", "--out", |
| 498 help="Output directory", | 481 help="Output directory", |
| 499 type="string", | 482 type="string", |
| 500 default=None, | 483 default=None, |
| 501 action="store") | 484 action="store") |
| 502 result.add_option("-t", "--target", | 485 result.add_option("-t", "--target", |
| (...skipping 21 matching lines...) Expand all Loading... |
| 524 prefix_path = dirname(filename) | 507 prefix_path = dirname(filename) |
| 525 | 508 |
| 526 # outdirBase is the directory to place all subdirectories for other dart files | 509 # outdirBase is the directory to place all subdirectories for other dart files |
| 527 # and resources. | 510 # and resources. |
| 528 converter = DartToDartHTMLConverter(prefix_path, outdirBase, verbose) | 511 converter = DartToDartHTMLConverter(prefix_path, outdirBase, verbose) |
| 529 converter.feed(contents) | 512 converter.feed(contents) |
| 530 converter.close() | 513 converter.close() |
| 531 writeOut(converter.getResult(), outfile) | 514 writeOut(converter.getResult(), outfile) |
| 532 | 515 |
| 533 def convertForChromium( | 516 def convertForChromium( |
| 534 filename, optimize, use_frog, extra_flags, outfile, verbose): | 517 filename, extra_flags, outfile, verbose): |
| 535 """ Converts a file for a chromium target. """ | 518 """ Converts a file for a chromium target. """ |
| 536 with open(filename, 'r') as f: | 519 with open(filename, 'r') as f: |
| 537 contents = f.read() | 520 contents = f.read() |
| 538 prefix_path = dirname(filename) | 521 prefix_path = dirname(filename) |
| 539 converter = DartHTMLConverter( | 522 converter = DartHTMLConverter( |
| 540 DartCompiler(optimize, use_frog, verbose, extra_flags), prefix_path) | 523 DartCompiler(verbose, extra_flags), prefix_path) |
| 541 converter.feed(contents) | 524 converter.feed(contents) |
| 542 converter.close() | 525 converter.close() |
| 543 writeOut(converter.getResult(), outfile) | 526 writeOut(converter.getResult(), outfile) |
| 544 | 527 |
| 545 def convertForOffline(filename, outfile, verbose, encode_images): | 528 def convertForOffline(filename, outfile, verbose, encode_images): |
| 546 """ Converts a file for offline use. """ | 529 """ Converts a file for offline use. """ |
| 547 with codecs.open(filename, 'r', 'utf-8') as f: | 530 with codecs.open(filename, 'r', 'utf-8') as f: |
| 548 contents = f.read() | 531 contents = f.read() |
| 549 converter = OfflineHTMLConverter(dirname(filename), | 532 converter = OfflineHTMLConverter(dirname(filename), |
| 550 dirname(outfile), | 533 dirname(outfile), |
| (...skipping 19 matching lines...) Expand all Loading... |
| 570 return 1 | 553 return 1 |
| 571 | 554 |
| 572 try: | 555 try: |
| 573 filename = args[0] | 556 filename = args[0] |
| 574 extension = filename[filename.rfind('.'):] | 557 extension = filename[filename.rfind('.'):] |
| 575 if extension != '.html' and extension != '.htm': | 558 if extension != '.html' and extension != '.htm': |
| 576 print "Invalid input file extension: %s" % extension | 559 print "Invalid input file extension: %s" % extension |
| 577 return 1 | 560 return 1 |
| 578 outfile = join(options.out, filename) | 561 outfile = join(options.out, filename) |
| 579 if 'chromium' in options.target or 'js' in options.target: | 562 if 'chromium' in options.target or 'js' in options.target: |
| 580 convertForChromium(filename, options.optimize, | 563 convertForChromium(filename, |
| 581 options.frog, options.extra_flags, | 564 options.extra_flags, |
| 582 outfile.replace(extension, '-js' + extension), options.verbose) | 565 outfile.replace(extension, '-js' + extension), options.verbose) |
| 583 if 'dartium' in options.target: | 566 if 'dartium' in options.target: |
| 584 convertForDartium(filename, options.out, | 567 convertForDartium(filename, options.out, |
| 585 outfile.replace(extension, '-dart' + extension), options.verbose) | 568 outfile.replace(extension, '-dart' + extension), options.verbose) |
| 586 except Exception as e: | 569 except Exception as e: |
| 587 print "%sERROR%s: %s" % (RED_COLOR, NO_COLOR, str(e)) | 570 print "%sERROR%s: %s" % (RED_COLOR, NO_COLOR, str(e)) |
| 588 return 1 | 571 return 1 |
| 589 return 0 | 572 return 0 |
| 590 | 573 |
| 591 if __name__ == '__main__': | 574 if __name__ == '__main__': |
| 592 sys.exit(main()) | 575 sys.exit(main()) |
| OLD | NEW |