1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
#!/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_file in sorted([os.path.basename(x) for x in self.js_files]):
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(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)
template_path = os.path.join(self.template_rel_dir, template_name)
if not self.validateTemplate(template_path):
error('Found template not in list of expected templates: %s' %
template_name)
self.processTemplate(output, template_path, 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='+',
default={},
help='The Javascript files to include in HTML <head>')
parser.add_argument(
'--js-list-file',
help='The name of a file containing a list of files, one per line, '
'identifying the Javascript to include in HTML <head>. This is an '
'alternate to specifying the files directly via the "--js" option. '
'The files listed in this file are appended to the files passed via '
'the "--js" option, if any.')
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(
'--template-dir',
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)
# Load the files from the --js-list-file.
js_list_file = args.js_list_file
if js_list_file:
js_files = js_files.union(set(line.rstrip() for line in open(js_list_file)))
js_files = js_files - set(args.exclude_js)
instrumented_js_files = set(args.instrument_js) - set(args.exclude_js)
# Create the output directory if it does not exist.
out_directory = os.path.dirname(out_file)
if out_directory is not '' and 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, instrumented_js_files,
args.template_dir)
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())
|