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 |