2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Builds the complete main.html file from the basic components.
9 from HTMLParser
import HTMLParser
17 print 'Error: %s' % msg
21 class HtmlChecker(HTMLParser
):
23 HTMLParser
.__init
__(self
)
26 def handle_starttag(self
, tag
, attrs
):
27 for (name
, value
) in attrs
:
30 error('Duplicate id: %s' % value
)
34 class GenerateWebappHtml
:
35 def __init__(self
, template_files
, js_files
, instrumented_js_files
,
38 self
.js_files
= js_files
39 self
.instrumented_js_files
= instrumented_js_files
40 self
.template_rel_dir
= template_rel_dir
42 self
.templates_expected
= set()
43 for template
in template_files
:
44 self
.templates_expected
.add(os
.path
.basename(template
))
46 self
.templates_found
= set()
48 def includeJavascript(self
, output
):
49 for js_path
in sorted(self
.js_files
):
50 js_file
= os
.path
.basename(js_path
)
51 output
.write(' <script src="' + js_file
+ '"></script>\n')
53 for js_path
in sorted(self
.instrumented_js_files
):
54 js_file
= os
.path
.basename(js_path
)
55 output
.write(' <script src="' + js_file
+ '" data-cover></script>\n')
57 def verifyTemplateList(self
):
58 """Verify that all the expected templates were found."""
59 if self
.templates_expected
> self
.templates_found
:
60 extra
= self
.templates_expected
- self
.templates_found
61 print 'Extra templates specified:', extra
65 def validateTemplate(self
, template_path
):
66 template
= os
.path
.basename(template_path
)
67 if template
in self
.templates_expected
:
68 self
.templates_found
.add(template
)
72 def processTemplate(self
, output
, template_file
, indent
):
73 with
open(os
.path
.join(self
.template_rel_dir
, template_file
), 'r') as \
76 skip_header_comment
= False
78 for line
in input_template
:
79 # If the first line is the start of a copyright notice, then
80 # skip over the entire comment.
81 # This will remove the copyright info from the included files,
82 # but leave the one on the main template.
83 if first_line
and re
.match(r
'<!--', line
):
84 skip_header_comment
= True
86 if skip_header_comment
:
87 if re
.search(r
'-->', line
):
88 skip_header_comment
= False
92 r
'^(\s*)<meta-include src="(.+)"\s*/>\s*$',
96 template_name
= m
.group(2)
97 if not self
.validateTemplate(template_name
):
98 error('Found template not in list of expected templates: %s' %
100 self
.processTemplate(output
, template_name
, indent
+ len(prefix
))
103 m
= re
.match(r
'^\s*<meta-include type="javascript"\s*/>\s*$', line
)
105 self
.includeJavascript(output
)
108 if line
.strip() == '':
111 output
.write((' ' * indent
) + line
)
115 parser
= argparse
.ArgumentParser()
117 '--js', nargs
='+', help='The Javascript files to include in HTML <head>')
122 help='The html template files used by input-template')
127 help='The Javascript files to exclude from <--js> and <--instrumentedjs>')
132 help='Javascript to include and instrument for code coverage')
134 '--dir-for-templates',
136 help='Directory template references in html are relative to')
137 parser
.add_argument('output_file')
138 parser
.add_argument('input_template')
139 return parser
.parse_args(sys
.argv
[1:])
145 out_file
= args
.output_file
146 js_files
= set(args
.js
) - set(args
.exclude_js
)
148 # Create the output directory if it does not exist.
149 out_directory
= os
.path
.dirname(out_file
)
150 if not os
.path
.exists(out_directory
):
151 os
.makedirs(out_directory
)
153 # Generate the main HTML file from the templates.
154 with
open(out_file
, 'w') as output
:
155 gen
= GenerateWebappHtml(args
.templates
, js_files
, args
.instrument_js
,
156 args
.dir_for_templates
)
157 gen
.processTemplate(output
, args
.input_template
, 0)
159 # Verify that all the expected templates were found.
160 if not gen
.verifyTemplateList():
161 error('Extra templates specified')
163 # Verify that the generated HTML file is valid.
164 with
open(out_file
, 'r') as input_html
:
165 parser
= HtmlChecker()
166 parser
.feed(input_html
.read())
169 if __name__
== '__main__':