bridge(constructor): constructor now uses argparse instead of optparse

This commit is contained in:
Goffi 2016-10-02 15:56:20 +02:00
commit df1b19bd66

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python2
#-*- coding: utf-8 -*-
# SAT: a jabber client
# SàT: a XMPP client
# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org)
# This program is free software: you can redistribute it and/or modify
@ -17,36 +17,38 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#consts
NAME = u"bridge_constructor"
VERSION = "0.1.0"
DEST_DIR = "generated"
ABOUT = NAME + u""" v%s (c) Jérôme Poisson (aka Goffi) 2011
---
""" + NAME + u""" Copyright (C) 2011 Jérôme Poisson (aka Goffi)
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions.
---
This script construct a SàT bridge using the given protocol
"""
MANAGED_PROTOCOLES = ['dbus', 'mediawiki', 'dbus-xml']
DEFAULT_PROTOCOLE = 'dbus'
FLAGS = ['deprecated', 'async']
ENV_OVERRIDE = "SAT_BRIDGE_CONST_" # Prefix used to override a constant
from sat.core.constants import Const as C
import sys
import os
from optparse import OptionParser
import argparse
from ConfigParser import SafeConfigParser as Parser
from ConfigParser import NoOptionError
import re
from datetime import datetime
from xml.dom import minidom
#consts
NAME = u"bridge_constructor"
__version__ = C.APP_VERSION
DEST_DIR_DEFAULT = "generated"
DESCRIPTION = u"""{name} Copyright (C) 2009-2016 Jérôme Poisson (aka Goffi)
This script construct a SàT bridge using the given protocol
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions.
""".format(name=NAME, version=__version__)
# TODO: move protocoles in separate files (plugins?)
MANAGED_PROTOCOLES = ['dbus', 'mediawiki', 'dbus-xml']
DEFAULT_PROTOCOLE = 'dbus'
# flags used method/signal declaration (not to be confused with constructor flags)
DECLARATION_FLAGS = ['deprecated', 'async']
ENV_OVERRIDE = "SAT_BRIDGE_CONST_" # Prefix used to override a constant
class ParseError(Exception):
#Used when the signature parsing is going wrong (invalid signature ?)
@ -57,7 +59,7 @@ class Constructor(object):
def __init__(self, bridge_template, options):
self.bridge_template = bridge_template
self.options = options
self.args = options
def getValues(self, name):
"""Return values of a function in a dict
@ -96,7 +98,7 @@ class Constructor(object):
@return: List of flags (string)"""
flags = []
for option in self.bridge_template.options(name):
if option in FLAGS:
if option in DECLARATION_FLAGS:
flags.append(option)
return flags
@ -196,17 +198,19 @@ class Constructor(object):
raise NotImplementedError
def finalWrite(self, filename, file_buf):
"""Write the final generated file in DEST_DIR/filename
"""Write the final generated file in [dest dir]/filename
@param filename: name of the file to generate
@param file_buf: list of lines (stings) of the file"""
if os.path.exists(DEST_DIR) and not os.path.isdir(DEST_DIR):
@param file_buf: list of lines (stings) of the file
"""
if os.path.exists(self.args.dest_dir) and not os.path.isdir(self.args.dest_dir):
print ("The destination dir [%s] can't be created: a file with this name already exists !")
sys.exit(1)
try:
if not os.path.exists(DEST_DIR):
os.mkdir(DEST_DIR)
full_path = os.path.join(DEST_DIR, filename)
if os.path.exists(full_path) and not self.options.force:
if not os.path.exists(self.args.dest_dir):
os.mkdir(self.args.dest_dir)
full_path = os.path.join(self.args.dest_dir, filename)
if os.path.exists(full_path) and not self.args.force:
print ("The destination file [%s] already exists ! Use --force to overwrite it" % full_path)
try:
with open(full_path, 'w') as dest_file:
@ -373,7 +377,7 @@ class DbusConstructor(Constructor):
'args': self.getArguments(function['sig_in'], name=arg_doc, default=default)}
if function["type"] == "signal":
completion['body'] = "pass" if not self.options.debug else 'log.debug ("%s")' % section
completion['body'] = "pass" if not self.args.debug else 'log.debug ("%s")' % section
signals_part.append("""\
@dbus.service.signal(const_INT_PREFIX+const_%(category)s_SUFFIX,
signature='%(sig_in)s')
@ -386,8 +390,8 @@ class DbusConstructor(Constructor):
""" % completion)
elif function["type"] == "method":
completion['debug'] = "" if not self.options.debug else 'log.debug ("%s")\n%s' % (section, 8 * ' ')
completion['args_result'] = self.getArguments(function['sig_in'], name=arg_doc, unicode_protect=self.options.unicode)
completion['debug'] = "" if not self.args.debug else 'log.debug ("%s")\n%s' % (section, 8 * ' ')
completion['args_result'] = self.getArguments(function['sig_in'], name=arg_doc, unicode_protect=self.args.unicode)
completion['async_comma'] = ', ' if async and function['sig_in'] else ''
completion['async_args_def'] = 'callback=None, errback=None' if async else ''
completion['async_args_call'] = 'callback=callback, errback=errback' if async else ''
@ -448,7 +452,7 @@ class DbusConstructor(Constructor):
if function["type"] == "method":
# XXX: we can manage blocking call in the same way as async one: if callback is None the call will be blocking
completion['debug'] = "" if not self.options.debug else 'log.debug ("%s")\n%s' % (section, 8 * ' ')
completion['debug'] = "" if not self.args.debug else 'log.debug ("%s")\n%s' % (section, 8 * ' ')
completion['args_result'] = self.getArguments(function['sig_in'], name=arg_doc)
completion['async_args'] = 'callback=None, errback=None'
completion['async_comma'] = ', ' if function['sig_in'] else ''
@ -472,7 +476,7 @@ class DbusConstructor(Constructor):
"""
completion['async_args_result'] = '**kwargs'
result = "self.db_%(category)s_iface.%(name)s(%(args_result)s%(async_comma)s%(async_args_result)s)" % completion
completion['result'] = ("unicode(%s)" if self.options.unicode and function['sig_out'] == 's' else "%s") % result
completion['result'] = ("unicode(%s)" if self.args.unicode and function['sig_out'] == 's' else "%s") % result
methods_part.append("""\
def %(name)s(self, %(args)s%(async_comma)s%(async_args)s):
%(error_handler)s%(blocking_call)s%(debug)sreturn %(result)s
@ -547,7 +551,7 @@ class DbusXmlConstructor(Constructor):
_direction = 'in' if function["type"] == 'method' else 'out'
arg_elt.setAttribute('direction', _direction)
new_elt.appendChild(arg_elt)
if "annotation" in self.options.flags:
if "annotation" in self.args.flags:
if arg in self.default_annotation:
annot_elt = doc.createElement("annotation")
annot_elt.setAttribute('name', "com.trolltech.QtDBus.QtTypeName.In%d" % idx)
@ -560,7 +564,7 @@ class DbusXmlConstructor(Constructor):
arg_elt.setAttribute('type', function['sig_out'])
arg_elt.setAttribute('direction', 'out')
new_elt.appendChild(arg_elt)
if "annotation" in self.options.flags:
if "annotation" in self.args.flags:
if function['sig_out'] in self.default_annotation:
annot_elt = doc.createElement("annotation")
annot_elt.setAttribute('name', "com.trolltech.QtDBus.QtTypeName.Out0")
@ -591,48 +595,44 @@ class ConstructorFactory(object):
class BridgeConstructor(object):
def __init__(self):
self.options = None
self.args = None
def check_options(self):
def parse_args(self):
"""Check command line options"""
_usage = """
%prog [options]
parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.RawDescriptionHelpFormatter)
%prog --help for options list
"""
parser = OptionParser(usage=_usage, version=ABOUT % VERSION)
parser.add_argument("--version", action="version", version= __version__)
parser.add_argument("-p", "--protocole", choices=MANAGED_PROTOCOLES, default=DEFAULT_PROTOCOLE,
help="generate bridge using PROTOCOLE (default: %(default)s)") # (default: %s, possible values: [%s])" % (DEFAULT_PROTOCOLE, ", ".join(MANAGED_PROTOCOLES)))
parser.add_argument("-s", "--side", choices=("core", "frontend"), default="core",
help="which side of the bridge do you want to make ?") # (default: %default, possible values: [core, frontend])")
parser.add_argument("-t", "--template", type=file, default='bridge_template.ini',
help="use TEMPLATE to generate bridge (default: %(default)s)")
parser.add_argument("-f", "--force", action="store_true",
help=("force overwritting of existing files"))
parser.add_argument("-d", "--debug", action="store_true",
help=("add debug information printing"))
parser.add_argument("--no-unicode", action="store_false", dest="unicode",
help=("remove unicode type protection from string results"))
parser.add_argument("--flags", nargs='+', default=[],
help=("constructors' specific flags"))
parser.add_argument("--dest-dir", default=DEST_DIR_DEFAULT,
help=("directory when the generated files will be written (default: %(default)s"))
parser.add_option("-p", "--protocole", action="store", type="string", default=DEFAULT_PROTOCOLE,
help="Generate bridge using PROTOCOLE (default: %s, possible values: [%s])" % (DEFAULT_PROTOCOLE, ", ".join(MANAGED_PROTOCOLES)))
parser.add_option("-s", "--side", action="store", type="string", default="core",
help="Which side of the bridge do you want to make ? (default: %default, possible values: [core, frontend])")
parser.add_option("-t", "--template", action="store", type="string", default='bridge_template.ini',
help="Use TEMPLATE to generate bridge (default: %default)")
parser.add_option("-f", "--force", action="store_true", default=False,
help=("Force overwritting of existing files"))
parser.add_option("-d", "--debug", action="store_true", default=False,
help=("Add debug information printing"))
parser.add_option("--no_unicode", action="store_false", dest="unicode", default=True,
help=("Remove unicode type protection from string results"))
parser.add_option("--flags", action="store", type="string",
help=("Constructors' specific flags, comma separated"))
(self.options, args) = parser.parse_args()
self.options.flags = self.options.flags.split(',') if self.options.flags else []
return args
return parser.parse_args()
def go(self):
self.check_options()
args = self.parse_args()
self.template = Parser()
try:
self.template.readfp(open(self.options.template))
self.template.readfp(args.template)
except IOError:
print ("The template file doesn't exist or is not accessible")
exit(1)
constructor = ConstructorFactory().create(self.template, self.options)
if self.options.side == "core":
constructor = ConstructorFactory().create(self.template, args)
if args.side == "core":
constructor.generateCoreSide()
elif self.options.side == "frontend":
elif args.side == "frontend":
constructor.generateFrontendSide()
if __name__ == "__main__":