]> git.ipfire.org Git - people/stevee/selinux-policy.git/blob - support/pyplate.py
Unconfined_t needs to transition to useradd_t and useradd_t needs to be able to manag...
[people/stevee/selinux-policy.git] / support / pyplate.py
1 """PyPlate : a simple Python-based templating program
2
3 PyPlate parses a file and replaces directives (in double square brackets [[ ... ]])
4 by various means using a given dictionary of variables. Arbitrary Python code
5 can be run inside many of the directives, making this system highly flexible.
6
7 Usage:
8 # Load and parse template file
9 template = pyplate.Template("output") (filename or string)
10 # Execute it with a dictionary of variables
11 template.execute_file(output_stream, locals())
12
13 PyPlate defines the following directives:
14 [[...]] evaluate the arbitrary Python expression and insert the
15 result into the output
16
17 [[# ... #]] comment.
18
19 [[exec ...]] execute arbitrary Python code in the sandbox namespace
20
21 [[if ...]] conditional expressions with usual Python semantics
22 [[elif ...]]
23 [[else]]
24 [[end]]
25
26 [[for ... in ...]] for-loop with usual Python semantics
27 [[end]]
28
29 [[def ...(...)]] define a "function" out of other templating elements
30 [[end]]
31
32 [[call ...]] call a templating function (not a regular Python function)
33 """
34
35 #
36 # Copyright (C) 2002 Michael Droettboom
37 #
38 # This program is free software; you can redistribute it and/or
39 # modify it under the terms of the GNU General Public License
40 # as published by the Free Software Foundation; either version 2
41 # of the License, or (at your option) any later version.
42 #
43 # This program is distributed in the hope that it will be useful,
44 # but WITHOUT ANY WARRANTY; without even the implied warranty of
45 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 # GNU General Public License for more details.
47 #
48 # You should have received a copy of the GNU General Public License
49 # along with this program; if not, write to the Free Software
50 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 #
52
53 from __future__ import nested_scopes
54 import sys, string, re, cStringIO
55
56 re_directive = re.compile("\[\[(.*)\]\]")
57 re_for_loop = re.compile("for (.*) in (.*)")
58 re_if = re.compile("if (.*)")
59 re_elif = re.compile("elif (.*)")
60 re_def = re.compile("def (.*?)\((.*)\)")
61 re_call = re.compile("call (.*?)\((.*)\)")
62 re_exec = re.compile("exec (.*)")
63 re_comment = re.compile("#(.*)#")
64
65 ############################################################
66 # Template parser
67 class ParserException(Exception):
68 def __init__(self, lineno, s):
69 Exception.__init__(self, "line %d: %s" % (lineno, s))
70
71 class Template:
72 def __init__(self, filename=None):
73 if filename != None:
74 try:
75 self.parse_file(filename)
76 except:
77 self.parse_string(filename)
78
79 def parse_file(self, filename):
80 file = open(filename, 'r')
81 self.parse(file)
82 file.close()
83
84 def parse_string(self, template):
85 file = cStringIO.StringIO(template)
86 self.parse(file)
87 file.close()
88
89 def parse(self, file):
90 self.file = file
91 self.line = self.file.read()
92 self.lineno = 0
93 self.functions = {}
94 self.tree = TopLevelTemplateNode(self)
95
96 def parser_get(self):
97 if self.line == '':
98 return None
99 return self.line
100
101 def parser_eat(self, chars):
102 self.lineno = self.lineno + self.line[:chars].count("\n")
103 self.line = self.line[chars:]
104
105 def parser_exception(self, s):
106 raise ParserException(self.lineno, s)
107
108 def execute_file(self, filename, data):
109 file = open(filename, 'w')
110 self.execute(file, data)
111 file.close()
112
113 def execute_string(self, data):
114 s = cStringIO.StringIO()
115 self.execute(s, data)
116 return s.getvalue()
117
118 def execute_stdout(self, data):
119 self.execute(sys.stdout, data)
120
121 def execute(self, stream=sys.stdout, data={}):
122 self.tree.execute(stream, data)
123
124 def __repr__(self):
125 return repr(self.tree)
126
127
128 ############################################################
129 # NODES
130 class TemplateNode:
131 def __init__(self, parent, s):
132 self.parent = parent
133 self.s = s
134 self.node_list = []
135 while 1:
136 new_node = TemplateNodeFactory(parent)
137 if self.add_node(new_node):
138 break
139
140 def add_node(self, node):
141 if node == 'end':
142 return 1
143 elif node != None:
144 self.node_list.append(node)
145 else:
146 raise self.parent.parser_exception(
147 "[[%s]] does not have a matching [[end]]" % self.s)
148
149 def execute(self, stream, data):
150 for node in self.node_list:
151 node.execute(stream, data)
152
153 def __repr__(self):
154 r = "<" + self.__class__.__name__ + " "
155 for i in self.node_list:
156 r = r + repr(i)
157 r = r + ">"
158 return r
159
160 class TopLevelTemplateNode(TemplateNode):
161 def __init__(self, parent):
162 TemplateNode.__init__(self, parent, '')
163
164 def add_node(self, node):
165 if node != None:
166 self.node_list.append(node)
167 else:
168 return 1
169
170 class ForTemplateNode(TemplateNode):
171 def __init__(self, parent, s):
172 TemplateNode.__init__(self, parent, s)
173 match = re_for_loop.match(s)
174 if match == None:
175 raise self.parent.parser_exception(
176 "[[%s]] is not a valid for-loop expression" % self.s)
177 else:
178 self.vars_temp = match.group(1).split(",")
179 self.vars = []
180 for v in self.vars_temp:
181 self.vars.append(v.strip())
182 #print self.vars
183 self.expression = match.group(2)
184
185 def execute(self, stream, data):
186 remember_vars = {}
187 for var in self.vars:
188 if data.has_key(var):
189 remember_vars[var] = data[var]
190 for list in eval(self.expression, globals(), data):
191 if is_sequence(list):
192 for index, value in enumerate(list):
193 data[self.vars[index]] = value
194 else:
195 data[self.vars[0]] = list
196 TemplateNode.execute(self, stream, data)
197 for key, value in remember_vars.items():
198 data[key] = value
199
200 class IfTemplateNode(TemplateNode):
201 def __init__(self, parent, s):
202 self.else_node = None
203 TemplateNode.__init__(self, parent, s)
204 match = re_if.match(s)
205 if match == None:
206 raise self.parent.parser_exception(
207 "[[%s]] is not a valid if expression" % self.s)
208 else:
209 self.expression = match.group(1)
210
211 def add_node(self, node):
212 if node == 'end':
213 return 1
214 elif isinstance(node, ElseTemplateNode):
215 self.else_node = node
216 return 1
217 elif isinstance(node, ElifTemplateNode):
218 self.else_node = node
219 return 1
220 elif node != None:
221 self.node_list.append(node)
222 else:
223 raise self.parent.parser_exception(
224 "[[%s]] does not have a matching [[end]]" % self.s)
225
226 def execute(self, stream, data):
227 if eval(self.expression, globals(), data):
228 TemplateNode.execute(self, stream, data)
229 elif self.else_node != None:
230 self.else_node.execute(stream, data)
231
232 class ElifTemplateNode(IfTemplateNode):
233 def __init__(self, parent, s):
234 self.else_node = None
235 TemplateNode.__init__(self, parent, s)
236 match = re_elif.match(s)
237 if match == None:
238 self.parent.parser_exception(
239 "[[%s]] is not a valid elif expression" % self.s)
240 else:
241 self.expression = match.group(1)
242
243 class ElseTemplateNode(TemplateNode):
244 pass
245
246 class FunctionTemplateNode(TemplateNode):
247 def __init__(self, parent, s):
248 TemplateNode.__init__(self, parent, s)
249 match = re_def.match(s)
250 if match == None:
251 self.parent.parser_exception(
252 "[[%s]] is not a valid function definition" % self.s)
253 self.function_name = match.group(1)
254 self.vars_temp = match.group(2).split(",")
255 self.vars = []
256 for v in self.vars_temp:
257 self.vars.append(v.strip())
258 #print self.vars
259 self.parent.functions[self.function_name] = self
260
261 def execute(self, stream, data):
262 pass
263
264 def call(self, args, stream, data):
265 remember_vars = {}
266 for index, var in enumerate(self.vars):
267 if data.has_key(var):
268 remember_vars[var] = data[var]
269 data[var] = args[index]
270 TemplateNode.execute(self, stream, data)
271 for key, value in remember_vars.items():
272 data[key] = value
273
274 class LeafTemplateNode(TemplateNode):
275 def __init__(self, parent, s):
276 self.parent = parent
277 self.s = s
278
279 def execute(self, stream, data):
280 stream.write(self.s)
281
282 def __repr__(self):
283 return "<" + self.__class__.__name__ + ">"
284
285 class CommentTemplateNode(LeafTemplateNode):
286 def execute(self, stream, data):
287 pass
288
289 class ExpressionTemplateNode(LeafTemplateNode):
290 def execute(self, stream, data):
291 stream.write(str(eval(self.s, globals(), data)))
292
293 class ExecTemplateNode(LeafTemplateNode):
294 def __init__(self, parent, s):
295 LeafTemplateNode.__init__(self, parent, s)
296 match = re_exec.match(s)
297 if match == None:
298 self.parent.parser_exception(
299 "[[%s]] is not a valid statement" % self.s)
300 self.s = match.group(1)
301
302 def execute(self, stream, data):
303 exec(self.s, globals(), data)
304 pass
305
306 class CallTemplateNode(LeafTemplateNode):
307 def __init__(self, parent, s):
308 LeafTemplateNode.__init__(self, parent, s)
309 match = re_call.match(s)
310 if match == None:
311 self.parent.parser_exception(
312 "[[%s]] is not a valid function call" % self.s)
313 self.function_name = match.group(1)
314 self.vars = "(" + match.group(2).strip() + ",)"
315
316 def execute(self, stream, data):
317 self.parent.functions[self.function_name].call(
318 eval(self.vars, globals(), data), stream, data)
319
320
321 ############################################################
322 # Node factory
323 template_factory_type_map = {
324 'if' : IfTemplateNode,
325 'for' : ForTemplateNode,
326 'elif' : ElifTemplateNode,
327 'else' : ElseTemplateNode,
328 'def' : FunctionTemplateNode,
329 'call' : CallTemplateNode,
330 'exec' : ExecTemplateNode }
331 template_factory_types = template_factory_type_map.keys()
332
333 def TemplateNodeFactory(parent):
334 src = parent.parser_get()
335
336 if src == None:
337 return None
338 match = re_directive.search(src)
339 if match == None:
340 parent.parser_eat(len(src))
341 return LeafTemplateNode(parent, src)
342 elif src == '' or match.start() != 0:
343 parent.parser_eat(match.start())
344 return LeafTemplateNode(parent, src[:match.start()])
345 else:
346 directive = match.group()[2:-2].strip()
347 parent.parser_eat(match.end())
348 if directive == 'end':
349 return 'end'
350 elif re_comment.match(directive):
351 return CommentTemplateNode(parent, directive)
352 else:
353 for i in template_factory_types:
354 if directive[0:len(i)] == i:
355 return template_factory_type_map[i](parent, directive)
356 return ExpressionTemplateNode(parent, directive)
357
358 def is_sequence(object):
359 try:
360 test = object[0:0]
361 except:
362 return False
363 else:
364 return True