comparison src/bridge/bridge_constructor/bridge_constructor.py @ 612:dfb9b01b09db

misc: fixed bridge_constructor.py typo
author Goffi <goffi@goffi.org>
date Sun, 24 Mar 2013 15:41:30 +0100
parents src/bridge/bridge_constructor/bridge_contructor.py@84a6e83157c2
children 1fe00f0c9a91
comparison
equal deleted inserted replaced
611:d722778b152c 612:dfb9b01b09db
1 #!/usr/bin/python
2 #-*- coding: utf-8 -*-
3
4 # SAT: a jabber client
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 #consts
21 NAME = u"bridge_constructor"
22 VERSION = "0.1.0"
23 DEST_DIR = "generated"
24 ABOUT = NAME + u""" v%s (c) Jérôme Poisson (aka Goffi) 2011
25
26 ---
27 """ + NAME + u""" Copyright (C) 2011 Jérôme Poisson (aka Goffi)
28 This program comes with ABSOLUTELY NO WARRANTY;
29 This is free software, and you are welcome to redistribute it
30 under certain conditions.
31 ---
32
33 This script construct a SàT bridge using the given protocol
34 """
35 MANAGED_PROTOCOLES = ['dbus', 'mediawiki', 'dbus-xml']
36 DEFAULT_PROTOCOLE = 'dbus'
37 FLAGS = ['deprecated', 'async']
38
39 ENV_OVERRIDE = "SAT_BRIDGE_CONST_" # Prefix used to override a constant
40
41 import sys
42 import os
43 from os import path
44 from optparse import OptionParser
45 from ConfigParser import SafeConfigParser as Parser
46 from ConfigParser import NoOptionError
47 import re
48 from datetime import datetime
49 from xml.dom import minidom
50
51
52 class ParseError(Exception):
53 #Used when the signature parsing is going wrong (invalid signature ?)
54 pass
55
56
57 class Constructor(object):
58
59 def __init__(self, bridge_template, options):
60 self.bridge_template = bridge_template
61 self.options = options
62
63 def getValues(self, name):
64 """Return values of a function in a dict
65 @param name: Name of the function to get
66 @return: dict, each key has the config value or None if the value is not set"""
67 function = {}
68 for option in ['type', 'category', 'sig_in', 'sig_out', 'doc']:
69 try:
70 value = self.bridge_template.get(name, option)
71 except NoOptionError:
72 value = None
73 function[option] = value
74 return function
75
76 def getDefault(self, name):
77 """Return default values of a function in a dict
78 @param name: Name of the function to get
79 @return: dict, each key is the integer param number (no key if no default value)"""
80 default_dict = {}
81 def_re = re.compile(r"param_(\d+)_default")
82
83 for option in self.bridge_template.options(name):
84 match = def_re.match(option)
85 if match:
86 try:
87 idx = int(match.group(1))
88 except ValueError:
89 raise ParseError("Invalid value [%s] for parameter number" % match.group(1))
90 default_dict[idx] = self.bridge_template.get(name, option)
91
92 return default_dict
93
94 def getFlags(self, name):
95 """Return list of flags set for this function
96 @param name: Name of the function to get
97 @return: List of flags (string)"""
98 flags = []
99 for option in self.bridge_template.options(name):
100 if option in FLAGS:
101 flags.append(option)
102 return flags
103
104 def getArgumentsDoc(self, name):
105 """Return documentation of arguments
106 @param name: Name of the function to get
107 @return: dict, each key is the integer param number (no key if no argument doc), value is a tuple (name, doc)"""
108 doc_dict = {}
109 option_re = re.compile(r"doc_param_(\d+)")
110 value_re = re.compile(r"^(\w+): (.*)$", re.MULTILINE | re.DOTALL)
111 for option in self.bridge_template.options(name):
112 if option == 'doc_return':
113 doc_dict['return'] = self.bridge_template.get(name, option)
114 continue
115 match = option_re.match(option)
116 if match:
117 try:
118 idx = int(match.group(1))
119 except ValueError:
120 raise ParseError("Invalid value [%s] for parameter number" % match.group(1))
121 value_match = value_re.match(self.bridge_template.get(name, option))
122 if not value_match:
123 raise ParseError("Invalid value for parameter doc [%i]" % idx)
124 doc_dict[idx] = (value_match.group(1), value_match.group(2))
125 return doc_dict
126
127 def getDoc(self, name):
128 """Return documentation of the method
129 @param name: Name of the function to get
130 @return: string documentation, or None"""
131 if self.bridge_template.has_option(name, "doc"):
132 return self.bridge_template.get(name, "doc")
133 return None
134
135 def argumentsParser(self, signature):
136 """Generator which return individual arguments signatures from a global signature"""
137 start = 0
138 i = 0
139
140 while i < len(signature):
141 if signature[i] not in ['b', 'y', 'n', 'i', 'x', 'q', 'u', 't', 'd', 's', 'a']:
142 raise ParseError("Unmanaged attribute type [%c]" % signature[i])
143
144 if signature[i] == 'a':
145 i += 1
146 if signature[i] != '{' and signature[i] != '(': # FIXME: must manage tuples out of arrays
147 i += 1
148 yield signature[start:i]
149 start = i
150 continue # we have a simple type for the array
151 opening_car = signature[i]
152 assert(opening_car in ['{', '('])
153 closing_car = '}' if opening_car == '{' else ')'
154 opening_count = 1
155 while (True): # we have a dict or a list of tuples
156 i += 1
157 if i >= len(signature):
158 raise ParseError("missing }")
159 if signature[i] == opening_car:
160 opening_count += 1
161 if signature[i] == closing_car:
162 opening_count -= 1
163 if opening_count == 0:
164 break
165 i += 1
166 yield signature[start:i]
167 start = i
168
169 def getArguments(self, signature, name=None, default=None, unicode_protect=False):
170 """Return arguments to user given a signature
171 @param signature: signature in the short form (using s,a,i,b etc)
172 @param name: dictionary of arguments name like given by getArguments
173 @param default: dictionary of default values, like given by getDefault
174 @param unicode_protect: activate unicode protection on strings (return strings as unicode(str))
175 @return: list of arguments that correspond to a signature (e.g.: "sss" return "arg1, arg2, arg3")"""
176 idx = 0
177 attr_string = []
178
179 for arg in self.argumentsParser(signature):
180 attr_string.append(("unicode(%(name)s)%(default)s" if (unicode_protect and arg == 's') else "%(name)s%(default)s") % {
181 'name': name[idx][0] if (name and idx in name) else "arg_%i" % idx,
182 'default': "=" + default[idx] if (default and idx in default) else ''})
183 # give arg_1, arg2, etc or name1, name2=default, etc.
184 #give unicode(arg_1), unicode(arg_2), etc. if unicode_protect is set and arg is a string
185 idx += 1
186
187 return ", ".join(attr_string)
188
189 def generateCoreSide(self):
190 """create the constructor in SàT core side (backend)"""
191 raise NotImplementedError
192
193 def generateFrontendSide(self):
194 """create the constructor in SàT frontend side"""
195 raise NotImplementedError
196
197 def finalWrite(self, filename, file_buf):
198 """Write the final generated file in DEST_DIR/filename
199 @param filename: name of the file to generate
200 @param file_buf: list of lines (stings) of the file"""
201 if os.path.exists(DEST_DIR) and not os.path.isdir(DEST_DIR):
202 print ("The destination dir [%s] can't be created: a file with this name already exists !")
203 sys.exit(1)
204 try:
205 if not os.path.exists(DEST_DIR):
206 os.mkdir(DEST_DIR)
207 full_path = os.path.join(DEST_DIR, filename)
208 if os.path.exists(full_path) and not self.options.force:
209 print ("The destination file [%s] already exists ! Use --force to overwrite it" % full_path)
210 try:
211 with open(full_path, 'w') as dest_file:
212 dest_file.write('\n'.join(file_buf))
213 except IOError:
214 print ("Can't open destination file [%s]" % full_path)
215 except OSError:
216 print("It's not possible to generate the file, check your permissions")
217 exit(1)
218
219
220 class MediawikiConstructor(Constructor):
221
222 def __init__(self, bridge_template, options):
223 Constructor.__init__(self, bridge_template, options)
224 self.core_template = "mediawiki_template.tpl"
225 self.core_dest = "mediawiki.wiki"
226
227 def _addTextDecorations(self, text):
228 """Add text decorations like coloration or shortcuts"""
229
230 def anchor_link(match):
231 link = match.group(1)
232 #we add anchor_link for [method_name] syntax:
233 if link in self.bridge_template.sections():
234 return "[[#%s|%s]]" % (link, link)
235 print ("WARNING: found an anchor link to an unknown method")
236 return link
237
238 return re.sub(r"\[(\w+)\]", anchor_link, text)
239
240 def _wikiParameter(self, name, sig_in):
241 """Format parameters with the wiki syntax
242 @param name: name of the function
243 @param sig_in: signature in
244 @return: string of the formated parameters"""
245 arg_doc = self.getArgumentsDoc(name)
246 arg_default = self.getDefault(name)
247 args_str = self.getArguments(sig_in)
248 args = args_str.split(', ') if args_str else [] # ugly but it works :)
249 wiki = []
250 for i in range(len(args)):
251 if i in arg_doc:
252 name, doc = arg_doc[i]
253 doc = '\n:'.join(doc.rstrip('\n').split('\n'))
254 wiki.append("; %s: %s" % (name, self._addTextDecorations(doc)))
255 else:
256 wiki.append("; arg_%d: " % i)
257 if i in arg_default:
258 wiki.append(":''DEFAULT: %s''" % arg_default[i])
259 return "\n".join(wiki)
260
261 def _wikiReturn(self, name):
262 """Format return doc with the wiki syntax
263 @param name: name of the function
264 """
265 arg_doc = self.getArgumentsDoc(name)
266 wiki = []
267 if 'return' in arg_doc:
268 wiki.append('\n|-\n! scope=row | return value\n|')
269 wiki.append('<br />\n'.join(self._addTextDecorations(arg_doc['return']).rstrip('\n').split('\n')))
270 return "\n".join(wiki)
271
272 def generateCoreSide(self):
273 signals_part = []
274 methods_part = []
275 sections = self.bridge_template.sections()
276 sections.sort()
277 for section in sections:
278 function = self.getValues(section)
279 print ("Adding %s %s" % (section, function["type"]))
280 default = self.getDefault(section)
281 async_msg = """<br />'''This method is asynchronous'''"""
282 deprecated_msg = """<br />'''<font color="#FF0000">/!\ WARNING /!\ : This method is deprecated, please don't use it !</font>'''"""
283 signature_signal = \
284 """\
285 ! scope=row | signature
286 | %s
287 |-\
288 """ % function['sig_in']
289 signature_method = \
290 """\
291 ! scope=row | signature in
292 | %s
293 |-
294 ! scope=row | signature out
295 | %s
296 |-\
297 """ % (function['sig_in'], function['sig_out'])
298 completion = {
299 'signature': signature_signal if function['type'] == "signal" else signature_method,
300 'sig_out': function['sig_out'] or '',
301 'category': function['category'],
302 'name': section,
303 'doc': self.getDoc(section) or "FIXME: No description available",
304 'async': async_msg if "async" in self.getFlags(section) else "",
305 'deprecated': deprecated_msg if "deprecated" in self.getFlags(section) else "",
306 'parameters': self._wikiParameter(section, function['sig_in']),
307 'return': self._wikiReturn(section) if function['type'] == 'method' else ''}
308
309 dest = signals_part if function['type'] == "signal" else methods_part
310 dest.append("""\
311 == %(name)s ==
312 ''%(doc)s''
313 %(deprecated)s
314 %(async)s
315 {| class="wikitable" style="text-align:left; width:80%%;"
316 ! scope=row | category
317 | %(category)s
318 |-
319 %(signature)s
320 ! scope=row | parameters
321 |
322 %(parameters)s%(return)s
323 |}
324 """ % completion)
325
326 #at this point, signals_part, and methods_part should be filled,
327 #we just have to place them in the right part of the template
328 core_bridge = []
329 try:
330 with open(self.core_template) as core_template:
331 for line in core_template:
332 if line.startswith('##SIGNALS_PART##'):
333 core_bridge.extend(signals_part)
334 elif line.startswith('##METHODS_PART##'):
335 core_bridge.extend(methods_part)
336 elif line.startswith('##TIMESTAMP##'):
337 core_bridge.append('Generated on %s' % datetime.now())
338 else:
339 core_bridge.append(line.replace('\n', ''))
340 except IOError:
341 print ("Can't open template file [%s]" % self.core_template)
342 sys.exit(1)
343
344 #now we write to final file
345 self.finalWrite(self.core_dest, core_bridge)
346
347
348 class DbusConstructor(Constructor):
349
350 def __init__(self, bridge_template, options):
351 Constructor.__init__(self, bridge_template, options)
352 self.core_template = "dbus_core_template.py"
353 self.frontend_template = "dbus_frontend_template.py"
354 self.frontend_dest = self.core_dest = "DBus.py"
355
356 def generateCoreSide(self):
357 signals_part = []
358 methods_part = []
359 direct_calls = []
360 sections = self.bridge_template.sections()
361 sections.sort()
362 for section in sections:
363 function = self.getValues(section)
364 print ("Adding %s %s" % (section, function["type"]))
365 default = self.getDefault(section)
366 arg_doc = self.getArgumentsDoc(section)
367 async = "async" in self.getFlags(section)
368 completion = {
369 'sig_in': function['sig_in'] or '',
370 'sig_out': function['sig_out'] or '',
371 'category': 'PLUGIN' if function['category'] == 'plugin' else 'CORE',
372 'name': section,
373 'args': self.getArguments(function['sig_in'], name=arg_doc, default=default)}
374
375 if function["type"] == "signal":
376 completion['body'] = "pass" if not self.options.debug else 'debug ("%s")' % section
377 signals_part.append("""\
378 @dbus.service.signal(const_INT_PREFIX+const_%(category)s_SUFFIX,
379 signature='%(sig_in)s')
380 def %(name)s(self, %(args)s):
381 %(body)s
382 """ % completion)
383 direct_calls.append("""\
384 def %(name)s(self, %(args)s):
385 self.dbus_bridge.%(name)s(%(args)s)
386 """ % completion)
387
388 elif function["type"] == "method":
389 completion['debug'] = "" if not self.options.debug else 'debug ("%s")\n%s' % (section, 8 * ' ')
390 completion['args_result'] = self.getArguments(function['sig_in'], name=arg_doc, unicode_protect=self.options.unicode)
391 completion['async_comma'] = ', ' if async and function['sig_in'] else ''
392 completion['async_args_def'] = 'callback=None, errback=None' if async else ''
393 completion['async_args_call'] = 'callback=callback, errback=errback' if async else ''
394 completion['async_callbacks'] = "('callback', 'errback')" if async else "None"
395 methods_part.append("""\
396 @dbus.service.method(const_INT_PREFIX+const_%(category)s_SUFFIX,
397 in_signature='%(sig_in)s', out_signature='%(sig_out)s',
398 async_callbacks=%(async_callbacks)s)
399 def %(name)s(self, %(args)s%(async_comma)s%(async_args_def)s):
400 %(debug)sreturn self._callback("%(name)s", %(args_result)s%(async_comma)s%(async_args_call)s)
401 """ % completion)
402
403 #at this point, signals_part, methods_part and direct_calls should be filled,
404 #we just have to place them in the right part of the template
405 core_bridge = []
406 const_override_pref = filter(lambda env: env.startswith(ENV_OVERRIDE), os.environ)
407 const_override = [env[len(ENV_OVERRIDE):] for env in const_override_pref]
408 try:
409 with open(self.core_template) as core_template:
410 for line in core_template:
411 if line.startswith('##SIGNALS_PART##'):
412 core_bridge.extend(signals_part)
413 elif line.startswith('##METHODS_PART##'):
414 core_bridge.extend(methods_part)
415 elif line.startswith('##DIRECT_CALLS##'):
416 core_bridge.extend(direct_calls)
417 else:
418 if line.startswith('const_'):
419 const_name = line[len('const_'):line.find(' = ')]
420 if const_name in const_override:
421 print ("const %s overriden" % const_name)
422 core_bridge.append('const_%s = %s' % (const_name, os.environ[ENV_OVERRIDE + const_name]))
423 continue
424 core_bridge.append(line.replace('\n', ''))
425 except IOError:
426 print ("Can't open template file [%s]" % self.core_template)
427 sys.exit(1)
428
429 #now we write to final file
430 self.finalWrite(self.core_dest, core_bridge)
431
432 def generateFrontendSide(self):
433 methods_part = []
434 sections = self.bridge_template.sections()
435 sections.sort()
436 for section in sections:
437 function = self.getValues(section)
438 print ("Adding %s %s" % (section, function["type"]))
439 default = self.getDefault(section)
440 arg_doc = self.getArgumentsDoc(section)
441 async = "async" in self.getFlags(section)
442 completion = {
443 'sig_in': function['sig_in'] or '',
444 'sig_out': function['sig_out'] or '',
445 'category': 'plugin' if function['category'] == 'plugin' else 'core',
446 'name': section,
447 'args': self.getArguments(function['sig_in'], name=arg_doc, default=default)}
448
449 if function["type"] == "method":
450 completion['debug'] = "" if not self.options.debug else 'debug ("%s")\n%s' % (section, 8 * ' ')
451 completion['args_result'] = self.getArguments(function['sig_in'], name=arg_doc)
452 completion['async_args'] = ', callback=None, errback=None' if async else ''
453 completion['async_comma'] = ', ' if async and function['sig_in'] else ''
454 completion['async_args_result'] = 'reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:])' if async else ''
455 result = "self.db_%(category)s_iface.%(name)s(%(args_result)s%(async_comma)s%(async_args_result)s)" % completion
456 completion['result'] = ("unicode(%s)" if self.options.unicode and function['sig_out'] == 's' else "%s") % result
457 methods_part.append("""\
458 def %(name)s(self, %(args)s%(async_args)s):
459 %(debug)sreturn %(result)s
460 """ % completion)
461
462 #at this point, methods_part should be filled,
463 #we just have to place it in the right part of the template
464 frontend_bridge = []
465 const_override_pref = filter(lambda env: env.startswith(ENV_OVERRIDE), os.environ)
466 const_override = [env[len(ENV_OVERRIDE):] for env in const_override_pref]
467 try:
468 with open(self.frontend_template) as frontend_template:
469 for line in frontend_template:
470 if line.startswith('##METHODS_PART##'):
471 frontend_bridge.extend(methods_part)
472 else:
473 if line.startswith('const_'):
474 const_name = line[len('const_'):line.find(' = ')]
475 if const_name in const_override:
476 print ("const %s overriden" % const_name)
477 frontend_bridge.append('const_%s = %s' % (const_name, os.environ[ENV_OVERRIDE + const_name]))
478 continue
479 frontend_bridge.append(line.replace('\n', ''))
480 except IOError:
481 print ("Can't open template file [%s]" % self.frontend_template)
482 sys.exit(1)
483
484 #now we write to final file
485 self.finalWrite(self.frontend_dest, frontend_bridge)
486
487
488 class DbusXmlConstructor(Constructor):
489 """Constructor for DBus XML syntaxt (used by Qt frontend)"""
490
491 def __init__(self, bridge_template, options):
492 Constructor.__init__(self, bridge_template, options)
493
494 self.template = "dbus_xml_template.xml"
495 self.core_dest = "org.goffi.sat.xml"
496 self.default_annotation = {'a{ss}': 'StringDict',
497 'a(sa{ss}as)': 'QList<Contact>',
498 'a{i(ss)}': 'HistoryT',
499 'a(sss)': 'QList<MenuT>',
500 'a{sa{s(sia{ss})}}': 'PresenceStatusT',
501 'a{sa{ss}}': 'ActionResultExtDataT'}
502
503 def generateCoreSide(self):
504 try:
505 doc = minidom.parse(self.template)
506 interface_elt = doc.getElementsByTagName('interface')[0]
507 except IOError:
508 print ("Can't access template")
509 sys.exit(1)
510 except IndexError:
511 print ("Template error")
512 sys.exit(1)
513
514 sections = self.bridge_template.sections()
515 sections.sort()
516 for section in sections:
517 function = self.getValues(section)
518 print ("Adding %s %s" % (section, function["type"]))
519 new_elt = doc.createElement('method' if function["type"] == 'method' else 'signal')
520 new_elt.setAttribute('name', section)
521 args_in_str = self.getArguments(function['sig_in'])
522
523 idx = 0
524 args_doc = self.getArgumentsDoc(section)
525 for arg in self.argumentsParser(function['sig_in'] or ''):
526 arg_elt = doc.createElement('arg')
527 arg_elt.setAttribute('name', args_doc[idx][0] if idx in args_doc else "arg_%i" % idx)
528 arg_elt.setAttribute('type', arg)
529 _direction = 'in' if function["type"] == 'method' else 'out'
530 arg_elt.setAttribute('direction', _direction)
531 new_elt.appendChild(arg_elt)
532 if "annotation" in self.options.flags:
533 if arg in self.default_annotation:
534 annot_elt = doc.createElement("annotation")
535 annot_elt.setAttribute('name', "com.trolltech.QtDBus.QtTypeName.In%d" % idx)
536 annot_elt.setAttribute('value', self.default_annotation[arg])
537 new_elt.appendChild(annot_elt)
538 idx += 1
539
540 if function['sig_out']:
541 arg_elt = doc.createElement('arg')
542 arg_elt.setAttribute('type', function['sig_out'])
543 arg_elt.setAttribute('direction', 'out')
544 new_elt.appendChild(arg_elt)
545 if "annotation" in self.options.flags:
546 if function['sig_out'] in self.default_annotation:
547 annot_elt = doc.createElement("annotation")
548 annot_elt.setAttribute('name', "com.trolltech.QtDBus.QtTypeName.Out0")
549 annot_elt.setAttribute('value', self.default_annotation[function['sig_out']])
550 new_elt.appendChild(annot_elt)
551
552 interface_elt.appendChild(new_elt)
553
554 #now we write to final file
555 self.finalWrite(self.core_dest, [doc.toprettyxml()])
556
557
558 class ConstructorError(Exception):
559 pass
560
561
562 class ConstructorFactory(object):
563 def create(self, bridge_template, options):
564 if options.protocole == 'dbus':
565 return DbusConstructor(bridge_template, options)
566 elif options.protocole == 'mediawiki':
567 return MediawikiConstructor(bridge_template, options)
568 elif options.protocole == 'dbus-xml':
569 return DbusXmlConstructor(bridge_template, options)
570
571 raise ConstructorError('Unknown constructor type')
572
573
574 class BridgeConstructor(object):
575 def __init__(self):
576 self.options = None
577
578 def check_options(self):
579 """Check command line options"""
580 _usage = """
581 %prog [options]
582
583 %prog --help for options list
584 """
585 parser = OptionParser(usage=_usage, version=ABOUT % VERSION)
586
587 parser.add_option("-p", "--protocole", action="store", type="string", default=DEFAULT_PROTOCOLE,
588 help="Generate bridge using PROTOCOLE (default: %s, possible values: [%s])" % (DEFAULT_PROTOCOLE, ", ".join(MANAGED_PROTOCOLES)))
589 parser.add_option("-s", "--side", action="store", type="string", default="core",
590 help="Which side of the bridge do you want to make ? (default: %default, possible values: [core, frontend])")
591 parser.add_option("-t", "--template", action="store", type="string", default='bridge_template.ini',
592 help="Use TEMPLATE to generate bridge (default: %default)")
593 parser.add_option("-f", "--force", action="store_true", default=False,
594 help=("Force overwritting of existing files"))
595 parser.add_option("-d", "--debug", action="store_true", default=False,
596 help=("Add debug information printing"))
597 parser.add_option("--no_unicode", action="store_false", dest="unicode", default=True,
598 help=("Remove unicode type protection from string results"))
599 parser.add_option("--flags", action="store", type="string",
600 help=("Constructors' specific flags, comma separated"))
601
602 (self.options, args) = parser.parse_args()
603 self.options.flags = self.options.flags.split(',') if self.options.flags else []
604 return args
605
606 def go(self):
607 self.check_options()
608 self.template = Parser()
609 try:
610 self.template.readfp(open(self.options.template))
611 except IOError:
612 print ("The template file doesn't exist or is not accessible")
613 exit(1)
614 constructor = ConstructorFactory().create(self.template, self.options)
615 if self.options.side == "core":
616 constructor.generateCoreSide()
617 elif self.options.side == "frontend":
618 constructor.generateFrontendSide()
619
620 if __name__ == "__main__":
621 bc = BridgeConstructor()
622 bc.go()