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

Unified Diff: client/tools/htmlconverter.py

Issue 9977011: get rid of dependency on htmlconverter for everything but swarm. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | client/tools/htmlconverter_test.py » ('j') | samples/dartcombat/README » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/tools/htmlconverter.py
===================================================================
--- client/tools/htmlconverter.py (revision 6168)
+++ client/tools/htmlconverter.py (working copy)
@@ -1,558 +0,0 @@
-# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-#!/usr/bin/env python
-#
-
-"""Rewrites HTML files, converting Dart script sections into JavaScript.
-
-Process HTML files, and internally changes script sections that use Dart code
-into JavaScript sections. It also can optimize the HTML to inline code.
-"""
-
-from HTMLParser import HTMLParser
-import os.path
-from os.path import abspath, basename, dirname, exists, isabs, join
-import base64, re, optparse, os, shutil, subprocess, sys, tempfile, codecs
-import urllib2
-
-CLIENT_PATH = dirname(dirname(abspath(__file__)))
-DART_PATH = dirname(CLIENT_PATH)
-TOOLS_PATH = join(DART_PATH, 'tools')
-
-sys.path.append(TOOLS_PATH)
-import utils
-
-DART_MIME_TYPE = "application/dart"
-LIBRARY_PATTERN = "^#library\(.*\);"
-IMPORT_SOURCE_MATCHER = re.compile(
- r"^ *(#import|#source)(\(['\"])([^'\"]*)(.*\);)", re.MULTILINE)
-DOM_IMPORT_MATCHER = re.compile(
- r"^#import\(['\"]dart\:dom['\"].*\);", re.MULTILINE)
-HTML_IMPORT_MATCHER = re.compile(
- r"^#import\(['\"]dart\:html['\"].*\);", re.MULTILINE)
-
-FROG_NOT_FOUND_ERROR = (
-"""Couldn't find compiler: please run the following commands:
- $ cd %s/frog
- $ ./tools/build.py -m release""")
-
-ENTRY_POINT = """
-#library('entry');
-#import('%s', prefix: 'original');
-main() => original.main();
-"""
-
-CSS_TEMPLATE = '<style type="text/css">%s</style>'
-CHROMIUM_SCRIPT_TEMPLATE = '<script type="application/javascript">%s</script>'
-
-DARTIUM_TO_JS_SCRIPT = """
-<script type="text/javascript">
- (function() {
- // Let the user know that Dart is required.
- if (!window.navigator.webkitStartDart) {
- if (confirm(
- "You are trying to run Dart code on a browser " +
- "that doesn't support Dart. Do you want to redirect to " +
- "a version compiled to JavaScript instead?")) {
- var addr = window.location;
- window.location = addr.toString().replace('-dart.html', '-js.html');
- }
- } else {
- window.navigator.webkitStartDart();
- }
-})();
-</script>
-"""
-
-def adjustImports(contents):
- def repl(matchobj):
- path = matchobj.group(3)
- if not path.startswith('dart:'):
- path = abspath(path)
- return (matchobj.group(1) + matchobj.group(2) + path + matchobj.group(4))
- return IMPORT_SOURCE_MATCHER.sub(repl, contents)
-
-class DartCompiler(object):
- """ Common code for compiling Dart script tags in an HTML file. """
-
- def __init__(self, verbose=False,
- extra_flags=""):
- self.verbose = verbose
- self.extra_flags = extra_flags
-
- def compileCode(self, src=None, body=None):
- """ Compile the given source code.
-
- Either the script tag has a src attribute or a non-empty body (one of the
- arguments will be none, the other is not).
-
- Args:
- src: a string pointing to a Dart script file.
- body: a string containing Dart code.
- """
-
- outdir = tempfile.mkdtemp()
- indir = None
- useDartHtml = False
- if src is not None:
- if body is not None and body.strip() != '':
- raise ConverterException(
- "The script body should be empty if src is specified")
- elif src.endswith('.dart'):
- indir = tempfile.mkdtemp()
- inputfile = abspath(src)
- with open(inputfile, 'r') as f:
- contents = f.read();
-
- if HTML_IMPORT_MATCHER.search(contents):
- useDartHtml = True
-
- # We will import the source file to emulate in JS that code is run after
- # DOMContentLoaded. We need a #library to ensure #import won't fail:
- if not re.search(LIBRARY_PATTERN, contents, re.MULTILINE):
- inputfile = join(indir, 'code.dart')
- with open(inputfile, 'w') as f:
- f.write("#library('code');")
- f.write(adjustImports(contents))
-
- else:
- raise ConverterException("invalid file type:" + src)
- else:
- if body is None or body.strip() == '':
- # nothing to do
- print 'Warning: empty script tag with no src attribute'
- return ''
-
- indir = tempfile.mkdtemp()
- # eliminate leading spaces in front of directives
- body = adjustImports(body)
-
- if HTML_IMPORT_MATCHER.search(body):
- useDartHtml = True
-
- inputfile = join(indir, 'code.dart')
- with open(inputfile, 'w') as f:
- f.write("#library('inlinedcode');\n")
- f.write(body)
-
- wrappedfile = join(indir, 'entry.dart')
- with open(wrappedfile, 'w') as f:
- f.write(ENTRY_POINT % inputfile)
-
- status, out, err = execute(self.compileCommand(wrappedfile, outdir),
- self.verbose)
- if status:
- raise ConverterException('compilation errors')
-
- # Inline the compiled code in the page
- with open(self.outputFileName(wrappedfile, outdir), 'r') as f:
- res = f.read()
-
- # Cleanup
- if indir is not None:
- shutil.rmtree(indir)
- shutil.rmtree(outdir)
- return CHROMIUM_SCRIPT_TEMPLATE % res
-
- def compileCommand(self, inputfile, outdir):
- binary = abspath(join(DART_PATH,
- utils.GetBuildRoot(utils.GuessOS(),
- 'release', 'ia32'),
- 'frog', 'bin', 'frogsh'))
- if not exists(binary):
- raise ConverterException(FROG_NOT_FOUND_ERROR % DART_PATH)
-
- cmd = [binary, '--compile-only',
- '--libdir=' + join(DART_PATH, 'frog', 'lib'),
- '--out=' + self.outputFileName(inputfile, outdir)]
- if self.extra_flags != "":
- cmd.append(self.extra_flags);
- cmd.append(inputfile)
- return cmd
-
- def outputFileName(self, inputfile, outdir):
- return join(outdir, basename(inputfile) + '.js')
-
-def execute(cmd, verbose=False):
- """Execute a command in a subprocess. """
- if verbose: print 'Executing: ' + ' '.join(cmd)
- try:
- pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, err = pipe.communicate()
- if pipe.returncode != 0:
- print 'Execution failed: ' + output + '\n' + err
- if verbose or pipe.returncode != 0:
- print output
- print err
- return pipe.returncode, output, err
- except Exception as e:
- print 'Exception when executing: ' + ' '.join(cmd)
- print e
- return 1, None, None
-
-
-def convertPath(project_path, prefix_path):
- """ Convert a project path (whose root corresponds to the current working
- directory) to a system path.
- Args:
- - project_path: path in the project context.
- - prefix_path: prefix for relative paths.
- """
- if isabs(project_path):
- # TODO(sigmund): add a flag to pass in the root-level for absolute paths.
- return project_path[1:]
- elif not (project_path.startswith('http://') or
- project_path.startswith('https://')):
- return join(prefix_path, project_path)
- else:
- return project_path
-
-def encodeImage(rootDir, filename):
- """ Returns a base64 url encoding for an image """
- filetype = filename[-3:]
- if filetype == 'svg': filetype = 'svg+xml'
- with open(join(rootDir, filename), 'r') as f:
- return 'url(data:image/%s;charset=utf-8;base64,%s)' % (
- filetype,
- base64.b64encode(f.read()))
-
-def processCss(filename):
- """ Reads and converts a css file by replacing all image refernces into
- base64 encoded images.
- """
- css = open(filename, 'r').read()
- cssDir = os.path.split(filename)[0]
- def transformUrl(match):
- imagefile = match.group(1)
- # if the image is not local or can't be found, leave the url alone:
- if (imagefile.startswith('http://')
- or imagefile.startswith('https://')
- or not exists(join(cssDir, imagefile))):
- return match.group(0)
- return encodeImage(cssDir, imagefile)
-
- pattern = 'url\((.*\.(svg|png|jpg|gif))\)'
- return re.sub(pattern, transformUrl, css)
-
-class DartHTMLConverter(HTMLParser):
- """ An HTML processor that inlines css and compiled dart code.
-
- Args:
- - compiler: an implementation of DartAnyCompiler
- - prefix_path: prefix for relative paths encountered in the HTML.
- """
- def __init__(self, compiler, prefix_path):
- HTMLParser.__init__(self)
- self.in_dart_tag = False
- self.output = []
- self.dart_inline_code = []
- self.contains_dart = False
- self.compiler = compiler
- self.prefix_path = prefix_path
-
- def inlineCss(self, attrDic):
- path = convertPath(attrDic['href'], self.prefix_path)
- self.output.append(CSS_TEMPLATE % processCss(path))
-
- def compileScript(self, attrDic):
- if 'src' in attrDic:
- self.output.append(self.compiler.compileCode(
- src=convertPath(attrDic.pop('src'), self.prefix_path),
- body=None))
- else:
- self.in_dart_tag = True
- # no tag is generated until we parse the body of the tag
- self.dart_inline_code = []
- return True
-
- def convertImage(self, attrDic):
- pass
-
- def starttagHelper(self, tag, attrs, isEnd):
- attrDic = dict(attrs)
-
- # collect all script files, and generate a single script before </body>
- if (tag == 'script' and 'type' in attrDic
- and (attrDic['type'] == DART_MIME_TYPE)):
- if self.compileScript(attrDic):
- return
-
- # convert css imports into inlined css
- elif (tag == 'link' and
- 'rel' in attrDic and attrDic['rel'] == 'stylesheet' and
- 'type' in attrDic and attrDic['type'] == 'text/css' and
- 'href' in attrDic):
- self.inlineCss(attrDic)
- return
-
- elif tag == 'img' and 'src' in attrDic:
- self.convertImage(attrDic)
-
- # emit everything else as in the input
- self.output.append('<%s%s%s>' % (
- tag + (' ' if len(attrDic) else ''),
- ' '.join(['%s="%s"' % (k, attrDic[k]) for k in attrDic]),
- '/' if isEnd else ''))
-
- def handle_starttag(self, tag, attrs):
- self.starttagHelper(tag, attrs, False)
-
- def handle_startendtag(self, tag, attrs):
- self.starttagHelper(tag, attrs, True)
-
- def handle_data(self, data):
- if self.in_dart_tag:
- # collect the dart source code and compile it all at once when no more
- # script tags can be included. Note: the code will anyways start on
- # DOMContentLoaded, so moving the script is OK.
- self.dart_inline_code.append(data)
- else:
- self.output.append(data),
-
- def handle_endtag(self, tag):
- if tag == 'script' and self.in_dart_tag:
- self.in_dart_tag = False
- self.output.append(self.compiler.compileCode(
- src=None, body='\n'.join(self.dart_inline_code)))
- else:
- self.output.append('</%s>' % tag)
-
- def handle_charref(self, ref):
- self.output.append('&#%s;' % ref)
-
- def handle_entityref(self, name):
- self.output.append('&%s;' % name)
-
- def handle_comment(self, data):
- self.output.append('<!--%s-->' % data)
-
- def handle_decl(self, decl):
- self.output.append('<!%s>' % decl)
-
- def unknown_decl(self, data):
- self.output.append('<!%s>' % data)
-
- def handle_pi(self, data):
- self.output.append('<?%s>' % data)
-
- def getResult(self):
- return ''.join(self.output)
-
-
-class DartToDartHTMLConverter(DartHTMLConverter):
- def __init__(self, prefix_path, outdir, verbose):
- # Note: can't use super calls because HTMLParser is not a subclass of object
- DartHTMLConverter.__init__(self, None, prefix_path)
- self.outdir = outdir
- self.verbose = verbose
-
- def compileScript(self, attrDic):
- self.contains_dart = True
- if 'src' in attrDic:
- status, out, err = execute([
- sys.executable,
- join(DART_PATH, 'tools', 'copy_dart.py'),
- self.outdir,
- convertPath(attrDic['src'], self.prefix_path)],
- self.verbose)
-
- if status:
- raise ConverterException('exception calling copy_dart.py')
-
- # do not rewrite the script tag
- return False
-
- def handle_endtag(self, tag):
- if tag == 'body' and self.contains_dart:
- self.output.append(DARTIUM_TO_JS_SCRIPT)
- DartHTMLConverter.handle_endtag(self, tag)
-
-# A data URL for a blank 1x1 PNG. The PNG's data is from
-# convert -size 1x1 +set date:create +set date:modify \
-# xc:'rgba(0,0,0,0)' 1x1.png
-# base64.b64encode(open('1x1.png').read())
-# (The +set stuff is because just doing "-strip" apparently doesn't work;
-# it leaves several info chunks resulting in a 224-byte PNG.)
-BLANK_IMAGE_BASE64_URL = 'data:image/png;charset=utf-8;base64,%s' % (
- ('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABEAQAAADljNBBAAAAAmJLR0T//xSrMc0AAAAJc'
- 'EhZcwAAAEgAAABIAEbJaz4AAAAJdnBBZwAAAAEAAAABAMeVX+0AAAANSURBVAjXY2BgYG'
- 'AAAAAFAAFe8yo6AAAAAElFTkSuQmCC'))
-
-class OfflineHTMLConverter(DartHTMLConverter):
- def __init__(self, prefix_path, outdir, verbose, inline_images):
- # Note: can't use super calls because HTMLParser is not a subclass of object
- DartHTMLConverter.__init__(self, None, prefix_path)
- self.outdir = outdir
- self.verbose = verbose
- self.inline_images = inline_images # Inline as data://, vs. use local file.
-
- def compileScript(self, attrDic):
- # do not rewrite the script tag
- return False
-
- def downloadImageUrlToEncode(self, url):
- """ Downloads an image and returns a base64 url encoding for it.
- May throw if the download fails.
- """
- # Don't try to re-encode an image that's already data://.
- filetype = url[-3:]
- if filetype == 'svg': filetype = 'svg+xml'
- if self.verbose:
- print 'Downloading ' + url
- f = urllib2.urlopen(url)
-
- return 'data:image/%s;charset=utf-8;base64,%s' % (
- filetype,
- base64.b64encode(f.read()))
-
- def downloadImageUrlToFile(self, url):
- """Downloads an image and returns the filename. May throw if the
- download fails.
- """
- extension = os.path.splitext(url)[1]
- # mkstemp() happens to work to create a non-temporary, so we use it.
- filename = tempfile.mkstemp(extension, 'img_', self.prefix_path)[1]
- if self.verbose:
- print 'Downloading %s to %s' % (url, filename)
- writeOut(urllib2.urlopen(url).read(), filename)
- return os.path.join(self.prefix_path, os.path.basename(filename))
-
- def downloadImage(self, url):
- """Downloads an image either to file or to data://, and return the URL."""
- if url.startswith('data:image/'):
- return url
- try:
- if self.inline_images:
- return self.downloadImageUrlToEncode(url)
- else:
- return self.downloadImageUrlToFile(url)
- except:
- print '*** Image download failed: %s' % url
- return BLANK_IMAGE_BASE64_URL
-
- def convertImage(self, attrDic):
- attrDic['src'] = self.downloadImage(attrDic['src'])
-
-def safeMakeDirs(dirname):
- """ Creates a directory and, if necessary its parent directories.
-
- This function will safely return if other concurrent jobs try to create the
- same directory.
- """
- if not exists(dirname):
- try:
- os.makedirs(dirname)
- except Exception:
- # this check allows invoking this script concurrently in many jobs
- if not exists(dirname):
- raise
-
-class ConverterException(Exception):
- """ An exception encountered during the convertion process """
- pass
-
-def Flags():
- """ Constructs a parser for extracting flags from the command line. """
- result = optparse.OptionParser()
- result.add_option("--verbose",
- help="Print verbose output",
- default=False,
- action="store_true")
- result.add_option("-o", "--out",
- help="Output directory",
- type="string",
- default=None,
- action="store")
- result.add_option("-t", "--target",
- help="The target html to generate",
- metavar="[js,chromium,dartium]",
- default='chromium')
- result.add_option("--extra-flags",
- help="Extra flags for dartc",
- type="string",
- default="")
- result.set_usage("htmlconverter.py input.html -o OUTDIR")
- return result
-
-def writeOut(contents, filepath):
- """ Writes contents to a file, ensuring that the output directory exists. """
- safeMakeDirs(dirname(filepath))
- with open(filepath, 'w') as f:
- f.write(contents)
- print "Generated output in: " + abspath(filepath)
-
-def convertForDartium(filename, outdirBase, outfile, verbose):
- """ Converts a file for a dartium target. """
- with open(filename, 'r') as f:
- contents = f.read()
- prefix_path = dirname(filename)
-
- # outdirBase is the directory to place all subdirectories for other dart files
- # and resources.
- converter = DartToDartHTMLConverter(prefix_path, outdirBase, verbose)
- converter.feed(contents)
- converter.close()
- writeOut(converter.getResult(), outfile)
-
-def convertForChromium(
- filename, extra_flags, outfile, verbose):
- """ Converts a file for a chromium target. """
- with open(filename, 'r') as f:
- contents = f.read()
- prefix_path = dirname(filename)
- converter = DartHTMLConverter(
- DartCompiler(verbose, extra_flags), prefix_path)
- converter.feed(contents)
- converter.close()
- writeOut(converter.getResult(), outfile)
-
-def convertForOffline(filename, outfile, verbose, encode_images):
- """ Converts a file for offline use. """
- with codecs.open(filename, 'r', 'utf-8') as f:
- contents = f.read()
- converter = OfflineHTMLConverter(dirname(filename),
- dirname(outfile),
- verbose,
- encode_images)
- converter.feed(contents)
- converter.close()
-
- contents = converter.getResult()
- safeMakeDirs(dirname(outfile))
- with codecs.open(outfile, 'w', 'utf-8') as f:
- f.write(contents)
- print "Generated output in: " + abspath(outfile)
-
-RED_COLOR = "\033[31m"
-NO_COLOR = "\033[0m"
-
-def main():
- parser = Flags()
- options, args = parser.parse_args()
- if len(args) < 1 or not options.out or not options.target:
- parser.print_help()
- return 1
-
- try:
- filename = args[0]
- extension = filename[filename.rfind('.'):]
- if extension != '.html' and extension != '.htm':
- print "Invalid input file extension: %s" % extension
- return 1
- outfile = join(options.out, filename)
- if 'chromium' in options.target or 'js' in options.target:
- convertForChromium(filename,
- options.extra_flags,
- outfile.replace(extension, '-js' + extension), options.verbose)
- if 'dartium' in options.target:
- convertForDartium(filename, options.out,
- outfile.replace(extension, '-dart' + extension), options.verbose)
- except Exception as e:
- print "%sERROR%s: %s" % (RED_COLOR, NO_COLOR, str(e))
- return 1
- return 0
-
-if __name__ == '__main__':
- sys.exit(main())
« no previous file with comments | « no previous file | client/tools/htmlconverter_test.py » ('j') | samples/dartcombat/README » ('J')

Powered by Google App Engine
This is Rietveld 408576698