Mercurial > libervia-backend
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() |