1 | #!/usr/bin/env python
|
---|
2 | # -*- coding: utf-8 -*-
|
---|
3 |
|
---|
4 | # ship.py
|
---|
5 | #
|
---|
6 | # Licensed under the Apache 2 License as is the rest of the project
|
---|
7 | # Copyright (c) 2011 Jeff Schiller
|
---|
8 | #
|
---|
9 | # This script has very little real-world application. It is only used in our pure-client web app
|
---|
10 | # served on GoogleCode so we can have one HTML file, run a build script and generate a 'release'
|
---|
11 | # version without having to maintain two separate HTML files. It does this by evaluating
|
---|
12 | # 'processing comments' that are suspicously similar to IE conditional comments and then outputting
|
---|
13 | # a new HTML file after evaluating particular variables.
|
---|
14 | #
|
---|
15 | # This script takes the following inputs:
|
---|
16 | #
|
---|
17 | # * a HTML file (--i=in.html)
|
---|
18 | # * a series of flag names (--on=Foo --on=Bar)
|
---|
19 | #
|
---|
20 | # Example:
|
---|
21 | #
|
---|
22 | # in.html:
|
---|
23 | # <!--{if foo}>
|
---|
24 | # FOO!
|
---|
25 | # <!{else}-->
|
---|
26 | # BAR!
|
---|
27 | # <!--{endif}-->
|
---|
28 | #
|
---|
29 | # $ ship.py --i in.html --on foo
|
---|
30 | #
|
---|
31 | # out.html:
|
---|
32 | # <!--{if foo}-->
|
---|
33 | # FOO!
|
---|
34 | # <!--{else}>
|
---|
35 | # BAR!
|
---|
36 | # <!{endif}-->
|
---|
37 | #
|
---|
38 | # It has the following limitations:
|
---|
39 | #
|
---|
40 | # 1) Only if-else-endif are currently supported.
|
---|
41 | # 2) All processing comments must be on one line with no other non-whitespace characters.
|
---|
42 | # 3) Comments cannot be nested.
|
---|
43 |
|
---|
44 | import optparse
|
---|
45 | import os
|
---|
46 |
|
---|
47 | inside_if = False
|
---|
48 | last_if_true = False
|
---|
49 |
|
---|
50 | _options_parser = optparse.OptionParser(
|
---|
51 | usage='%prog --i input.html [--on flag1]',
|
---|
52 | description=('Rewrites an HTML file based on conditional comments and flags'))
|
---|
53 | _options_parser.add_option('--i',
|
---|
54 | action='store', dest='input_html_file', help='Input HTML filename')
|
---|
55 | _options_parser.add_option('--on',
|
---|
56 | action='append', type='string', dest='enabled_flags',
|
---|
57 | help='name of flag to enable')
|
---|
58 |
|
---|
59 | def parse_args(args=None):
|
---|
60 | options, rargs = _options_parser.parse_args(args)
|
---|
61 | return options, (None, None)
|
---|
62 |
|
---|
63 | def parseComment(line, line_num, enabled_flags):
|
---|
64 | global inside_if
|
---|
65 | global last_if_true
|
---|
66 |
|
---|
67 | start = line.find('{')
|
---|
68 | end = line.find('}')
|
---|
69 | statement = line[start+1:end].strip()
|
---|
70 | if statement.startswith('if '):
|
---|
71 | if inside_if == True:
|
---|
72 | print 'Fatal Error: Nested {if} found on line ' + str(line_num)
|
---|
73 | print line
|
---|
74 | quit()
|
---|
75 |
|
---|
76 | # Evaluate whether the expression is true/false.
|
---|
77 | # only one variable name allowed for now
|
---|
78 | variable_name = statement[3:].strip()
|
---|
79 | if variable_name in enabled_flags:
|
---|
80 | last_if_true = True
|
---|
81 | line = '<!--{if ' + variable_name + '}-->'
|
---|
82 | else:
|
---|
83 | last_if_true = False
|
---|
84 | line = '<!--{if ' + variable_name + '}>'
|
---|
85 |
|
---|
86 | inside_if = True
|
---|
87 |
|
---|
88 | elif statement == 'else':
|
---|
89 | if inside_if == False:
|
---|
90 | print 'Fatal Error: {else} found without {if} on line ' + str(line_num)
|
---|
91 | print line
|
---|
92 | quit()
|
---|
93 | if inside_if == 'else':
|
---|
94 | print 'Fatal Error: Multiple {else} clauses found in the same if on line ' + str(line_num)
|
---|
95 | print line
|
---|
96 | quit()
|
---|
97 |
|
---|
98 | if last_if_true:
|
---|
99 | line = '<!--{else}>'
|
---|
100 | else:
|
---|
101 | line = '<!{else}-->'
|
---|
102 |
|
---|
103 | # invert the logic so the endif clause is closed properly
|
---|
104 | last_if_true = not last_if_true
|
---|
105 |
|
---|
106 | # ensure we don't have two else statements in the same if
|
---|
107 | inside_if = 'else'
|
---|
108 |
|
---|
109 | elif statement == 'endif':
|
---|
110 | if inside_if == False:
|
---|
111 | print 'Fatal Error: {endif} found without {if} on line ' + str(line_num)
|
---|
112 | print line
|
---|
113 | quit()
|
---|
114 |
|
---|
115 | if last_if_true:
|
---|
116 | line = '<!--{endif}-->'
|
---|
117 | else:
|
---|
118 | line = '<!{endif}-->'
|
---|
119 |
|
---|
120 | inside_if = False
|
---|
121 |
|
---|
122 | return line
|
---|
123 |
|
---|
124 |
|
---|
125 | def ship(inFileName, enabled_flags):
|
---|
126 | # read in HTML file
|
---|
127 | lines = file(inFileName, 'r').readlines()
|
---|
128 | out_lines = []
|
---|
129 | i = 0
|
---|
130 |
|
---|
131 | # loop for each line of markup
|
---|
132 | for line in lines:
|
---|
133 | strline = line.strip()
|
---|
134 | # if we find a comment, process it and print out
|
---|
135 | if strline.startswith('<!--{') or strline.startswith('<!{'):
|
---|
136 | # using the same indentation as the previous line
|
---|
137 | start = line.find('<')
|
---|
138 | out_lines.append(line[:start] \
|
---|
139 | + parseComment(strline, i, enabled_flags) \
|
---|
140 | + os.linesep)
|
---|
141 | else: # else append line to the output list
|
---|
142 | out_lines.append(line)
|
---|
143 | i += 1
|
---|
144 |
|
---|
145 | return ''.join(out_lines)
|
---|
146 |
|
---|
147 | if __name__ == '__main__':
|
---|
148 | options, (input, output) = parse_args()
|
---|
149 |
|
---|
150 | if options.input_html_file != None:
|
---|
151 | enabled_flags = []
|
---|
152 | if options.enabled_flags != None:
|
---|
153 | enabled_flags.extend(options.enabled_flags)
|
---|
154 | out_file = ship(options.input_html_file, enabled_flags)
|
---|
155 | print out_file
|
---|