| #!/usr/bin/env python |
| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Builds the complete main.html file from the basic components. |
| """ |
| |
| from HTMLParser import HTMLParser |
| import argparse |
| import os |
| import re |
| import sys |
| |
| |
| def error(msg): |
| print 'Error: %s' % msg |
| sys.exit(1) |
| |
| |
| class HtmlChecker(HTMLParser): |
| def __init__(self): |
| HTMLParser.__init__(self) |
| self.ids = set() |
| |
| def handle_starttag(self, tag, attrs): |
| for (name, value) in attrs: |
| if name == 'id': |
| if value in self.ids: |
| error('Duplicate id: %s' % value) |
| self.ids.add(value) |
| |
| |
| class GenerateWebappHtml: |
| def __init__(self, template_files, js_files, instrumented_js_files, |
| template_rel_dir): |
| |
| self.js_files = js_files |
| self.instrumented_js_files = instrumented_js_files |
| self.template_rel_dir = template_rel_dir |
| |
| self.templates_expected = set() |
| for template in template_files: |
| self.templates_expected.add(os.path.basename(template)) |
| |
| self.templates_found = set() |
| |
| def includeJavascript(self, output): |
| for js_path in sorted(self.js_files): |
| js_file = os.path.basename(js_path) |
| output.write(' <script src="' + js_file + '"></script>\n') |
| |
| for js_path in sorted(self.instrumented_js_files): |
| js_file = os.path.basename(js_path) |
| output.write(' <script src="' + js_file + '" data-cover></script>\n') |
| |
| def verifyTemplateList(self): |
| """Verify that all the expected templates were found.""" |
| if self.templates_expected > self.templates_found: |
| extra = self.templates_expected - self.templates_found |
| print 'Extra templates specified:', extra |
| return False |
| return True |
| |
| def validateTemplate(self, template_path): |
| template = os.path.basename(template_path) |
| if template in self.templates_expected: |
| self.templates_found.add(template) |
| return True |
| return False |
| |
| def processTemplate(self, output, template_file, indent): |
| with open(os.path.join(self.template_rel_dir, template_file), 'r') as \ |
| input_template: |
| first_line = True |
| skip_header_comment = False |
| |
| for line in input_template: |
| # If the first line is the start of a copyright notice, then |
| # skip over the entire comment. |
| # This will remove the copyright info from the included files, |
| # but leave the one on the main template. |
| if first_line and re.match(r'<!--', line): |
| skip_header_comment = True |
| first_line = False |
| if skip_header_comment: |
| if re.search(r'-->', line): |
| skip_header_comment = False |
| continue |
| |
| m = re.match( |
| r'^(\s*)<meta-include src="(.+)"\s*/>\s*$', |
| line) |
| if m: |
| prefix = m.group(1) |
| template_name = m.group(2) |
| if not self.validateTemplate(template_name): |
| error('Found template not in list of expected templates: %s' % |
| template_name) |
| self.processTemplate(output, template_name, indent + len(prefix)) |
| continue |
| |
| m = re.match(r'^\s*<meta-include type="javascript"\s*/>\s*$', line) |
| if m: |
| self.includeJavascript(output) |
| continue |
| |
| if line.strip() == '': |
| output.write('\n') |
| else: |
| output.write((' ' * indent) + line) |
| |
| |
| def parseArgs(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| '--js', nargs='+', help='The Javascript files to include in HTML <head>') |
| parser.add_argument( |
| '--templates', |
| nargs='*', |
| default=[], |
| help='The html template files used by input-template') |
| parser.add_argument( |
| '--exclude-js', |
| nargs='*', |
| default=[], |
| help='The Javascript files to exclude from <--js> and <--instrumentedjs>') |
| parser.add_argument( |
| '--instrument-js', |
| nargs='*', |
| default=[], |
| help='Javascript to include and instrument for code coverage') |
| parser.add_argument( |
| '--dir-for-templates', |
| default = ".", |
| help='Directory template references in html are relative to') |
| parser.add_argument('output_file') |
| parser.add_argument('input_template') |
| return parser.parse_args(sys.argv[1:]) |
| |
| |
| def main(): |
| args = parseArgs() |
| |
| out_file = args.output_file |
| js_files = set(args.js) - set(args.exclude_js) |
| |
| # Create the output directory if it does not exist. |
| out_directory = os.path.dirname(out_file) |
| if not os.path.exists(out_directory): |
| os.makedirs(out_directory) |
| |
| # Generate the main HTML file from the templates. |
| with open(out_file, 'w') as output: |
| gen = GenerateWebappHtml(args.templates, js_files, args.instrument_js, |
| args.dir_for_templates) |
| gen.processTemplate(output, args.input_template, 0) |
| |
| # Verify that all the expected templates were found. |
| if not gen.verifyTemplateList(): |
| error('Extra templates specified') |
| |
| # Verify that the generated HTML file is valid. |
| with open(out_file, 'r') as input_html: |
| parser = HtmlChecker() |
| parser.feed(input_html.read()) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |