code style reformatting using black
This commit is contained in:
parent
4127bcffd0
commit
744cb0c503
205 changed files with 21394 additions and 10488 deletions
|
|
@ -18,10 +18,10 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import os.path
|
||||
|
||||
version_file = os.path.join(os.path.dirname(__file__), 'VERSION')
|
||||
version_file = os.path.join(os.path.dirname(__file__), "VERSION")
|
||||
try:
|
||||
with open(version_file) as f:
|
||||
__version__ = f.read().strip()
|
||||
except NotImplementedError:
|
||||
# pyjamas workaround
|
||||
__version__ = '0.7D'
|
||||
__version__ = "0.7D"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -29,7 +29,7 @@ from importlib import import_module
|
|||
|
||||
|
||||
class ParseError(Exception):
|
||||
#Used when the signature parsing is going wrong (invalid signature ?)
|
||||
# Used when the signature parsing is going wrong (invalid signature ?)
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ class Constructor(object):
|
|||
# replace ##SIGNALS_PART## in template), while the value is the format
|
||||
# keys starting with "signal" will be used for signals, while ones starting with
|
||||
# "method" will be used for methods
|
||||
# check D-Bus constructor for an example
|
||||
# check D-Bus constructor for an example
|
||||
CORE_FORMATS = None
|
||||
CORE_TEMPLATE = None
|
||||
CORE_DEST = None
|
||||
|
|
@ -66,7 +66,7 @@ class Constructor(object):
|
|||
@param name: Name of the function to get
|
||||
@return: dict, each key has the config value or None if the value is not set"""
|
||||
function = {}
|
||||
for option in ['type', 'category', 'sig_in', 'sig_out', 'doc']:
|
||||
for option in ["type", "category", "sig_in", "sig_out", "doc"]:
|
||||
try:
|
||||
value = self.bridge_template.get(name, option)
|
||||
except NoOptionError:
|
||||
|
|
@ -87,7 +87,9 @@ class Constructor(object):
|
|||
try:
|
||||
idx = int(match.group(1))
|
||||
except ValueError:
|
||||
raise ParseError("Invalid value [%s] for parameter number" % match.group(1))
|
||||
raise ParseError(
|
||||
"Invalid value [%s] for parameter number" % match.group(1)
|
||||
)
|
||||
default_dict[idx] = self.bridge_template.get(name, option)
|
||||
|
||||
return default_dict
|
||||
|
|
@ -112,15 +114,17 @@ class Constructor(object):
|
|||
option_re = re.compile(r"doc_param_(\d+)")
|
||||
value_re = re.compile(r"^(\w+): (.*)$", re.MULTILINE | re.DOTALL)
|
||||
for option in self.bridge_template.options(name):
|
||||
if option == 'doc_return':
|
||||
doc_dict['return'] = self.bridge_template.get(name, option)
|
||||
if option == "doc_return":
|
||||
doc_dict["return"] = self.bridge_template.get(name, option)
|
||||
continue
|
||||
match = option_re.match(option)
|
||||
if match:
|
||||
try:
|
||||
idx = int(match.group(1))
|
||||
except ValueError:
|
||||
raise ParseError("Invalid value [%s] for parameter number" % match.group(1))
|
||||
raise ParseError(
|
||||
"Invalid value [%s] for parameter number" % match.group(1)
|
||||
)
|
||||
value_match = value_re.match(self.bridge_template.get(name, option))
|
||||
if not value_match:
|
||||
raise ParseError("Invalid value for parameter doc [%i]" % idx)
|
||||
|
|
@ -141,21 +145,35 @@ class Constructor(object):
|
|||
i = 0
|
||||
|
||||
while i < len(signature):
|
||||
if signature[i] not in ['b', 'y', 'n', 'i', 'x', 'q', 'u', 't', 'd', 's', 'a']:
|
||||
if signature[i] not in [
|
||||
"b",
|
||||
"y",
|
||||
"n",
|
||||
"i",
|
||||
"x",
|
||||
"q",
|
||||
"u",
|
||||
"t",
|
||||
"d",
|
||||
"s",
|
||||
"a",
|
||||
]:
|
||||
raise ParseError("Unmanaged attribute type [%c]" % signature[i])
|
||||
|
||||
if signature[i] == 'a':
|
||||
if signature[i] == "a":
|
||||
i += 1
|
||||
if signature[i] != '{' and signature[i] != '(': # FIXME: must manage tuples out of arrays
|
||||
if (
|
||||
signature[i] != "{" and signature[i] != "("
|
||||
): # FIXME: must manage tuples out of arrays
|
||||
i += 1
|
||||
yield signature[start:i]
|
||||
start = i
|
||||
continue # we have a simple type for the array
|
||||
opening_car = signature[i]
|
||||
assert(opening_car in ['{', '('])
|
||||
closing_car = '}' if opening_car == '{' else ')'
|
||||
assert opening_car in ["{", "("]
|
||||
closing_car = "}" if opening_car == "{" else ")"
|
||||
opening_count = 1
|
||||
while (True): # we have a dict or a list of tuples
|
||||
while True: # we have a dict or a list of tuples
|
||||
i += 1
|
||||
if i >= len(signature):
|
||||
raise ParseError("missing }")
|
||||
|
|
@ -182,11 +200,19 @@ class Constructor(object):
|
|||
attr_string = []
|
||||
|
||||
for arg in self.argumentsParser(signature):
|
||||
attr_string.append(("unicode(%(name)s)%(default)s" if (unicode_protect and arg == 's') else "%(name)s%(default)s") % {
|
||||
'name': name[idx][0] if (name and idx in name) else "arg_%i" % idx,
|
||||
'default': "=" + default[idx] if (default and idx in default) else ''})
|
||||
# give arg_1, arg2, etc or name1, name2=default, etc.
|
||||
#give unicode(arg_1), unicode(arg_2), etc. if unicode_protect is set and arg is a string
|
||||
attr_string.append(
|
||||
(
|
||||
"unicode(%(name)s)%(default)s"
|
||||
if (unicode_protect and arg == "s")
|
||||
else "%(name)s%(default)s"
|
||||
)
|
||||
% {
|
||||
"name": name[idx][0] if (name and idx in name) else "arg_%i" % idx,
|
||||
"default": "=" + default[idx] if (default and idx in default) else "",
|
||||
}
|
||||
)
|
||||
# give arg_1, arg2, etc or name1, name2=default, etc.
|
||||
# give unicode(arg_1), unicode(arg_2), etc. if unicode_protect is set and arg is a string
|
||||
idx += 1
|
||||
|
||||
return ", ".join(attr_string)
|
||||
|
|
@ -214,7 +240,6 @@ class Constructor(object):
|
|||
"""override this method to extend completion"""
|
||||
pass
|
||||
|
||||
|
||||
def generate(self, side):
|
||||
"""generate bridge
|
||||
|
||||
|
|
@ -242,7 +267,7 @@ class Constructor(object):
|
|||
@param side(str): core or frontend
|
||||
"""
|
||||
side_vars = []
|
||||
for var in ('FORMATS', 'TEMPLATE', 'DEST'):
|
||||
for var in ("FORMATS", "TEMPLATE", "DEST"):
|
||||
attr = "{}_{}".format(side.upper(), var)
|
||||
value = getattr(self, attr)
|
||||
if value is None:
|
||||
|
|
@ -252,59 +277,70 @@ class Constructor(object):
|
|||
FORMATS, TEMPLATE, DEST = side_vars
|
||||
del side_vars
|
||||
|
||||
parts = {part.upper():[] for part in FORMATS}
|
||||
parts = {part.upper(): [] for part in FORMATS}
|
||||
sections = self.bridge_template.sections()
|
||||
sections.sort()
|
||||
for section in sections:
|
||||
function = self.getValues(section)
|
||||
print ("Adding %s %s" % (section, function["type"]))
|
||||
print("Adding %s %s" % (section, function["type"]))
|
||||
default = self.getDefault(section)
|
||||
arg_doc = self.getArgumentsDoc(section)
|
||||
async_ = "async" in self.getFlags(section)
|
||||
completion = {
|
||||
'sig_in': function['sig_in'] or '',
|
||||
'sig_out': function['sig_out'] or '',
|
||||
'category': 'plugin' if function['category'] == 'plugin' else 'core',
|
||||
'name': section,
|
||||
"sig_in": function["sig_in"] or "",
|
||||
"sig_out": function["sig_out"] or "",
|
||||
"category": "plugin" if function["category"] == "plugin" else "core",
|
||||
"name": section,
|
||||
# arguments with default values
|
||||
'args': self.getArguments(function['sig_in'], name=arg_doc, default=default),
|
||||
}
|
||||
"args": self.getArguments(
|
||||
function["sig_in"], name=arg_doc, default=default
|
||||
),
|
||||
}
|
||||
|
||||
extend_method = getattr(self, "{}_completion_{}".format(side, function["type"]))
|
||||
extend_method = getattr(
|
||||
self, "{}_completion_{}".format(side, function["type"])
|
||||
)
|
||||
extend_method(completion, function, default, arg_doc, async_)
|
||||
|
||||
for part, fmt in FORMATS.iteritems():
|
||||
if part.startswith(function["type"]):
|
||||
parts[part.upper()].append(fmt.format(**completion))
|
||||
|
||||
|
||||
#at this point, signals_part, methods_part and direct_calls should be filled,
|
||||
#we just have to place them in the right part of the template
|
||||
# at this point, signals_part, methods_part and direct_calls should be filled,
|
||||
# we just have to place them in the right part of the template
|
||||
bridge = []
|
||||
const_override = {env[len(C.ENV_OVERRIDE):]:v for env,v in os.environ.iteritems() if env.startswith(C.ENV_OVERRIDE)}
|
||||
const_override = {
|
||||
env[len(C.ENV_OVERRIDE) :]: v
|
||||
for env, v in os.environ.iteritems()
|
||||
if env.startswith(C.ENV_OVERRIDE)
|
||||
}
|
||||
template_path = self.getTemplatePath(TEMPLATE)
|
||||
try:
|
||||
with open(template_path) as template:
|
||||
for line in template:
|
||||
|
||||
for part, extend_list in parts.iteritems():
|
||||
if line.startswith('##{}_PART##'.format(part)):
|
||||
if line.startswith("##{}_PART##".format(part)):
|
||||
bridge.extend(extend_list)
|
||||
break
|
||||
else:
|
||||
# the line is not a magic part replacement
|
||||
if line.startswith('const_'):
|
||||
const_name = line[len('const_'):line.find(' = ')].strip()
|
||||
if line.startswith("const_"):
|
||||
const_name = line[len("const_") : line.find(" = ")].strip()
|
||||
if const_name in const_override:
|
||||
print("const {} overriden".format(const_name))
|
||||
bridge.append('const_{} = {}'.format(const_name, const_override[const_name]))
|
||||
bridge.append(
|
||||
"const_{} = {}".format(
|
||||
const_name, const_override[const_name]
|
||||
)
|
||||
)
|
||||
continue
|
||||
bridge.append(line.replace('\n', ''))
|
||||
bridge.append(line.replace("\n", ""))
|
||||
except IOError:
|
||||
print ("can't open template file [{}]".format(template_path))
|
||||
print("can't open template file [{}]".format(template_path))
|
||||
sys.exit(1)
|
||||
|
||||
#now we write to final file
|
||||
# now we write to final file
|
||||
self.finalWrite(DEST, bridge)
|
||||
|
||||
def finalWrite(self, filename, file_buf):
|
||||
|
|
@ -314,19 +350,24 @@ class Constructor(object):
|
|||
@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 !")
|
||||
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(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)
|
||||
print(
|
||||
"The destination file [%s] already exists ! Use --force to overwrite it"
|
||||
% full_path
|
||||
)
|
||||
try:
|
||||
with open(full_path, 'w') as dest_file:
|
||||
dest_file.write('\n'.join(file_buf))
|
||||
with open(full_path, "w") as dest_file:
|
||||
dest_file.write("\n".join(file_buf))
|
||||
except IOError:
|
||||
print ("Can't open destination file [%s]" % full_path)
|
||||
print("Can't open destination file [%s]" % full_path)
|
||||
except OSError:
|
||||
print("It's not possible to generate the file, check your permissions")
|
||||
exit(1)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -23,23 +23,24 @@ from sat.bridge.bridge_constructor.constants import Const as C
|
|||
from sat.bridge.bridge_constructor import constructors, base_constructor
|
||||
import argparse
|
||||
from ConfigParser import SafeConfigParser as Parser
|
||||
from importlib import import_module
|
||||
from importlib import import_module
|
||||
import os
|
||||
import os.path
|
||||
|
||||
#consts
|
||||
# consts
|
||||
__version__ = C.APP_VERSION
|
||||
|
||||
|
||||
class BridgeConstructor(object):
|
||||
|
||||
def importConstructors(self):
|
||||
constructors_dir = os.path.dirname(constructors.__file__)
|
||||
self.protocoles = {}
|
||||
for dir_ in os.listdir(constructors_dir):
|
||||
init_path = os.path.join(constructors_dir, dir_, '__init__.py')
|
||||
constructor_path = os.path.join(constructors_dir, dir_, 'constructor.py')
|
||||
module_path = "sat.bridge.bridge_constructor.constructors.{}.constructor".format(dir_)
|
||||
init_path = os.path.join(constructors_dir, dir_, "__init__.py")
|
||||
constructor_path = os.path.join(constructors_dir, dir_, "constructor.py")
|
||||
module_path = "sat.bridge.bridge_constructor.constructors.{}.constructor".format(
|
||||
dir_
|
||||
)
|
||||
if os.path.isfile(init_path) and os.path.isfile(constructor_path):
|
||||
mod = import_module(module_path)
|
||||
for attr in dir(mod):
|
||||
|
|
@ -55,27 +56,66 @@ class BridgeConstructor(object):
|
|||
|
||||
def parse_args(self):
|
||||
"""Check command line options"""
|
||||
parser = argparse.ArgumentParser(description=C.DESCRIPTION, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser = argparse.ArgumentParser(
|
||||
description=C.DESCRIPTION,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
|
||||
parser.add_argument("--version", action="version", version= __version__)
|
||||
default_protocole = C.DEFAULT_PROTOCOLE if C.DEFAULT_PROTOCOLE in self.protocoles else self.protocoles[0]
|
||||
parser.add_argument("-p", "--protocole", choices=sorted(self.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])")
|
||||
default_template = os.path.join(os.path.dirname(bridge_constructor.__file__), 'bridge_template.ini')
|
||||
parser.add_argument("-t", "--template", type=file, default=default_template,
|
||||
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=C.DEST_DIR_DEFAULT,
|
||||
help=("directory when the generated files will be written (default: %(default)s)"))
|
||||
parser.add_argument("--version", action="version", version=__version__)
|
||||
default_protocole = (
|
||||
C.DEFAULT_PROTOCOLE
|
||||
if C.DEFAULT_PROTOCOLE in self.protocoles
|
||||
else self.protocoles[0]
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--protocole",
|
||||
choices=sorted(self.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])")
|
||||
default_template = os.path.join(
|
||||
os.path.dirname(bridge_constructor.__file__), "bridge_template.ini"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--template",
|
||||
type=file,
|
||||
default=default_template,
|
||||
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=C.DEST_DIR_DEFAULT,
|
||||
help=(
|
||||
"directory when the generated files will be written (default: %(default)s)"
|
||||
),
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
|
@ -86,7 +126,7 @@ class BridgeConstructor(object):
|
|||
try:
|
||||
template_parser.readfp(args.template)
|
||||
except IOError:
|
||||
print ("The template file doesn't exist or is not accessible")
|
||||
print("The template file doesn't exist or is not accessible")
|
||||
exit(1)
|
||||
constructor = self.protocoles[args.protocole](template_parser, args)
|
||||
constructor.generate(args.side)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -31,11 +31,13 @@ class Const(constants.Const):
|
|||
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=constants.Const.APP_VERSION)
|
||||
# TODO: move protocoles in separate files (plugins?)
|
||||
DEFAULT_PROTOCOLE = 'dbus'
|
||||
""".format(
|
||||
name=NAME, version=constants.Const.APP_VERSION
|
||||
)
|
||||
# TODO: move protocoles in separate files (plugins?)
|
||||
DEFAULT_PROTOCOLE = "dbus"
|
||||
|
||||
# flags used method/signal declaration (not to be confused with constructor flags)
|
||||
DECLARATION_FLAGS = ['deprecated', 'async']
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -30,62 +30,73 @@ class DbusXmlConstructor(base_constructor.Constructor):
|
|||
|
||||
self.template = "dbus_xml_template.xml"
|
||||
self.core_dest = "org.goffi.sat.xml"
|
||||
self.default_annotation = {'a{ss}': 'StringDict',
|
||||
'a(sa{ss}as)': 'QList<Contact>',
|
||||
'a{i(ss)}': 'HistoryT',
|
||||
'a(sss)': 'QList<MenuT>',
|
||||
'a{sa{s(sia{ss})}}': 'PresenceStatusT',
|
||||
}
|
||||
self.default_annotation = {
|
||||
"a{ss}": "StringDict",
|
||||
"a(sa{ss}as)": "QList<Contact>",
|
||||
"a{i(ss)}": "HistoryT",
|
||||
"a(sss)": "QList<MenuT>",
|
||||
"a{sa{s(sia{ss})}}": "PresenceStatusT",
|
||||
}
|
||||
|
||||
def generateCoreSide(self):
|
||||
try:
|
||||
doc = minidom.parse(self.getTemplatePath(self.template))
|
||||
interface_elt = doc.getElementsByTagName('interface')[0]
|
||||
interface_elt = doc.getElementsByTagName("interface")[0]
|
||||
except IOError:
|
||||
print ("Can't access template")
|
||||
print("Can't access template")
|
||||
sys.exit(1)
|
||||
except IndexError:
|
||||
print ("Template error")
|
||||
print("Template error")
|
||||
sys.exit(1)
|
||||
|
||||
sections = self.bridge_template.sections()
|
||||
sections.sort()
|
||||
for section in sections:
|
||||
function = self.getValues(section)
|
||||
print ("Adding %s %s" % (section, function["type"]))
|
||||
new_elt = doc.createElement('method' if function["type"] == 'method' else 'signal')
|
||||
new_elt.setAttribute('name', section)
|
||||
print("Adding %s %s" % (section, function["type"]))
|
||||
new_elt = doc.createElement(
|
||||
"method" if function["type"] == "method" else "signal"
|
||||
)
|
||||
new_elt.setAttribute("name", section)
|
||||
|
||||
idx = 0
|
||||
args_doc = self.getArgumentsDoc(section)
|
||||
for arg in self.argumentsParser(function['sig_in'] or ''):
|
||||
arg_elt = doc.createElement('arg')
|
||||
arg_elt.setAttribute('name', args_doc[idx][0] if idx in args_doc else "arg_%i" % idx)
|
||||
arg_elt.setAttribute('type', arg)
|
||||
_direction = 'in' if function["type"] == 'method' else 'out'
|
||||
arg_elt.setAttribute('direction', _direction)
|
||||
for arg in self.argumentsParser(function["sig_in"] or ""):
|
||||
arg_elt = doc.createElement("arg")
|
||||
arg_elt.setAttribute(
|
||||
"name", args_doc[idx][0] if idx in args_doc else "arg_%i" % idx
|
||||
)
|
||||
arg_elt.setAttribute("type", arg)
|
||||
_direction = "in" if function["type"] == "method" else "out"
|
||||
arg_elt.setAttribute("direction", _direction)
|
||||
new_elt.appendChild(arg_elt)
|
||||
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)
|
||||
annot_elt.setAttribute('value', self.default_annotation[arg])
|
||||
annot_elt.setAttribute(
|
||||
"name", "com.trolltech.QtDBus.QtTypeName.In%d" % idx
|
||||
)
|
||||
annot_elt.setAttribute("value", self.default_annotation[arg])
|
||||
new_elt.appendChild(annot_elt)
|
||||
idx += 1
|
||||
|
||||
if function['sig_out']:
|
||||
arg_elt = doc.createElement('arg')
|
||||
arg_elt.setAttribute('type', function['sig_out'])
|
||||
arg_elt.setAttribute('direction', 'out')
|
||||
if function["sig_out"]:
|
||||
arg_elt = doc.createElement("arg")
|
||||
arg_elt.setAttribute("type", function["sig_out"])
|
||||
arg_elt.setAttribute("direction", "out")
|
||||
new_elt.appendChild(arg_elt)
|
||||
if "annotation" in self.args.flags:
|
||||
if function['sig_out'] in self.default_annotation:
|
||||
if function["sig_out"] in self.default_annotation:
|
||||
annot_elt = doc.createElement("annotation")
|
||||
annot_elt.setAttribute('name', "com.trolltech.QtDBus.QtTypeName.Out0")
|
||||
annot_elt.setAttribute('value', self.default_annotation[function['sig_out']])
|
||||
annot_elt.setAttribute(
|
||||
"name", "com.trolltech.QtDBus.QtTypeName.Out0"
|
||||
)
|
||||
annot_elt.setAttribute(
|
||||
"value", self.default_annotation[function["sig_out"]]
|
||||
)
|
||||
new_elt.appendChild(annot_elt)
|
||||
|
||||
interface_elt.appendChild(new_elt)
|
||||
|
||||
#now we write to final file
|
||||
# now we write to final file
|
||||
self.finalWrite(self.core_dest, [doc.toprettyxml()])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -25,73 +25,94 @@ class DbusConstructor(base_constructor.Constructor):
|
|||
CORE_TEMPLATE = "dbus_core_template.py"
|
||||
CORE_DEST = "dbus_bridge.py"
|
||||
CORE_FORMATS = {
|
||||
'signals': """\
|
||||
"signals": """\
|
||||
@dbus.service.signal(const_INT_PREFIX+const_{category}_SUFFIX,
|
||||
signature='{sig_in}')
|
||||
def {name}(self, {args}):
|
||||
{body}\n""",
|
||||
|
||||
'methods': """\
|
||||
"methods": """\
|
||||
@dbus.service.method(const_INT_PREFIX+const_{category}_SUFFIX,
|
||||
in_signature='{sig_in}', out_signature='{sig_out}',
|
||||
async_callbacks={async_callbacks})
|
||||
def {name}(self, {args}{async_comma}{async_args_def}):
|
||||
{debug}return self._callback("{name}", {args_result}{async_comma}{async_args_call})\n""",
|
||||
|
||||
'signal_direct_calls': """\
|
||||
"signal_direct_calls": """\
|
||||
def {name}(self, {args}):
|
||||
self.dbus_bridge.{name}({args})\n""",
|
||||
}
|
||||
}
|
||||
|
||||
FRONTEND_TEMPLATE = "dbus_frontend_template.py"
|
||||
FRONTEND_DEST = CORE_DEST
|
||||
FRONTEND_FORMATS = {
|
||||
'methods': """\
|
||||
"methods": """\
|
||||
def {name}(self, {args}{async_comma}{async_args}):
|
||||
{error_handler}{blocking_call}{debug}return {result}\n""",
|
||||
}
|
||||
{error_handler}{blocking_call}{debug}return {result}\n"""
|
||||
}
|
||||
|
||||
def core_completion_signal(self, completion, function, default, arg_doc, async_):
|
||||
completion['category'] = completion['category'].upper()
|
||||
completion['body'] = "pass" if not self.args.debug else 'log.debug ("{}")'.format(completion['name'])
|
||||
completion["category"] = completion["category"].upper()
|
||||
completion["body"] = (
|
||||
"pass"
|
||||
if not self.args.debug
|
||||
else 'log.debug ("{}")'.format(completion["name"])
|
||||
)
|
||||
|
||||
def core_completion_method(self, completion, function, default, arg_doc, async_):
|
||||
completion.update({
|
||||
'debug': "" if not self.args.debug else 'log.debug ("%s")\n%s' % (completion['name'], 8 * ' '),
|
||||
'args_result': self.getArguments(function['sig_in'], name=arg_doc, unicode_protect=self.args.unicode),
|
||||
'async_comma': ', ' if async_ and function['sig_in'] else '',
|
||||
'async_args_def': 'callback=None, errback=None' if async_ else '',
|
||||
'async_args_call': 'callback=callback, errback=errback' if async_ else '',
|
||||
'async_callbacks': "('callback', 'errback')" if async_ else "None",
|
||||
'category': completion['category'].upper(),
|
||||
})
|
||||
completion.update(
|
||||
{
|
||||
"debug": ""
|
||||
if not self.args.debug
|
||||
else 'log.debug ("%s")\n%s' % (completion["name"], 8 * " "),
|
||||
"args_result": self.getArguments(
|
||||
function["sig_in"], name=arg_doc, unicode_protect=self.args.unicode
|
||||
),
|
||||
"async_comma": ", " if async_ and function["sig_in"] else "",
|
||||
"async_args_def": "callback=None, errback=None" if async_ else "",
|
||||
"async_args_call": "callback=callback, errback=errback" if async_ else "",
|
||||
"async_callbacks": "('callback', 'errback')" if async_ else "None",
|
||||
"category": completion["category"].upper(),
|
||||
}
|
||||
)
|
||||
|
||||
def frontend_completion_method(self, completion, function, default, arg_doc, async_):
|
||||
completion.update({
|
||||
# XXX: we can manage blocking call in the same way as async one: if callback is None the call will be blocking
|
||||
'debug': "" if not self.args.debug else 'log.debug ("%s")\n%s' % (completion['name'], 8 * ' '),
|
||||
'args_result': self.getArguments(function['sig_in'], name=arg_doc),
|
||||
'async_args': 'callback=None, errback=None',
|
||||
'async_comma': ', ' if function['sig_in'] else '',
|
||||
'error_handler': """if callback is None:
|
||||
completion.update(
|
||||
{
|
||||
# XXX: we can manage blocking call in the same way as async one: if callback is None the call will be blocking
|
||||
"debug": ""
|
||||
if not self.args.debug
|
||||
else 'log.debug ("%s")\n%s' % (completion["name"], 8 * " "),
|
||||
"args_result": self.getArguments(function["sig_in"], name=arg_doc),
|
||||
"async_args": "callback=None, errback=None",
|
||||
"async_comma": ", " if function["sig_in"] else "",
|
||||
"error_handler": """if callback is None:
|
||||
error_handler = None
|
||||
else:
|
||||
if errback is None:
|
||||
errback = log.error
|
||||
error_handler = lambda err:errback(dbus_to_bridge_exception(err))
|
||||
""",
|
||||
})
|
||||
}
|
||||
)
|
||||
if async_:
|
||||
completion['blocking_call'] = ''
|
||||
completion['async_args_result'] = 'timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler'
|
||||
completion["blocking_call"] = ""
|
||||
completion[
|
||||
"async_args_result"
|
||||
] = "timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler"
|
||||
else:
|
||||
# XXX: To have a blocking call, we must have not reply_handler, so we test if callback exists, and add reply_handler only in this case
|
||||
completion['blocking_call'] = """kwargs={}
|
||||
completion[
|
||||
"blocking_call"
|
||||
] = """kwargs={}
|
||||
if callback is not None:
|
||||
kwargs['timeout'] = const_TIMEOUT
|
||||
kwargs['reply_handler'] = callback
|
||||
kwargs['error_handler'] = error_handler
|
||||
"""
|
||||
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.args.unicode and function['sig_out'] == 's' else "%s") % result
|
||||
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.args.unicode and function["sig_out"] == "s" else "%s"
|
||||
) % result
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SAT: a jabber client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -23,13 +23,14 @@ import dbus.service
|
|||
import dbus.mainloop.glib
|
||||
import inspect
|
||||
from sat.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
from twisted.internet.defer import Deferred
|
||||
from sat.core.exceptions import BridgeInitError
|
||||
|
||||
const_INT_PREFIX = "org.goffi.SAT" # Interface prefix
|
||||
const_ERROR_PREFIX = const_INT_PREFIX + ".error"
|
||||
const_OBJ_PATH = '/org/goffi/SAT/bridge'
|
||||
const_OBJ_PATH = "/org/goffi/SAT/bridge"
|
||||
const_CORE_SUFFIX = ".core"
|
||||
const_PLUGIN_SUFFIX = ".plugin"
|
||||
|
||||
|
|
@ -73,11 +74,12 @@ class GenericException(dbus.DBusException):
|
|||
self.args = (message, twisted_error.value.condition)
|
||||
except AttributeError:
|
||||
self.args = (message,)
|
||||
self._dbus_error_name = '.'.join([const_ERROR_PREFIX, class_.__module__, class_.__name__])
|
||||
self._dbus_error_name = ".".join(
|
||||
[const_ERROR_PREFIX, class_.__module__, class_.__name__]
|
||||
)
|
||||
|
||||
|
||||
class DbusObject(dbus.service.Object):
|
||||
|
||||
def __init__(self, bus, path):
|
||||
dbus.service.Object.__init__(self, bus, path)
|
||||
log.debug("Init DbusObject...")
|
||||
|
|
@ -93,7 +95,7 @@ class DbusObject(dbus.service.Object):
|
|||
raise MethodNotRegistered
|
||||
|
||||
if "callback" in kwargs:
|
||||
#we must have errback too
|
||||
# we must have errback too
|
||||
if not "errback" in kwargs:
|
||||
log.error("errback is missing in method call [%s]" % name)
|
||||
raise InternalError
|
||||
|
|
@ -107,27 +109,29 @@ class DbusObject(dbus.service.Object):
|
|||
if not isinstance(result, Deferred):
|
||||
log.error("Asynchronous method [%s] does not return a Deferred." % name)
|
||||
raise AsyncNotDeferred
|
||||
result.addCallback(lambda result: callback() if result is None else callback(result))
|
||||
result.addCallback(
|
||||
lambda result: callback() if result is None else callback(result)
|
||||
)
|
||||
result.addErrback(lambda err: errback(GenericException(err)))
|
||||
else:
|
||||
if isinstance(result, Deferred):
|
||||
log.error("Synchronous method [%s] return a Deferred." % name)
|
||||
raise DeferredNotAsync
|
||||
return result
|
||||
|
||||
### signals ###
|
||||
|
||||
@dbus.service.signal(const_INT_PREFIX + const_PLUGIN_SUFFIX,
|
||||
signature='')
|
||||
@dbus.service.signal(const_INT_PREFIX + const_PLUGIN_SUFFIX, signature="")
|
||||
def dummySignal(self):
|
||||
#FIXME: workaround for addSignal (doesn't work if one method doensn't
|
||||
# FIXME: workaround for addSignal (doesn't work if one method doensn't
|
||||
# already exist for plugins), probably missing some initialisation, need
|
||||
# further investigations
|
||||
pass
|
||||
|
||||
##SIGNALS_PART##
|
||||
##SIGNALS_PART##
|
||||
### methods ###
|
||||
|
||||
##METHODS_PART##
|
||||
##METHODS_PART##
|
||||
def __attributes(self, in_sign):
|
||||
"""Return arguments to user given a in_sign
|
||||
@param in_sign: in_sign in the short form (using s,a,i,b etc)
|
||||
|
|
@ -136,22 +140,24 @@ class DbusObject(dbus.service.Object):
|
|||
idx = 0
|
||||
attr = []
|
||||
while i < len(in_sign):
|
||||
if in_sign[i] not in ['b', 'y', 'n', 'i', 'x', 'q', 'u', 't', 'd', 's', 'a']:
|
||||
if in_sign[i] not in ["b", "y", "n", "i", "x", "q", "u", "t", "d", "s", "a"]:
|
||||
raise ParseError("Unmanaged attribute type [%c]" % in_sign[i])
|
||||
|
||||
attr.append("arg_%i" % idx)
|
||||
idx += 1
|
||||
|
||||
if in_sign[i] == 'a':
|
||||
if in_sign[i] == "a":
|
||||
i += 1
|
||||
if in_sign[i] != '{' and in_sign[i] != '(': # FIXME: must manage tuples out of arrays
|
||||
if (
|
||||
in_sign[i] != "{" and in_sign[i] != "("
|
||||
): # FIXME: must manage tuples out of arrays
|
||||
i += 1
|
||||
continue # we have a simple type for the array
|
||||
opening_car = in_sign[i]
|
||||
assert(opening_car in ['{', '('])
|
||||
closing_car = '}' if opening_car == '{' else ')'
|
||||
assert opening_car in ["{", "("]
|
||||
closing_car = "}" if opening_car == "{" else ")"
|
||||
opening_count = 1
|
||||
while (True): # we have a dict or a list of tuples
|
||||
while True: # we have a dict or a list of tuples
|
||||
i += 1
|
||||
if i >= len(in_sign):
|
||||
raise ParseError("missing }")
|
||||
|
|
@ -172,47 +178,80 @@ class DbusObject(dbus.service.Object):
|
|||
_defaults = list(inspect_args.defaults or [])
|
||||
|
||||
if inspect.ismethod(method):
|
||||
#if we have a method, we don't want the first argument (usually 'self')
|
||||
del(_arguments[0])
|
||||
# if we have a method, we don't want the first argument (usually 'self')
|
||||
del (_arguments[0])
|
||||
|
||||
#first arguments are for the _callback method
|
||||
arguments_callback = ', '.join([repr(name)] + ((_arguments + ['callback=callback', 'errback=errback']) if async else _arguments))
|
||||
# first arguments are for the _callback method
|
||||
arguments_callback = ", ".join(
|
||||
[repr(name)]
|
||||
+ (
|
||||
(_arguments + ["callback=callback", "errback=errback"])
|
||||
if async
|
||||
else _arguments
|
||||
)
|
||||
)
|
||||
|
||||
if async:
|
||||
_arguments.extend(['callback', 'errback'])
|
||||
_arguments.extend(["callback", "errback"])
|
||||
_defaults.extend([None, None])
|
||||
|
||||
#now we create a second list with default values
|
||||
# now we create a second list with default values
|
||||
for i in range(1, len(_defaults) + 1):
|
||||
_arguments[-i] = "%s = %s" % (_arguments[-i], repr(_defaults[-i]))
|
||||
|
||||
arguments_defaults = ', '.join(_arguments)
|
||||
arguments_defaults = ", ".join(_arguments)
|
||||
|
||||
code = compile('def %(name)s (self,%(arguments_defaults)s): return self._callback(%(arguments_callback)s)' %
|
||||
{'name': name, 'arguments_defaults': arguments_defaults, 'arguments_callback': arguments_callback}, '<DBus bridge>', 'exec')
|
||||
exec (code) # FIXME: to the same thing in a cleaner way, without compile/exec
|
||||
code = compile(
|
||||
"def %(name)s (self,%(arguments_defaults)s): return self._callback(%(arguments_callback)s)"
|
||||
% {
|
||||
"name": name,
|
||||
"arguments_defaults": arguments_defaults,
|
||||
"arguments_callback": arguments_callback,
|
||||
},
|
||||
"<DBus bridge>",
|
||||
"exec",
|
||||
)
|
||||
exec(code) # FIXME: to the same thing in a cleaner way, without compile/exec
|
||||
method = locals()[name]
|
||||
async_callbacks = ('callback', 'errback') if async else None
|
||||
setattr(DbusObject, name, dbus.service.method(
|
||||
const_INT_PREFIX + int_suffix, in_signature=in_sign, out_signature=out_sign,
|
||||
async_callbacks=async_callbacks)(method))
|
||||
async_callbacks = ("callback", "errback") if async else None
|
||||
setattr(
|
||||
DbusObject,
|
||||
name,
|
||||
dbus.service.method(
|
||||
const_INT_PREFIX + int_suffix,
|
||||
in_signature=in_sign,
|
||||
out_signature=out_sign,
|
||||
async_callbacks=async_callbacks,
|
||||
)(method),
|
||||
)
|
||||
function = getattr(self, name)
|
||||
func_table = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__][function._dbus_interface]
|
||||
func_table = self._dbus_class_table[
|
||||
self.__class__.__module__ + "." + self.__class__.__name__
|
||||
][function._dbus_interface]
|
||||
func_table[function.__name__] = function # Needed for introspection
|
||||
|
||||
def addSignal(self, name, int_suffix, signature, doc={}):
|
||||
"""Dynamically add a signal to Dbus Bridge"""
|
||||
attributes = ', '.join(self.__attributes(signature))
|
||||
#TODO: use doc parameter to name attributes
|
||||
attributes = ", ".join(self.__attributes(signature))
|
||||
# TODO: use doc parameter to name attributes
|
||||
|
||||
#code = compile ('def '+name+' (self,'+attributes+'): log.debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the log.debug is too annoying with xmllog
|
||||
code = compile('def ' + name + ' (self,' + attributes + '): pass', '<DBus bridge>', 'exec')
|
||||
exec (code)
|
||||
# code = compile ('def '+name+' (self,'+attributes+'): log.debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the log.debug is too annoying with xmllog
|
||||
code = compile(
|
||||
"def " + name + " (self," + attributes + "): pass", "<DBus bridge>", "exec"
|
||||
)
|
||||
exec(code)
|
||||
signal = locals()[name]
|
||||
setattr(DbusObject, name, dbus.service.signal(
|
||||
const_INT_PREFIX + int_suffix, signature=signature)(signal))
|
||||
setattr(
|
||||
DbusObject,
|
||||
name,
|
||||
dbus.service.signal(const_INT_PREFIX + int_suffix, signature=signature)(
|
||||
signal
|
||||
),
|
||||
)
|
||||
function = getattr(self, name)
|
||||
func_table = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__][function._dbus_interface]
|
||||
func_table = self._dbus_class_table[
|
||||
self.__class__.__module__ + "." + self.__class__.__name__
|
||||
][function._dbus_interface]
|
||||
func_table[function.__name__] = function # Needed for introspection
|
||||
|
||||
|
||||
|
|
@ -223,20 +262,24 @@ class Bridge(object):
|
|||
try:
|
||||
self.session_bus = dbus.SessionBus()
|
||||
except dbus.DBusException as e:
|
||||
if e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
|
||||
log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it"))
|
||||
if e._dbus_error_name == "org.freedesktop.DBus.Error.NotSupported":
|
||||
log.error(
|
||||
_(
|
||||
u"D-Bus is not launched, please see README to see instructions on how to launch it"
|
||||
)
|
||||
)
|
||||
raise BridgeInitError
|
||||
self.dbus_name = dbus.service.BusName(const_INT_PREFIX, self.session_bus)
|
||||
self.dbus_bridge = DbusObject(self.session_bus, const_OBJ_PATH)
|
||||
|
||||
##SIGNAL_DIRECT_CALLS_PART##
|
||||
##SIGNAL_DIRECT_CALLS_PART##
|
||||
def register_method(self, name, callback):
|
||||
log.debug("registering DBus bridge method [%s]" % name)
|
||||
self.dbus_bridge.register_method(name, callback)
|
||||
|
||||
def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
|
||||
"""Dynamically add a method to Dbus Bridge"""
|
||||
#FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
# FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
log.debug("Adding method [%s] to DBus bridge" % name)
|
||||
self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async)
|
||||
self.register_method(name, method)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -18,7 +18,8 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from sat.bridge.bridge_constructor import base_constructor
|
||||
# from textwraps import dedent
|
||||
|
||||
# from textwraps import dedent
|
||||
|
||||
|
||||
class EmbeddedConstructor(base_constructor.Constructor):
|
||||
|
|
@ -26,11 +27,11 @@ class EmbeddedConstructor(base_constructor.Constructor):
|
|||
CORE_TEMPLATE = "embedded_template.py"
|
||||
CORE_DEST = "embedded.py"
|
||||
CORE_FORMATS = {
|
||||
'methods': """\
|
||||
"methods": """\
|
||||
def {name}(self, {args}{args_comma}callback=None, errback=None):
|
||||
{ret_routine}
|
||||
""",
|
||||
'signals': """\
|
||||
"signals": """\
|
||||
def {name}(self, {args}):
|
||||
try:
|
||||
cb = self._signals_cbs["{category}"]["{name}"]
|
||||
|
|
@ -38,22 +39,30 @@ class EmbeddedConstructor(base_constructor.Constructor):
|
|||
log.warning(u"ignoring signal {name}: no callback registered")
|
||||
else:
|
||||
cb({args_result})
|
||||
"""
|
||||
}
|
||||
""",
|
||||
}
|
||||
FRONTEND_TEMPLATE = "embedded_frontend_template.py"
|
||||
FRONTEND_DEST = CORE_DEST
|
||||
FRONTEND_FORMATS = {}
|
||||
|
||||
def core_completion_method(self, completion, function, default, arg_doc, async_):
|
||||
completion.update({
|
||||
'debug': "" if not self.args.debug else 'log.debug ("%s")\n%s' % (completion['name'], 8 * ' '),
|
||||
'args_result': self.getArguments(function['sig_in'], name=arg_doc),
|
||||
'args_comma': ', ' if function['sig_in'] else '',
|
||||
})
|
||||
completion.update(
|
||||
{
|
||||
"debug": ""
|
||||
if not self.args.debug
|
||||
else 'log.debug ("%s")\n%s' % (completion["name"], 8 * " "),
|
||||
"args_result": self.getArguments(function["sig_in"], name=arg_doc),
|
||||
"args_comma": ", " if function["sig_in"] else "",
|
||||
}
|
||||
)
|
||||
|
||||
if async_:
|
||||
completion["cb_or_lambda"] = "callback" if function['sig_out'] else "lambda dummy: callback()"
|
||||
completion["ret_routine"] = """\
|
||||
completion["cb_or_lambda"] = (
|
||||
"callback" if function["sig_out"] else "lambda dummy: callback()"
|
||||
)
|
||||
completion[
|
||||
"ret_routine"
|
||||
] = """\
|
||||
d = self._methods_cbs["{name}"]({args_result})
|
||||
if callback is not None:
|
||||
d.addCallback({cb_or_lambda})
|
||||
|
|
@ -62,10 +71,14 @@ class EmbeddedConstructor(base_constructor.Constructor):
|
|||
else:
|
||||
d.addErrback(errback)
|
||||
return d
|
||||
""".format(**completion)
|
||||
""".format(
|
||||
**completion
|
||||
)
|
||||
else:
|
||||
completion['ret_or_nothing'] = 'ret' if function['sig_out'] else ''
|
||||
completion["ret_routine"] = """\
|
||||
completion["ret_or_nothing"] = "ret" if function["sig_out"] else ""
|
||||
completion[
|
||||
"ret_routine"
|
||||
] = """\
|
||||
try:
|
||||
ret = self._methods_cbs["{name}"]({args_result})
|
||||
except Exception as e:
|
||||
|
|
@ -77,9 +90,11 @@ class EmbeddedConstructor(base_constructor.Constructor):
|
|||
if callback is None:
|
||||
return ret
|
||||
else:
|
||||
callback({ret_or_nothing})""".format(**completion)
|
||||
callback({ret_or_nothing})""".format(
|
||||
**completion
|
||||
)
|
||||
|
||||
def core_completion_signal(self, completion, function, default, arg_doc, async_):
|
||||
completion.update({
|
||||
'args_result': self.getArguments(function['sig_in'], name=arg_doc),
|
||||
})
|
||||
completion.update(
|
||||
{"args_result": self.getArguments(function["sig_in"], name=arg_doc)}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from sat.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
from sat.core import exceptions
|
||||
|
||||
|
|
@ -26,10 +27,7 @@ class _Bridge(object):
|
|||
def __init__(self):
|
||||
log.debug(u"Init embedded bridge...")
|
||||
self._methods_cbs = {}
|
||||
self._signals_cbs = {
|
||||
"core": {},
|
||||
"plugin": {}
|
||||
}
|
||||
self._signals_cbs = {"core": {}, "plugin": {}}
|
||||
|
||||
def bridgeConnect(self, callback, errback):
|
||||
callback()
|
||||
|
|
@ -43,7 +41,11 @@ class _Bridge(object):
|
|||
def register_signal(self, functionName, handler, iface="core"):
|
||||
iface_dict = self._signals_cbs[iface]
|
||||
if functionName in iface_dict:
|
||||
raise exceptions.ConflictError(u"signal {name} is already regitered for interface {iface}".format(name=functionName, iface=iface))
|
||||
raise exceptions.ConflictError(
|
||||
u"signal {name} is already regitered for interface {iface}".format(
|
||||
name=functionName, iface=iface
|
||||
)
|
||||
)
|
||||
iface_dict[functionName] = handler
|
||||
|
||||
def call_method(self, name, out_sign, async_, args, kwargs):
|
||||
|
|
@ -84,23 +86,36 @@ class _Bridge(object):
|
|||
cb(*args, **kwargs)
|
||||
|
||||
def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
|
||||
#FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
# FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
log.debug("Adding method [{}] to embedded bridge".format(name))
|
||||
self.register_method(name, method)
|
||||
setattr(self.__class__, name, lambda self_, *args, **kwargs: self.call_method(name, out_sign, async, args, kwargs))
|
||||
setattr(
|
||||
self.__class__,
|
||||
name,
|
||||
lambda self_, *args, **kwargs: self.call_method(
|
||||
name, out_sign, async, args, kwargs
|
||||
),
|
||||
)
|
||||
|
||||
def addSignal(self, name, int_suffix, signature, doc={}):
|
||||
setattr(self.__class__, name, lambda self_, *args, **kwargs: self.send_signal(name, args, kwargs))
|
||||
setattr(
|
||||
self.__class__,
|
||||
name,
|
||||
lambda self_, *args, **kwargs: self.send_signal(name, args, kwargs),
|
||||
)
|
||||
|
||||
## signals ##
|
||||
|
||||
|
||||
##SIGNALS_PART##
|
||||
## methods ##
|
||||
## methods ##
|
||||
|
||||
##METHODS_PART##
|
||||
|
||||
# we want the same instance for both core and frontend
|
||||
bridge = None
|
||||
|
||||
|
||||
def Bridge():
|
||||
global bridge
|
||||
if bridge is None:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -24,7 +24,6 @@ import re
|
|||
|
||||
|
||||
class MediawikiConstructor(base_constructor.Constructor):
|
||||
|
||||
def __init__(self, bridge_template, options):
|
||||
base_constructor.Constructor.__init__(self, bridge_template, options)
|
||||
self.core_template = "mediawiki_template.tpl"
|
||||
|
|
@ -35,10 +34,10 @@ class MediawikiConstructor(base_constructor.Constructor):
|
|||
|
||||
def anchor_link(match):
|
||||
link = match.group(1)
|
||||
#we add anchor_link for [method_name] syntax:
|
||||
# we add anchor_link for [method_name] syntax:
|
||||
if link in self.bridge_template.sections():
|
||||
return "[[#%s|%s]]" % (link, link)
|
||||
print ("WARNING: found an anchor link to an unknown method")
|
||||
print("WARNING: found an anchor link to an unknown method")
|
||||
return link
|
||||
|
||||
return re.sub(r"\[(\w+)\]", anchor_link, text)
|
||||
|
|
@ -51,12 +50,12 @@ class MediawikiConstructor(base_constructor.Constructor):
|
|||
arg_doc = self.getArgumentsDoc(name)
|
||||
arg_default = self.getDefault(name)
|
||||
args_str = self.getArguments(sig_in)
|
||||
args = args_str.split(', ') if args_str else [] # ugly but it works :)
|
||||
args = args_str.split(", ") if args_str else [] # ugly but it works :)
|
||||
wiki = []
|
||||
for i in range(len(args)):
|
||||
if i in arg_doc:
|
||||
name, doc = arg_doc[i]
|
||||
doc = '\n:'.join(doc.rstrip('\n').split('\n'))
|
||||
doc = "\n:".join(doc.rstrip("\n").split("\n"))
|
||||
wiki.append("; %s: %s" % (name, self._addTextDecorations(doc)))
|
||||
else:
|
||||
wiki.append("; arg_%d: " % i)
|
||||
|
|
@ -70,9 +69,13 @@ class MediawikiConstructor(base_constructor.Constructor):
|
|||
"""
|
||||
arg_doc = self.getArgumentsDoc(name)
|
||||
wiki = []
|
||||
if 'return' in arg_doc:
|
||||
wiki.append('\n|-\n! scope=row | return value\n|')
|
||||
wiki.append('<br />\n'.join(self._addTextDecorations(arg_doc['return']).rstrip('\n').split('\n')))
|
||||
if "return" in arg_doc:
|
||||
wiki.append("\n|-\n! scope=row | return value\n|")
|
||||
wiki.append(
|
||||
"<br />\n".join(
|
||||
self._addTextDecorations(arg_doc["return"]).rstrip("\n").split("\n")
|
||||
)
|
||||
)
|
||||
return "\n".join(wiki)
|
||||
|
||||
def generateCoreSide(self):
|
||||
|
|
@ -82,37 +85,49 @@ class MediawikiConstructor(base_constructor.Constructor):
|
|||
sections.sort()
|
||||
for section in sections:
|
||||
function = self.getValues(section)
|
||||
print ("Adding %s %s" % (section, function["type"]))
|
||||
print("Adding %s %s" % (section, function["type"]))
|
||||
async_msg = """<br />'''This method is asynchronous'''"""
|
||||
deprecated_msg = """<br />'''<font color="#FF0000">/!\ WARNING /!\ : This method is deprecated, please don't use it !</font>'''"""
|
||||
signature_signal = \
|
||||
"""\
|
||||
signature_signal = (
|
||||
"""\
|
||||
! scope=row | signature
|
||||
| %s
|
||||
|-\
|
||||
""" % function['sig_in']
|
||||
signature_method = \
|
||||
"""\
|
||||
"""
|
||||
% function["sig_in"]
|
||||
)
|
||||
signature_method = """\
|
||||
! scope=row | signature in
|
||||
| %s
|
||||
|-
|
||||
! scope=row | signature out
|
||||
| %s
|
||||
|-\
|
||||
""" % (function['sig_in'], function['sig_out'])
|
||||
""" % (
|
||||
function["sig_in"],
|
||||
function["sig_out"],
|
||||
)
|
||||
completion = {
|
||||
'signature': signature_signal if function['type'] == "signal" else signature_method,
|
||||
'sig_out': function['sig_out'] or '',
|
||||
'category': function['category'],
|
||||
'name': section,
|
||||
'doc': self.getDoc(section) or "FIXME: No description available",
|
||||
'async': async_msg if "async" in self.getFlags(section) else "",
|
||||
'deprecated': deprecated_msg if "deprecated" in self.getFlags(section) else "",
|
||||
'parameters': self._wikiParameter(section, function['sig_in']),
|
||||
'return': self._wikiReturn(section) if function['type'] == 'method' else ''}
|
||||
"signature": signature_signal
|
||||
if function["type"] == "signal"
|
||||
else signature_method,
|
||||
"sig_out": function["sig_out"] or "",
|
||||
"category": function["category"],
|
||||
"name": section,
|
||||
"doc": self.getDoc(section) or "FIXME: No description available",
|
||||
"async": async_msg if "async" in self.getFlags(section) else "",
|
||||
"deprecated": deprecated_msg
|
||||
if "deprecated" in self.getFlags(section)
|
||||
else "",
|
||||
"parameters": self._wikiParameter(section, function["sig_in"]),
|
||||
"return": self._wikiReturn(section)
|
||||
if function["type"] == "method"
|
||||
else "",
|
||||
}
|
||||
|
||||
dest = signals_part if function['type'] == "signal" else methods_part
|
||||
dest.append("""\
|
||||
dest = signals_part if function["type"] == "signal" else methods_part
|
||||
dest.append(
|
||||
"""\
|
||||
== %(name)s ==
|
||||
''%(doc)s''
|
||||
%(deprecated)s
|
||||
|
|
@ -126,28 +141,28 @@ class MediawikiConstructor(base_constructor.Constructor):
|
|||
|
|
||||
%(parameters)s%(return)s
|
||||
|}
|
||||
""" % completion)
|
||||
"""
|
||||
% completion
|
||||
)
|
||||
|
||||
#at this point, signals_part, and methods_part should be filled,
|
||||
#we just have to place them in the right part of the template
|
||||
# at this point, signals_part, and methods_part should be filled,
|
||||
# we just have to place them in the right part of the template
|
||||
core_bridge = []
|
||||
template_path = self.getTemplatePath(self.core_template)
|
||||
try:
|
||||
with open(template_path) as core_template:
|
||||
for line in core_template:
|
||||
if line.startswith('##SIGNALS_PART##'):
|
||||
if line.startswith("##SIGNALS_PART##"):
|
||||
core_bridge.extend(signals_part)
|
||||
elif line.startswith('##METHODS_PART##'):
|
||||
elif line.startswith("##METHODS_PART##"):
|
||||
core_bridge.extend(methods_part)
|
||||
elif line.startswith('##TIMESTAMP##'):
|
||||
core_bridge.append('Generated on %s' % datetime.now())
|
||||
elif line.startswith("##TIMESTAMP##"):
|
||||
core_bridge.append("Generated on %s" % datetime.now())
|
||||
else:
|
||||
core_bridge.append(line.replace('\n', ''))
|
||||
core_bridge.append(line.replace("\n", ""))
|
||||
except IOError:
|
||||
print ("Can't open template file [%s]" % template_path)
|
||||
print("Can't open template file [%s]" % template_path)
|
||||
sys.exit(1)
|
||||
|
||||
#now we write to final file
|
||||
# now we write to final file
|
||||
self.finalWrite(self.core_dest, core_bridge)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SàT: a XMPP client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -25,32 +25,42 @@ class pbConstructor(base_constructor.Constructor):
|
|||
CORE_TEMPLATE = "pb_core_template.py"
|
||||
CORE_DEST = "pb.py"
|
||||
CORE_FORMATS = {
|
||||
'signals': """\
|
||||
"signals": """\
|
||||
def {name}(self, {args}):
|
||||
{debug}self.sendSignal("{name}", {args_no_def})\n""",
|
||||
}
|
||||
{debug}self.sendSignal("{name}", {args_no_def})\n"""
|
||||
}
|
||||
|
||||
FRONTEND_TEMPLATE = "pb_frontend_template.py"
|
||||
FRONTEND_DEST = CORE_DEST
|
||||
FRONTEND_FORMATS = {
|
||||
'methods': """\
|
||||
"methods": """\
|
||||
def {name}(self{args_comma}{args}, callback=None, errback=None):
|
||||
{debug}d = self.root.callRemote("{name}"{args_comma}{args_no_def})
|
||||
if callback is not None:
|
||||
d.addCallback({callback})
|
||||
if errback is None:
|
||||
errback = self._generic_errback
|
||||
d.addErrback(errback)\n""",
|
||||
}
|
||||
d.addErrback(errback)\n"""
|
||||
}
|
||||
|
||||
def core_completion_signal(self, completion, function, default, arg_doc, async_):
|
||||
completion['args_no_def'] = self.getArguments(function['sig_in'], name=arg_doc)
|
||||
completion['debug'] = "" if not self.args.debug else 'log.debug ("%s")\n%s' % (completion['name'], 8 * ' ')
|
||||
completion["args_no_def"] = self.getArguments(function["sig_in"], name=arg_doc)
|
||||
completion["debug"] = (
|
||||
""
|
||||
if not self.args.debug
|
||||
else 'log.debug ("%s")\n%s' % (completion["name"], 8 * " ")
|
||||
)
|
||||
|
||||
def frontend_completion_method(self, completion, function, default, arg_doc, async_):
|
||||
completion.update({
|
||||
'args_comma': ', ' if function['sig_in'] else '',
|
||||
'args_no_def': self.getArguments(function['sig_in'], name=arg_doc),
|
||||
'callback': 'callback' if function['sig_out'] else 'lambda dummy: callback()',
|
||||
'debug': "" if not self.args.debug else 'log.debug ("%s")\n%s' % (completion['name'], 8 * ' '),
|
||||
})
|
||||
completion.update(
|
||||
{
|
||||
"args_comma": ", " if function["sig_in"] else "",
|
||||
"args_no_def": self.getArguments(function["sig_in"], name=arg_doc),
|
||||
"callback": "callback"
|
||||
if function["sig_out"]
|
||||
else "lambda dummy: callback()",
|
||||
"debug": ""
|
||||
if not self.args.debug
|
||||
else 'log.debug ("%s")\n%s' % (completion["name"], 8 * " "),
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SAT: a jabber client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
|
||||
from sat.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
from twisted.spread import jelly, pb
|
||||
from twisted.internet import reactor
|
||||
|
|
@ -28,17 +29,18 @@ from twisted.internet import reactor
|
|||
# we monkey patch jelly to handle namedtuple
|
||||
ori_jelly = jelly._Jellier.jelly
|
||||
|
||||
|
||||
def fixed_jelly(self, obj):
|
||||
"""this method fix handling of namedtuple"""
|
||||
if isinstance(obj, tuple) and not obj is tuple:
|
||||
obj = tuple(obj)
|
||||
return ori_jelly(self, obj)
|
||||
|
||||
|
||||
jelly._Jellier.jelly = fixed_jelly
|
||||
|
||||
|
||||
class PBRoot(pb.Root):
|
||||
|
||||
def __init__(self):
|
||||
self.signals_handlers = []
|
||||
|
||||
|
|
@ -47,10 +49,11 @@ class PBRoot(pb.Root):
|
|||
log.info(u"registered signal handler")
|
||||
|
||||
def sendSignalEb(self, failure, signal_name):
|
||||
log.error(u"Error while sending signal {name}: {msg}".format(
|
||||
name = signal_name,
|
||||
msg = failure,
|
||||
))
|
||||
log.error(
|
||||
u"Error while sending signal {name}: {msg}".format(
|
||||
name=signal_name, msg=failure
|
||||
)
|
||||
)
|
||||
|
||||
def sendSignal(self, name, args, kwargs):
|
||||
to_remove = []
|
||||
|
|
@ -66,11 +69,11 @@ class PBRoot(pb.Root):
|
|||
log.debug(u"Removing signal handler for dead frontend")
|
||||
self.signals_handlers.remove(handler)
|
||||
|
||||
|
||||
##METHODS_PART##
|
||||
|
||||
|
||||
class Bridge(object):
|
||||
|
||||
def __init__(self):
|
||||
log.info("Init Perspective Broker...")
|
||||
self.root = PBRoot()
|
||||
|
|
@ -85,17 +88,20 @@ class Bridge(object):
|
|||
|
||||
def register_method(self, name, callback):
|
||||
log.debug("registering PB bridge method [%s]" % name)
|
||||
setattr(self.root, "remote_"+name, callback)
|
||||
# self.root.register_method(name, callback)
|
||||
setattr(self.root, "remote_" + name, callback)
|
||||
# self.root.register_method(name, callback)
|
||||
|
||||
def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
|
||||
"""Dynamically add a method to PB Bridge"""
|
||||
#FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
# FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
log.debug("Adding method {name} to PB bridge".format(name=name))
|
||||
self.register_method(name, method)
|
||||
|
||||
def addSignal(self, name, int_suffix, signature, doc={}):
|
||||
log.debug("Adding signal {name} to PB bridge".format(name=name))
|
||||
setattr(self, name, lambda *args, **kwargs: self.sendSignal(name, *args, **kwargs))
|
||||
setattr(
|
||||
self, name, lambda *args, **kwargs: self.sendSignal(name, *args, **kwargs)
|
||||
)
|
||||
|
||||
|
||||
##SIGNALS_PART##
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SAT communication bridge
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from sat.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
from sat.core import exceptions
|
||||
from twisted.spread import pb
|
||||
|
|
@ -25,11 +26,9 @@ from twisted.internet import reactor
|
|||
|
||||
|
||||
class SignalsHandler(pb.Referenceable):
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith("remote_"):
|
||||
log.debug(u"calling an unregistered signal: {name}".format(
|
||||
name = name[7:]))
|
||||
log.debug(u"calling an unregistered signal: {name}".format(name=name[7:]))
|
||||
return lambda *args, **kwargs: None
|
||||
|
||||
else:
|
||||
|
|
@ -43,13 +42,15 @@ class SignalsHandler(pb.Referenceable):
|
|||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
raise exceptions.InternalError(u"{name} signal handler has been registered twice".format(
|
||||
name = method_name))
|
||||
raise exceptions.InternalError(
|
||||
u"{name} signal handler has been registered twice".format(
|
||||
name=method_name
|
||||
)
|
||||
)
|
||||
setattr(self, method_name, handler)
|
||||
|
||||
|
||||
class Bridge(object):
|
||||
|
||||
def __init__(self):
|
||||
self.signals_handler = SignalsHandler()
|
||||
|
||||
|
|
@ -81,11 +82,11 @@ class Bridge(object):
|
|||
callback = errback = None
|
||||
if kwargs:
|
||||
try:
|
||||
callback = kwargs.pop('callback')
|
||||
callback = kwargs.pop("callback")
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
errback = kwargs.pop('errback')
|
||||
errback = kwargs.pop("errback")
|
||||
except KeyError:
|
||||
pass
|
||||
elif len(args) >= 2 and callable(args[-1]) and callable(args[-2]):
|
||||
|
|
@ -124,4 +125,5 @@ class Bridge(object):
|
|||
def register_signal(self, functionName, handler, iface="core"):
|
||||
self.signals_handler.register_signal(functionName, handler, iface)
|
||||
|
||||
|
||||
##METHODS_PART##
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
#-*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SAT: a jabber client
|
||||
# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
|
||||
from sat.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
from twisted.spread import jelly, pb
|
||||
from twisted.internet import reactor
|
||||
|
|
@ -28,17 +29,18 @@ from twisted.internet import reactor
|
|||
# we monkey patch jelly to handle namedtuple
|
||||
ori_jelly = jelly._Jellier.jelly
|
||||
|
||||
|
||||
def fixed_jelly(self, obj):
|
||||
"""this method fix handling of namedtuple"""
|
||||
if isinstance(obj, tuple) and not obj is tuple:
|
||||
obj = tuple(obj)
|
||||
return ori_jelly(self, obj)
|
||||
|
||||
|
||||
jelly._Jellier.jelly = fixed_jelly
|
||||
|
||||
|
||||
class PBRoot(pb.Root):
|
||||
|
||||
def __init__(self):
|
||||
self.signals_handlers = []
|
||||
|
||||
|
|
@ -47,10 +49,11 @@ class PBRoot(pb.Root):
|
|||
log.info(u"registered signal handler")
|
||||
|
||||
def sendSignalEb(self, failure, signal_name):
|
||||
log.error(u"Error while sending signal {name}: {msg}".format(
|
||||
name = signal_name,
|
||||
msg = failure,
|
||||
))
|
||||
log.error(
|
||||
u"Error while sending signal {name}: {msg}".format(
|
||||
name=signal_name, msg=failure
|
||||
)
|
||||
)
|
||||
|
||||
def sendSignal(self, name, args, kwargs):
|
||||
to_remove = []
|
||||
|
|
@ -66,11 +69,11 @@ class PBRoot(pb.Root):
|
|||
log.debug(u"Removing signal handler for dead frontend")
|
||||
self.signals_handlers.remove(handler)
|
||||
|
||||
|
||||
##METHODS_PART##
|
||||
|
||||
|
||||
class Bridge(object):
|
||||
|
||||
def __init__(self):
|
||||
log.info("Init Perspective Broker...")
|
||||
self.root = PBRoot()
|
||||
|
|
@ -85,18 +88,20 @@ class Bridge(object):
|
|||
|
||||
def register_method(self, name, callback):
|
||||
log.debug("registering PB bridge method [%s]" % name)
|
||||
setattr(self.root, "remote_"+name, callback)
|
||||
# self.root.register_method(name, callback)
|
||||
setattr(self.root, "remote_" + name, callback)
|
||||
# self.root.register_method(name, callback)
|
||||
|
||||
def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
|
||||
"""Dynamically add a method to PB Bridge"""
|
||||
#FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
# FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
||||
log.debug("Adding method {name} to PB bridge".format(name=name))
|
||||
self.register_method(name, method)
|
||||
|
||||
def addSignal(self, name, int_suffix, signature, doc={}):
|
||||
log.debug("Adding signal {name} to PB bridge".format(name=name))
|
||||
setattr(self, name, lambda *args, **kwargs: self.sendSignal(name, *args, **kwargs))
|
||||
setattr(
|
||||
self, name, lambda *args, **kwargs: self.sendSignal(name, *args, **kwargs)
|
||||
)
|
||||
|
||||
def actionNew(self, action_data, id, security_limit, profile):
|
||||
self.sendSignal("actionNew", action_data, id, security_limit, profile)
|
||||
|
|
@ -113,8 +118,30 @@ class Bridge(object):
|
|||
def entityDataUpdated(self, jid, name, value, profile):
|
||||
self.sendSignal("entityDataUpdated", jid, name, value, profile)
|
||||
|
||||
def messageNew(self, uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile):
|
||||
self.sendSignal("messageNew", uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile)
|
||||
def messageNew(
|
||||
self,
|
||||
uid,
|
||||
timestamp,
|
||||
from_jid,
|
||||
to_jid,
|
||||
message,
|
||||
subject,
|
||||
mess_type,
|
||||
extra,
|
||||
profile,
|
||||
):
|
||||
self.sendSignal(
|
||||
"messageNew",
|
||||
uid,
|
||||
timestamp,
|
||||
from_jid,
|
||||
to_jid,
|
||||
message,
|
||||
subject,
|
||||
mess_type,
|
||||
extra,
|
||||
profile,
|
||||
)
|
||||
|
||||
def newContact(self, contact_jid, attributes, groups, profile):
|
||||
self.sendSignal("newContact", contact_jid, attributes, groups, profile)
|
||||
|
|
|
|||
|
|
@ -28,23 +28,24 @@ import sat
|
|||
class Const(object):
|
||||
|
||||
## Application ##
|
||||
APP_NAME = u'Salut à Toi'
|
||||
APP_NAME_SHORT = u'SàT'
|
||||
APP_NAME_FILE = u'sat'
|
||||
APP_NAME_FULL = u'{name_short} ({name})'.format(name_short=APP_NAME_SHORT,
|
||||
name=APP_NAME)
|
||||
APP_VERSION = sat.__version__ # Please add 'D' at the end of version in sat/VERSION for dev versions
|
||||
APP_RELEASE_NAME = u'La Commune'
|
||||
APP_URL = u'https://salut-a-toi.org'
|
||||
|
||||
APP_NAME = u"Salut à Toi"
|
||||
APP_NAME_SHORT = u"SàT"
|
||||
APP_NAME_FILE = u"sat"
|
||||
APP_NAME_FULL = u"{name_short} ({name})".format(
|
||||
name_short=APP_NAME_SHORT, name=APP_NAME
|
||||
)
|
||||
APP_VERSION = (
|
||||
sat.__version__
|
||||
) # Please add 'D' at the end of version in sat/VERSION for dev versions
|
||||
APP_RELEASE_NAME = u"La Commune"
|
||||
APP_URL = u"https://salut-a-toi.org"
|
||||
|
||||
## Runtime ##
|
||||
PLUGIN_EXT = "py"
|
||||
HISTORY_SKIP = u'skip'
|
||||
HISTORY_SKIP = u"skip"
|
||||
|
||||
## Main config ##
|
||||
DEFAULT_BRIDGE = 'dbus'
|
||||
|
||||
DEFAULT_BRIDGE = "dbus"
|
||||
|
||||
## Protocol ##
|
||||
XMPP_C2S_PORT = 5222
|
||||
|
|
@ -53,9 +54,8 @@ class Const(object):
|
|||
# default port used on Prosody, may differ on other servers
|
||||
XMPP_COMPONENT_PORT = 5347
|
||||
|
||||
|
||||
## Parameters ##
|
||||
NO_SECURITY_LIMIT = -1 # FIXME: to rename
|
||||
NO_SECURITY_LIMIT = -1 # FIXME: to rename
|
||||
SECURITY_LIMIT_MAX = 0
|
||||
INDIVIDUAL = "individual"
|
||||
GENERAL = "general"
|
||||
|
|
@ -67,9 +67,9 @@ class Const(object):
|
|||
FORCE_SERVER_PARAM = "Force server"
|
||||
FORCE_PORT_PARAM = "Force port"
|
||||
# Parameters related to encryption
|
||||
PROFILE_PASS_PATH = ('General', 'Password')
|
||||
MEMORY_CRYPTO_NAMESPACE = 'crypto' # for the private persistent binary dict
|
||||
MEMORY_CRYPTO_KEY = 'personal_key'
|
||||
PROFILE_PASS_PATH = ("General", "Password")
|
||||
MEMORY_CRYPTO_NAMESPACE = "crypto" # for the private persistent binary dict
|
||||
MEMORY_CRYPTO_KEY = "personal_key"
|
||||
# Parameters for static blog pages
|
||||
# FIXME: blog constants should not be in core constants
|
||||
STATIC_BLOG_KEY = "Blog page"
|
||||
|
|
@ -78,7 +78,6 @@ class Const(object):
|
|||
STATIC_BLOG_PARAM_KEYWORDS = "Keywords"
|
||||
STATIC_BLOG_PARAM_DESCRIPTION = "Description"
|
||||
|
||||
|
||||
## Menus ##
|
||||
MENU_GLOBAL = "GLOBAL"
|
||||
MENU_ROOM = "ROOM"
|
||||
|
|
@ -88,62 +87,64 @@ class Const(object):
|
|||
MENU_ROSTER_GROUP_CONTEXT = "MENU_ROSTER_GROUP_CONTEXT"
|
||||
MENU_ROOM_OCCUPANT_CONTEXT = "MENU_ROOM_OCCUPANT_CONTEXT"
|
||||
|
||||
|
||||
## Profile and entities ##
|
||||
PROF_KEY_NONE = '@NONE@'
|
||||
PROF_KEY_DEFAULT = '@DEFAULT@'
|
||||
PROF_KEY_ALL = '@ALL@'
|
||||
ENTITY_ALL = '@ALL@'
|
||||
ENTITY_ALL_RESOURCES = '@ALL_RESOURCES@'
|
||||
ENTITY_MAIN_RESOURCE = '@MAIN_RESOURCE@'
|
||||
ENTITY_CAP_HASH = 'CAP_HASH'
|
||||
ENTITY_TYPE = 'TYPE'
|
||||
|
||||
PROF_KEY_NONE = "@NONE@"
|
||||
PROF_KEY_DEFAULT = "@DEFAULT@"
|
||||
PROF_KEY_ALL = "@ALL@"
|
||||
ENTITY_ALL = "@ALL@"
|
||||
ENTITY_ALL_RESOURCES = "@ALL_RESOURCES@"
|
||||
ENTITY_MAIN_RESOURCE = "@MAIN_RESOURCE@"
|
||||
ENTITY_CAP_HASH = "CAP_HASH"
|
||||
ENTITY_TYPE = "TYPE"
|
||||
|
||||
## Roster jids selection ##
|
||||
PUBLIC = 'PUBLIC'
|
||||
ALL = 'ALL' # ALL means all known contacts, while PUBLIC means everybody, known or not
|
||||
GROUP = 'GROUP'
|
||||
JID = 'JID'
|
||||
|
||||
PUBLIC = "PUBLIC"
|
||||
ALL = (
|
||||
"ALL"
|
||||
) # ALL means all known contacts, while PUBLIC means everybody, known or not
|
||||
GROUP = "GROUP"
|
||||
JID = "JID"
|
||||
|
||||
## Messages ##
|
||||
MESS_TYPE_INFO = 'info'
|
||||
MESS_TYPE_CHAT = 'chat'
|
||||
MESS_TYPE_ERROR = 'error'
|
||||
MESS_TYPE_GROUPCHAT = 'groupchat'
|
||||
MESS_TYPE_HEADLINE = 'headline'
|
||||
MESS_TYPE_NORMAL = 'normal'
|
||||
MESS_TYPE_AUTO = 'auto' # magic value to let the backend guess the type
|
||||
MESS_TYPE_STANDARD = (MESS_TYPE_CHAT, MESS_TYPE_ERROR, MESS_TYPE_GROUPCHAT, MESS_TYPE_HEADLINE, MESS_TYPE_NORMAL)
|
||||
MESS_TYPE_INFO = "info"
|
||||
MESS_TYPE_CHAT = "chat"
|
||||
MESS_TYPE_ERROR = "error"
|
||||
MESS_TYPE_GROUPCHAT = "groupchat"
|
||||
MESS_TYPE_HEADLINE = "headline"
|
||||
MESS_TYPE_NORMAL = "normal"
|
||||
MESS_TYPE_AUTO = "auto" # magic value to let the backend guess the type
|
||||
MESS_TYPE_STANDARD = (
|
||||
MESS_TYPE_CHAT,
|
||||
MESS_TYPE_ERROR,
|
||||
MESS_TYPE_GROUPCHAT,
|
||||
MESS_TYPE_HEADLINE,
|
||||
MESS_TYPE_NORMAL,
|
||||
)
|
||||
MESS_TYPE_ALL = MESS_TYPE_STANDARD + (MESS_TYPE_INFO, MESS_TYPE_AUTO)
|
||||
|
||||
MESS_EXTRA_INFO = "info_type"
|
||||
|
||||
|
||||
## Chat ##
|
||||
CHAT_ONE2ONE = 'one2one'
|
||||
CHAT_GROUP = 'group'
|
||||
|
||||
CHAT_ONE2ONE = "one2one"
|
||||
CHAT_GROUP = "group"
|
||||
|
||||
## Presence ##
|
||||
PRESENCE_UNAVAILABLE = 'unavailable'
|
||||
PRESENCE_SHOW_AWAY = 'away'
|
||||
PRESENCE_SHOW_CHAT = 'chat'
|
||||
PRESENCE_SHOW_DND = 'dnd'
|
||||
PRESENCE_SHOW_XA = 'xa'
|
||||
PRESENCE_SHOW = 'show'
|
||||
PRESENCE_STATUSES = 'statuses'
|
||||
PRESENCE_STATUSES_DEFAULT = 'default'
|
||||
PRESENCE_PRIORITY = 'priority'
|
||||
|
||||
PRESENCE_UNAVAILABLE = "unavailable"
|
||||
PRESENCE_SHOW_AWAY = "away"
|
||||
PRESENCE_SHOW_CHAT = "chat"
|
||||
PRESENCE_SHOW_DND = "dnd"
|
||||
PRESENCE_SHOW_XA = "xa"
|
||||
PRESENCE_SHOW = "show"
|
||||
PRESENCE_STATUSES = "statuses"
|
||||
PRESENCE_STATUSES_DEFAULT = "default"
|
||||
PRESENCE_PRIORITY = "priority"
|
||||
|
||||
## Common namespaces ##
|
||||
NS_XML = 'http://www.w3.org/XML/1998/namespace'
|
||||
NS_CLIENT = 'jabber:client'
|
||||
NS_FORWARD = 'urn:xmpp:forward:0'
|
||||
NS_DELAY = 'urn:xmpp:delay'
|
||||
NS_XHTML = 'http://www.w3.org/1999/xhtml'
|
||||
NS_XML = "http://www.w3.org/XML/1998/namespace"
|
||||
NS_CLIENT = "jabber:client"
|
||||
NS_FORWARD = "urn:xmpp:forward:0"
|
||||
NS_DELAY = "urn:xmpp:delay"
|
||||
NS_XHTML = "http://www.w3.org/1999/xhtml"
|
||||
|
||||
## Common XPath ##
|
||||
|
||||
|
|
@ -153,23 +154,24 @@ class Const(object):
|
|||
## Directories ##
|
||||
|
||||
# directory for components specific data
|
||||
COMPONENTS_DIR = u'components'
|
||||
CACHE_DIR = u'cache'
|
||||
COMPONENTS_DIR = u"components"
|
||||
CACHE_DIR = u"cache"
|
||||
# files in file dir are stored for long term
|
||||
# files dir is global, i.e. for all profiles
|
||||
FILES_DIR = u'files'
|
||||
FILES_DIR = u"files"
|
||||
# FILES_LINKS_DIR is a directory where files owned by a specific profile
|
||||
# are linked to the global files directory. This way the directory can be
|
||||
# shared per profiles while keeping global directory where identical files
|
||||
# shared per profiles while keeping global directory where identical files
|
||||
# shared between different profiles are not duplicated.
|
||||
FILES_LINKS_DIR = u'files_links'
|
||||
FILES_LINKS_DIR = u"files_links"
|
||||
# FILES_TMP_DIR is where profile's partially transfered files are put.
|
||||
# Once transfer is completed, they are moved to FILES_DIR
|
||||
FILES_TMP_DIR = u'files_tmp'
|
||||
|
||||
FILES_TMP_DIR = u"files_tmp"
|
||||
|
||||
## Configuration ##
|
||||
if BaseDirectory: # skipped when xdg module is not available (should not happen in backend)
|
||||
if (
|
||||
BaseDirectory
|
||||
): # skipped when xdg module is not available (should not happen in backend)
|
||||
if "org.goffi.cagou.cagou" in BaseDirectory.__file__:
|
||||
# FIXME: hack to make config read from the right location on Android
|
||||
# TODO: fix it in a more proper way
|
||||
|
|
@ -177,56 +179,71 @@ class Const(object):
|
|||
# we need to use Android API to get downloads directory
|
||||
import os.path
|
||||
from jnius import autoclass
|
||||
|
||||
Environment = autoclass("android.os.Environment")
|
||||
|
||||
BaseDirectory = None
|
||||
DEFAULT_CONFIG = {
|
||||
'local_dir': '/data/data/org.goffi.cagou.cagou/app',
|
||||
'media_dir': '/data/data/org.goffi.cagou.cagou/files/app/media',
|
||||
"local_dir": "/data/data/org.goffi.cagou.cagou/app",
|
||||
"media_dir": "/data/data/org.goffi.cagou.cagou/files/app/media",
|
||||
# FIXME: temporary location for downloads, need to call API properly
|
||||
'downloads_dir': os.path.join(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(), APP_NAME_FILE),
|
||||
'pid_dir': '%(local_dir)s',
|
||||
'log_dir': '%(local_dir)s',
|
||||
"downloads_dir": os.path.join(
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS
|
||||
).getAbsolutePath(),
|
||||
APP_NAME_FILE,
|
||||
),
|
||||
"pid_dir": "%(local_dir)s",
|
||||
"log_dir": "%(local_dir)s",
|
||||
}
|
||||
CONFIG_FILES = ['/data/data/org.goffi.cagou.cagou/files/app/android/' + APP_NAME_FILE + '.conf']
|
||||
CONFIG_FILES = [
|
||||
"/data/data/org.goffi.cagou.cagou/files/app/android/"
|
||||
+ APP_NAME_FILE
|
||||
+ ".conf"
|
||||
]
|
||||
else:
|
||||
|
||||
## Configuration ##
|
||||
DEFAULT_CONFIG = {
|
||||
'media_dir': '/usr/share/' + APP_NAME_FILE + '/media',
|
||||
'local_dir': BaseDirectory.save_data_path(APP_NAME_FILE),
|
||||
'downloads_dir': '~/Downloads/' + APP_NAME_FILE,
|
||||
'pid_dir': '%(local_dir)s',
|
||||
'log_dir': '%(local_dir)s',
|
||||
"media_dir": "/usr/share/" + APP_NAME_FILE + "/media",
|
||||
"local_dir": BaseDirectory.save_data_path(APP_NAME_FILE),
|
||||
"downloads_dir": "~/Downloads/" + APP_NAME_FILE,
|
||||
"pid_dir": "%(local_dir)s",
|
||||
"log_dir": "%(local_dir)s",
|
||||
}
|
||||
|
||||
# List of the configuration filenames sorted by ascending priority
|
||||
CONFIG_FILES = [realpath(expanduser(path) + APP_NAME_FILE + '.conf') for path in
|
||||
['/etc/', '~/', '~/.', '', '.'] +
|
||||
['%s/' % path for path in list(BaseDirectory.load_config_paths(APP_NAME_FILE))]
|
||||
]
|
||||
CONFIG_FILES = [
|
||||
realpath(expanduser(path) + APP_NAME_FILE + ".conf")
|
||||
for path in ["/etc/", "~/", "~/.", "", "."]
|
||||
+ [
|
||||
"%s/" % path
|
||||
for path in list(BaseDirectory.load_config_paths(APP_NAME_FILE))
|
||||
]
|
||||
]
|
||||
|
||||
## Templates ##
|
||||
TEMPLATE_THEME_DEFAULT = u'default'
|
||||
TEMPLATE_STATIC_DIR = u'static'
|
||||
|
||||
TEMPLATE_THEME_DEFAULT = u"default"
|
||||
TEMPLATE_STATIC_DIR = u"static"
|
||||
|
||||
## Plugins ##
|
||||
|
||||
# PLUGIN_INFO keys
|
||||
# XXX: we use PI instead of PLUG_INFO which would normally be used
|
||||
# to make the header more readable
|
||||
PI_NAME = u'name'
|
||||
PI_IMPORT_NAME = u'import_name'
|
||||
PI_MAIN = u'main'
|
||||
PI_HANDLER = u'handler'
|
||||
PI_TYPE = u'type' # FIXME: should be types, and should handle single unicode type or tuple of types (e.g. "blog" and "import")
|
||||
PI_MODES = u'modes'
|
||||
PI_PROTOCOLS = u'protocols'
|
||||
PI_DEPENDENCIES = u'dependencies'
|
||||
PI_RECOMMENDATIONS = u'recommendations'
|
||||
PI_DESCRIPTION = u'description'
|
||||
PI_USAGE = u'usage'
|
||||
PI_NAME = u"name"
|
||||
PI_IMPORT_NAME = u"import_name"
|
||||
PI_MAIN = u"main"
|
||||
PI_HANDLER = u"handler"
|
||||
PI_TYPE = (
|
||||
u"type"
|
||||
) # FIXME: should be types, and should handle single unicode type or tuple of types (e.g. "blog" and "import")
|
||||
PI_MODES = u"modes"
|
||||
PI_PROTOCOLS = u"protocols"
|
||||
PI_DEPENDENCIES = u"dependencies"
|
||||
PI_RECOMMENDATIONS = u"recommendations"
|
||||
PI_DESCRIPTION = u"description"
|
||||
PI_USAGE = u"usage"
|
||||
|
||||
# Types
|
||||
PLUG_TYPE_XEP = "XEP"
|
||||
|
|
@ -245,7 +262,7 @@ class Const(object):
|
|||
PLUG_MODE_BOTH = (PLUG_MODE_CLIENT, PLUG_MODE_COMPONENT)
|
||||
|
||||
# names of widely used plugins
|
||||
TEXT_CMDS = 'TEXT-COMMANDS'
|
||||
TEXT_CMDS = "TEXT-COMMANDS"
|
||||
|
||||
# PubSub event categories
|
||||
PS_PEP = "PEP"
|
||||
|
|
@ -253,19 +270,18 @@ class Const(object):
|
|||
|
||||
# PubSub
|
||||
PS_PUBLISH = "publish"
|
||||
PS_RETRACT = "retract" # used for items
|
||||
PS_DELETE = "delete" # used for nodes
|
||||
PS_RETRACT = "retract" # used for items
|
||||
PS_DELETE = "delete" # used for nodes
|
||||
PS_ITEM = "item"
|
||||
PS_ITEMS = "items" # Can contain publish and retract items
|
||||
PS_ITEMS = "items" # Can contain publish and retract items
|
||||
PS_EVENTS = (PS_ITEMS, PS_DELETE)
|
||||
|
||||
|
||||
## XMLUI ##
|
||||
XMLUI_WINDOW = 'window'
|
||||
XMLUI_POPUP = 'popup'
|
||||
XMLUI_FORM = 'form'
|
||||
XMLUI_PARAM = 'param'
|
||||
XMLUI_DIALOG = 'dialog'
|
||||
XMLUI_WINDOW = "window"
|
||||
XMLUI_POPUP = "popup"
|
||||
XMLUI_FORM = "form"
|
||||
XMLUI_PARAM = "param"
|
||||
XMLUI_DIALOG = "dialog"
|
||||
XMLUI_DIALOG_CONFIRM = "confirm"
|
||||
XMLUI_DIALOG_MESSAGE = "message"
|
||||
XMLUI_DIALOG_NOTE = "note"
|
||||
|
|
@ -284,108 +300,119 @@ class Const(object):
|
|||
XMLUI_DATA_BTNS_SET_OKCANCEL = "ok/cancel"
|
||||
XMLUI_DATA_BTNS_SET_YESNO = "yes/no"
|
||||
XMLUI_DATA_BTNS_SET_DEFAULT = XMLUI_DATA_BTNS_SET_OKCANCEL
|
||||
XMLUI_DATA_FILETYPE = 'filetype'
|
||||
XMLUI_DATA_FILETYPE = "filetype"
|
||||
XMLUI_DATA_FILETYPE_FILE = "file"
|
||||
XMLUI_DATA_FILETYPE_DIR = "dir"
|
||||
XMLUI_DATA_FILETYPE_DEFAULT = XMLUI_DATA_FILETYPE_FILE
|
||||
|
||||
|
||||
## Logging ##
|
||||
LOG_LVL_DEBUG = 'DEBUG'
|
||||
LOG_LVL_INFO = 'INFO'
|
||||
LOG_LVL_WARNING = 'WARNING'
|
||||
LOG_LVL_ERROR = 'ERROR'
|
||||
LOG_LVL_CRITICAL = 'CRITICAL'
|
||||
LOG_LEVELS = (LOG_LVL_DEBUG, LOG_LVL_INFO, LOG_LVL_WARNING, LOG_LVL_ERROR, LOG_LVL_CRITICAL)
|
||||
LOG_BACKEND_STANDARD = 'standard'
|
||||
LOG_BACKEND_TWISTED = 'twisted'
|
||||
LOG_BACKEND_BASIC = 'basic'
|
||||
LOG_BACKEND_CUSTOM = 'custom'
|
||||
LOG_BASE_LOGGER = 'root'
|
||||
LOG_TWISTED_LOGGER = 'twisted'
|
||||
LOG_OPT_SECTION = 'DEFAULT' # section of sat.conf where log options should be
|
||||
LOG_OPT_PREFIX = 'log_'
|
||||
LOG_LVL_DEBUG = "DEBUG"
|
||||
LOG_LVL_INFO = "INFO"
|
||||
LOG_LVL_WARNING = "WARNING"
|
||||
LOG_LVL_ERROR = "ERROR"
|
||||
LOG_LVL_CRITICAL = "CRITICAL"
|
||||
LOG_LEVELS = (
|
||||
LOG_LVL_DEBUG,
|
||||
LOG_LVL_INFO,
|
||||
LOG_LVL_WARNING,
|
||||
LOG_LVL_ERROR,
|
||||
LOG_LVL_CRITICAL,
|
||||
)
|
||||
LOG_BACKEND_STANDARD = "standard"
|
||||
LOG_BACKEND_TWISTED = "twisted"
|
||||
LOG_BACKEND_BASIC = "basic"
|
||||
LOG_BACKEND_CUSTOM = "custom"
|
||||
LOG_BASE_LOGGER = "root"
|
||||
LOG_TWISTED_LOGGER = "twisted"
|
||||
LOG_OPT_SECTION = "DEFAULT" # section of sat.conf where log options should be
|
||||
LOG_OPT_PREFIX = "log_"
|
||||
# (option_name, default_value) tuples
|
||||
LOG_OPT_COLORS = ('colors', 'true') # true for auto colors, force to have colors even if stdout is not a tty, false for no color
|
||||
LOG_OPT_TAINTS_DICT = ('levels_taints_dict', {
|
||||
LOG_LVL_DEBUG: ('cyan',),
|
||||
LOG_LVL_INFO: (),
|
||||
LOG_LVL_WARNING: ('yellow',),
|
||||
LOG_LVL_ERROR: ('red', 'blink', r'/!\ ', 'blink_off'),
|
||||
LOG_LVL_CRITICAL: ('bold', 'red', 'Guru Meditation ', 'normal_weight')
|
||||
})
|
||||
LOG_OPT_LEVEL = ('level', 'info')
|
||||
LOG_OPT_FORMAT = ('fmt', '%(message)s') # similar to logging format.
|
||||
LOG_OPT_LOGGER = ('logger', '') # regex to filter logger name
|
||||
LOG_OPT_OUTPUT_SEP = '//'
|
||||
LOG_OPT_OUTPUT_DEFAULT = 'default'
|
||||
LOG_OPT_OUTPUT_MEMORY = 'memory'
|
||||
LOG_OPT_COLORS = (
|
||||
"colors",
|
||||
"true",
|
||||
) # true for auto colors, force to have colors even if stdout is not a tty, false for no color
|
||||
LOG_OPT_TAINTS_DICT = (
|
||||
"levels_taints_dict",
|
||||
{
|
||||
LOG_LVL_DEBUG: ("cyan",),
|
||||
LOG_LVL_INFO: (),
|
||||
LOG_LVL_WARNING: ("yellow",),
|
||||
LOG_LVL_ERROR: ("red", "blink", r"/!\ ", "blink_off"),
|
||||
LOG_LVL_CRITICAL: ("bold", "red", "Guru Meditation ", "normal_weight"),
|
||||
},
|
||||
)
|
||||
LOG_OPT_LEVEL = ("level", "info")
|
||||
LOG_OPT_FORMAT = ("fmt", "%(message)s") # similar to logging format.
|
||||
LOG_OPT_LOGGER = ("logger", "") # regex to filter logger name
|
||||
LOG_OPT_OUTPUT_SEP = "//"
|
||||
LOG_OPT_OUTPUT_DEFAULT = "default"
|
||||
LOG_OPT_OUTPUT_MEMORY = "memory"
|
||||
LOG_OPT_OUTPUT_MEMORY_LIMIT = 50
|
||||
LOG_OPT_OUTPUT_FILE = 'file' # file is implicit if only output
|
||||
LOG_OPT_OUTPUT = ('output', LOG_OPT_OUTPUT_SEP + LOG_OPT_OUTPUT_DEFAULT) # //default = normal output (stderr or a file with twistd), path/to/file for a file (must be the first if used), //memory for memory (options can be put in parenthesis, e.g.: //memory(500) for a 500 lines memory)
|
||||
|
||||
LOG_OPT_OUTPUT_FILE = "file" # file is implicit if only output
|
||||
LOG_OPT_OUTPUT = (
|
||||
"output",
|
||||
LOG_OPT_OUTPUT_SEP + LOG_OPT_OUTPUT_DEFAULT,
|
||||
) # //default = normal output (stderr or a file with twistd), path/to/file for a file (must be the first if used), //memory for memory (options can be put in parenthesis, e.g.: //memory(500) for a 500 lines memory)
|
||||
|
||||
## action constants ##
|
||||
META_TYPE_FILE = "file"
|
||||
META_TYPE_OVERWRITE = "overwrite"
|
||||
|
||||
|
||||
## HARD-CODED ACTIONS IDS (generated with uuid.uuid4) ##
|
||||
AUTHENTICATE_PROFILE_ID = u'b03bbfa8-a4ae-4734-a248-06ce6c7cf562'
|
||||
CHANGE_XMPP_PASSWD_ID = u'878b9387-de2b-413b-950f-e424a147bcd0'
|
||||
|
||||
AUTHENTICATE_PROFILE_ID = u"b03bbfa8-a4ae-4734-a248-06ce6c7cf562"
|
||||
CHANGE_XMPP_PASSWD_ID = u"878b9387-de2b-413b-950f-e424a147bcd0"
|
||||
|
||||
## Text values ##
|
||||
BOOL_TRUE = "true"
|
||||
BOOL_FALSE = "false"
|
||||
|
||||
|
||||
## Special values used in bridge methods calls ##
|
||||
HISTORY_LIMIT_DEFAULT = -1
|
||||
HISTORY_LIMIT_NONE = -2
|
||||
|
||||
|
||||
## Progress error special values ##
|
||||
PROGRESS_ERROR_DECLINED = u'declined' # session has been declined by peer user
|
||||
|
||||
PROGRESS_ERROR_DECLINED = u"declined" # session has been declined by peer user
|
||||
|
||||
## Files ##
|
||||
FILE_TYPE_DIRECTORY = 'directory'
|
||||
FILE_TYPE_FILE = 'file'
|
||||
|
||||
FILE_TYPE_DIRECTORY = "directory"
|
||||
FILE_TYPE_FILE = "file"
|
||||
|
||||
## Permissions management ##
|
||||
ACCESS_PERM_READ = u'read'
|
||||
ACCESS_PERM_WRITE = u'write'
|
||||
ACCESS_PERM_READ = u"read"
|
||||
ACCESS_PERM_WRITE = u"write"
|
||||
ACCESS_PERMS = {ACCESS_PERM_READ, ACCESS_PERM_WRITE}
|
||||
ACCESS_TYPE_PUBLIC = u'public'
|
||||
ACCESS_TYPE_WHITELIST = u'whitelist'
|
||||
ACCESS_TYPE_PUBLIC = u"public"
|
||||
ACCESS_TYPE_WHITELIST = u"whitelist"
|
||||
ACCESS_TYPES = (ACCESS_TYPE_PUBLIC, ACCESS_TYPE_WHITELIST)
|
||||
|
||||
|
||||
## Common data keys ##
|
||||
KEY_THUMBNAILS = u'thumbnails'
|
||||
KEY_PROGRESS_ID = u'progress_id'
|
||||
|
||||
|
||||
#internationalisation
|
||||
DEFAULT_LOCALE = u'en_GB'
|
||||
KEY_THUMBNAILS = u"thumbnails"
|
||||
KEY_PROGRESS_ID = u"progress_id"
|
||||
|
||||
# internationalisation
|
||||
DEFAULT_LOCALE = u"en_GB"
|
||||
|
||||
## Misc ##
|
||||
SAVEFILE_DATABASE = APP_NAME_FILE + ".db"
|
||||
IQ_SET = '/iq[@type="set"]'
|
||||
ENV_PREFIX = 'SAT_' # Prefix used for environment variables
|
||||
IGNORE = 'ignore'
|
||||
NO_LIMIT = -1 # used in bridge when a integer value is expected
|
||||
DEFAULT_MAX_AGE = 1209600 # default max age of cached files, in seconds
|
||||
HASH_SHA1_EMPTY = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
|
||||
ENV_PREFIX = "SAT_" # Prefix used for environment variables
|
||||
IGNORE = "ignore"
|
||||
NO_LIMIT = -1 # used in bridge when a integer value is expected
|
||||
DEFAULT_MAX_AGE = 1209600 # default max age of cached files, in seconds
|
||||
HASH_SHA1_EMPTY = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
|
||||
@classmethod
|
||||
def LOG_OPTIONS(cls):
|
||||
"""Return options checked for logs"""
|
||||
# XXX: we use a classmethod so we can use Const inheritance to change default options
|
||||
return(cls.LOG_OPT_COLORS, cls.LOG_OPT_TAINTS_DICT, cls.LOG_OPT_LEVEL, cls.LOG_OPT_FORMAT, cls.LOG_OPT_LOGGER, cls.LOG_OPT_OUTPUT)
|
||||
return (
|
||||
cls.LOG_OPT_COLORS,
|
||||
cls.LOG_OPT_TAINTS_DICT,
|
||||
cls.LOG_OPT_LEVEL,
|
||||
cls.LOG_OPT_FORMAT,
|
||||
cls.LOG_OPT_LOGGER,
|
||||
cls.LOG_OPT_OUTPUT,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def bool(cls, value):
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ class InternalError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class FeatureNotFound(Exception): # a disco feature/identity which is needed is not present
|
||||
class FeatureNotFound(
|
||||
Exception
|
||||
): # a disco feature/identity which is needed is not present
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,27 +19,31 @@
|
|||
|
||||
|
||||
from sat.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
try:
|
||||
|
||||
import gettext
|
||||
|
||||
_ = gettext.translation('sat', 'i18n', fallback=True).ugettext
|
||||
_ = gettext.translation("sat", "i18n", fallback=True).ugettext
|
||||
_translators = {None: gettext.NullTranslations()}
|
||||
|
||||
def languageSwitch(lang=None):
|
||||
if not lang in _translators:
|
||||
_translators[lang] = gettext.translation('sat', languages=[lang], fallback=True)
|
||||
_translators[lang] = gettext.translation(
|
||||
"sat", languages=[lang], fallback=True
|
||||
)
|
||||
_translators[lang].install(unicode=True)
|
||||
|
||||
|
||||
except ImportError:
|
||||
|
||||
log.warning("gettext support disabled")
|
||||
_ = lambda msg: msg # Libervia doesn't support gettext
|
||||
_ = lambda msg: msg # Libervia doesn't support gettext
|
||||
|
||||
def languageSwitch(lang=None):
|
||||
pass
|
||||
|
||||
|
||||
D_ = lambda msg: msg # used for deferred translations
|
||||
|
||||
D_ = lambda msg: msg # used for deferred translations
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class TwistedLogger(log.Logger):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(TwistedLogger, self).__init__(*args, **kwargs)
|
||||
from twisted.python import log as twisted_log
|
||||
|
||||
self.twisted_log = twisted_log
|
||||
|
||||
def out(self, message, level=None):
|
||||
|
|
@ -38,22 +39,30 @@ class TwistedLogger(log.Logger):
|
|||
|
||||
@param message: formatted message
|
||||
"""
|
||||
self.twisted_log.msg(message.encode('utf-8', 'ignore'), sat_logged=True, level=level)
|
||||
self.twisted_log.msg(
|
||||
message.encode("utf-8", "ignore"), sat_logged=True, level=level
|
||||
)
|
||||
|
||||
|
||||
class ConfigureBasic(log.ConfigureBase):
|
||||
|
||||
def configureColors(self, colors, force_colors, levels_taints_dict):
|
||||
super(ConfigureBasic, self).configureColors(colors, force_colors, levels_taints_dict)
|
||||
super(ConfigureBasic, self).configureColors(
|
||||
colors, force_colors, levels_taints_dict
|
||||
)
|
||||
if colors:
|
||||
import sys
|
||||
|
||||
try:
|
||||
isatty = sys.stdout.isatty()
|
||||
except AttributeError:
|
||||
isatty = False
|
||||
if force_colors or isatty: # FIXME: isatty should be tested on each handler, not globaly
|
||||
if (
|
||||
force_colors or isatty
|
||||
): # FIXME: isatty should be tested on each handler, not globaly
|
||||
# we need colors
|
||||
log.Logger.post_treat = lambda logger, level, message: self.ansiColors(level, message)
|
||||
log.Logger.post_treat = lambda logger, level, message: self.ansiColors(
|
||||
level, message
|
||||
)
|
||||
elif force_colors:
|
||||
raise ValueError("force_colors can't be used if colors is False")
|
||||
|
||||
|
|
@ -61,30 +70,36 @@ class ConfigureBasic(log.ConfigureBase):
|
|||
def getProfile():
|
||||
"""Try to find profile value using introspection"""
|
||||
import inspect
|
||||
|
||||
stack = inspect.stack()
|
||||
current_path = stack[0][1]
|
||||
for frame_data in stack[:-1]:
|
||||
if frame_data[1] != current_path:
|
||||
if log.backend == C.LOG_BACKEND_STANDARD and "/logging/__init__.py" in frame_data[1]:
|
||||
if (
|
||||
log.backend == C.LOG_BACKEND_STANDARD
|
||||
and "/logging/__init__.py" in frame_data[1]
|
||||
):
|
||||
continue
|
||||
break
|
||||
|
||||
frame = frame_data[0]
|
||||
args = inspect.getargvalues(frame)
|
||||
try:
|
||||
profile = args.locals.get('profile') or args.locals['profile_key']
|
||||
profile = args.locals.get("profile") or args.locals["profile_key"]
|
||||
except (TypeError, KeyError):
|
||||
try:
|
||||
try:
|
||||
profile = args.locals['self'].profile
|
||||
profile = args.locals["self"].profile
|
||||
except AttributeError:
|
||||
try:
|
||||
profile = args.locals['self'].parent.profile
|
||||
profile = args.locals["self"].parent.profile
|
||||
except AttributeError:
|
||||
profile = args.locals['self'].host.profile # used in quick_frontend for single profile configuration
|
||||
profile = args.locals[
|
||||
"self"
|
||||
].host.profile # used in quick_frontend for single profile configuration
|
||||
except Exception:
|
||||
# we can't find profile, we return an empty value
|
||||
profile = ''
|
||||
profile = ""
|
||||
return profile
|
||||
|
||||
|
||||
|
|
@ -97,16 +112,23 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
@param observer: original observer to hook
|
||||
@param can_colors: True if observer can display ansi colors
|
||||
"""
|
||||
|
||||
def observer_hook(event):
|
||||
"""redirect non SàT log to twisted_logger, and add colors when possible"""
|
||||
if 'sat_logged' in event: # we only want our own logs, other are managed by twistedObserver
|
||||
if (
|
||||
"sat_logged" in event
|
||||
): # we only want our own logs, other are managed by twistedObserver
|
||||
# we add colors if possible
|
||||
if (can_colors and self.LOGGER_CLASS.colors) or self.LOGGER_CLASS.force_colors:
|
||||
message = event.get('message', tuple())
|
||||
level = event.get('level', C.LOG_LVL_INFO)
|
||||
if (
|
||||
can_colors and self.LOGGER_CLASS.colors
|
||||
) or self.LOGGER_CLASS.force_colors:
|
||||
message = event.get("message", tuple())
|
||||
level = event.get("level", C.LOG_LVL_INFO)
|
||||
if message:
|
||||
event['message'] = (self.ansiColors(level, ''.join(message)),) # must be a tuple
|
||||
observer(event) # we can now call the original observer
|
||||
event["message"] = (
|
||||
self.ansiColors(level, "".join(message)),
|
||||
) # must be a tuple
|
||||
observer(event) # we can now call the original observer
|
||||
|
||||
return observer_hook
|
||||
|
||||
|
|
@ -130,7 +152,7 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
@param observer: observer to hook
|
||||
@return: hooked observer or original one
|
||||
"""
|
||||
if hasattr(observer, '__self__'):
|
||||
if hasattr(observer, "__self__"):
|
||||
ori = observer
|
||||
if isinstance(observer.__self__, self.twisted_log.FileLogObserver):
|
||||
observer = self.changeFileLogObserver(observer)
|
||||
|
|
@ -147,12 +169,15 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
"""initialise needed attributes, and install observers hooks"""
|
||||
self.observers = {}
|
||||
from twisted.python import log as twisted_log
|
||||
|
||||
self.twisted_log = twisted_log
|
||||
self.log_publisher = twisted_log.msg.__self__
|
||||
|
||||
def addObserverObserver(self_logpub, other):
|
||||
"""Install hook so we know when a new observer is added"""
|
||||
other = self.installObserverHook(other)
|
||||
return self_logpub._originalAddObserver(other)
|
||||
|
||||
def removeObserverObserver(self_logpub, ori):
|
||||
"""removeObserver hook fix
|
||||
|
||||
|
|
@ -170,11 +195,20 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
raise ValueError("Unknown observer")
|
||||
|
||||
# we replace addObserver/removeObserver by our own
|
||||
twisted_log.LogPublisher._originalAddObserver = twisted_log.LogPublisher.addObserver
|
||||
twisted_log.LogPublisher._originalRemoveObserver = twisted_log.LogPublisher.removeObserver
|
||||
import types # see https://stackoverflow.com/a/4267590 (thx Chris Morgan/aaronasterling)
|
||||
twisted_log.addObserver = types.MethodType(addObserverObserver, self.log_publisher, twisted_log.LogPublisher)
|
||||
twisted_log.removeObserver = types.MethodType(removeObserverObserver, self.log_publisher, twisted_log.LogPublisher)
|
||||
twisted_log.LogPublisher._originalAddObserver = (
|
||||
twisted_log.LogPublisher.addObserver
|
||||
)
|
||||
twisted_log.LogPublisher._originalRemoveObserver = (
|
||||
twisted_log.LogPublisher.removeObserver
|
||||
)
|
||||
import types # see https://stackoverflow.com/a/4267590 (thx Chris Morgan/aaronasterling)
|
||||
|
||||
twisted_log.addObserver = types.MethodType(
|
||||
addObserverObserver, self.log_publisher, twisted_log.LogPublisher
|
||||
)
|
||||
twisted_log.removeObserver = types.MethodType(
|
||||
removeObserverObserver, self.log_publisher, twisted_log.LogPublisher
|
||||
)
|
||||
|
||||
# we now change existing observers
|
||||
for idx, observer in enumerate(self.log_publisher.observers):
|
||||
|
|
@ -186,6 +220,7 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
|
||||
def configureOutput(self, output):
|
||||
import sys
|
||||
|
||||
if output is None:
|
||||
output = C.LOG_OPT_OUTPUT_SEP + C.LOG_OPT_OUTPUT_DEFAULT
|
||||
self.manageOutputs(output)
|
||||
|
|
@ -194,9 +229,11 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
if C.LOG_OPT_OUTPUT_DEFAULT in log.handlers:
|
||||
# default output is already managed, we just add output to stdout if we are in debug or nodaemon mode
|
||||
if self.backend_data is None:
|
||||
raise ValueError("You must pass options as backend_data with Twisted backend")
|
||||
raise ValueError(
|
||||
"You must pass options as backend_data with Twisted backend"
|
||||
)
|
||||
options = self.backend_data
|
||||
if options.get('nodaemon', False) or options.get('debug', False):
|
||||
if options.get("nodaemon", False) or options.get("debug", False):
|
||||
addObserver(self.twisted_log.FileLogObserver(sys.stdout).emit)
|
||||
else:
|
||||
# \\default is not in the output, so we remove current observers
|
||||
|
|
@ -208,49 +245,81 @@ class ConfigureTwisted(ConfigureBasic):
|
|||
|
||||
if C.LOG_OPT_OUTPUT_FILE in log.handlers:
|
||||
from twisted.python import logfile
|
||||
|
||||
for path in log.handlers[C.LOG_OPT_OUTPUT_FILE]:
|
||||
log_file = sys.stdout if path == '-' else logfile.LogFile.fromFullPath(path)
|
||||
log_file = (
|
||||
sys.stdout if path == "-" else logfile.LogFile.fromFullPath(path)
|
||||
)
|
||||
addObserver(self.twisted_log.FileLogObserver(log_file).emit)
|
||||
|
||||
if C.LOG_OPT_OUTPUT_MEMORY in log.handlers:
|
||||
raise NotImplementedError("Memory observer is not implemented in Twisted backend")
|
||||
raise NotImplementedError(
|
||||
"Memory observer is not implemented in Twisted backend"
|
||||
)
|
||||
|
||||
def configureColors(self, colors, force_colors, levels_taints_dict):
|
||||
super(ConfigureTwisted, self).configureColors(colors, force_colors, levels_taints_dict)
|
||||
super(ConfigureTwisted, self).configureColors(
|
||||
colors, force_colors, levels_taints_dict
|
||||
)
|
||||
self.LOGGER_CLASS.colors = colors
|
||||
self.LOGGER_CLASS.force_colors = force_colors
|
||||
if force_colors and not colors:
|
||||
raise ValueError('colors must be True if force_colors is True')
|
||||
raise ValueError("colors must be True if force_colors is True")
|
||||
|
||||
def postTreatment(self):
|
||||
"""Install twistedObserver which manage non SàT logs"""
|
||||
|
||||
def twistedObserver(event):
|
||||
"""Observer which redirect log message not produced by SàT to SàT logging system"""
|
||||
if not 'sat_logged' in event:
|
||||
if not "sat_logged" in event:
|
||||
# this log was not produced by SàT
|
||||
from twisted.python import log as twisted_log
|
||||
|
||||
text = twisted_log.textFromEventDict(event)
|
||||
if text is None:
|
||||
return
|
||||
twisted_logger = log.getLogger(C.LOG_TWISTED_LOGGER)
|
||||
log_method = twisted_logger.error if event.get('isError', False) else twisted_logger.info
|
||||
log_method(text.decode('utf-8'))
|
||||
log_method = (
|
||||
twisted_logger.error
|
||||
if event.get("isError", False)
|
||||
else twisted_logger.info
|
||||
)
|
||||
log_method(text.decode("utf-8"))
|
||||
|
||||
self.log_publisher._originalAddObserver(twistedObserver)
|
||||
|
||||
|
||||
class ConfigureStandard(ConfigureBasic):
|
||||
|
||||
def __init__(self, level=None, fmt=None, output=None, logger=None, colors=False, levels_taints_dict=None, force_colors=False, backend_data=None):
|
||||
def __init__(
|
||||
self,
|
||||
level=None,
|
||||
fmt=None,
|
||||
output=None,
|
||||
logger=None,
|
||||
colors=False,
|
||||
levels_taints_dict=None,
|
||||
force_colors=False,
|
||||
backend_data=None,
|
||||
):
|
||||
if fmt is None:
|
||||
fmt = C.LOG_OPT_FORMAT[1]
|
||||
if output is None:
|
||||
output = C.LOG_OPT_OUTPUT[1]
|
||||
super(ConfigureStandard, self).__init__(level, fmt, output, logger, colors, levels_taints_dict, force_colors, backend_data)
|
||||
super(ConfigureStandard, self).__init__(
|
||||
level,
|
||||
fmt,
|
||||
output,
|
||||
logger,
|
||||
colors,
|
||||
levels_taints_dict,
|
||||
force_colors,
|
||||
backend_data,
|
||||
)
|
||||
|
||||
def preTreatment(self):
|
||||
"""We use logging methods directly, instead of using Logger"""
|
||||
import logging
|
||||
|
||||
log.getLogger = logging.getLogger
|
||||
log.debug = logging.debug
|
||||
log.info = logging.info
|
||||
|
|
@ -271,7 +340,7 @@ class ConfigureStandard(ConfigureBasic):
|
|||
class SatFormatter(logging.Formatter):
|
||||
u"""Formatter which manage SàT specificities"""
|
||||
_format = fmt
|
||||
_with_profile = '%(profile)s' in fmt
|
||||
_with_profile = "%(profile)s" in fmt
|
||||
|
||||
def __init__(self, can_colors=False):
|
||||
super(SatFormatter, self).__init__(self._format)
|
||||
|
|
@ -288,14 +357,14 @@ class ConfigureStandard(ConfigureBasic):
|
|||
record.color_start = log.COLOR_START
|
||||
record.color_end = log.COLOR_END
|
||||
else:
|
||||
record.color_start = record.color_end = ''
|
||||
record.color_start = record.color_end = ""
|
||||
s = super(SatFormatter, self).format(record)
|
||||
if do_color:
|
||||
s = ConfigureStandard.ansiColors(record.levelname, s)
|
||||
if sys.platform == "android":
|
||||
# FIXME: dirty hack to workaround android encoding issue on log
|
||||
# need to be fixed properly
|
||||
return s.encode('ascii', 'ignore')
|
||||
return s.encode("ascii", "ignore")
|
||||
else:
|
||||
return s
|
||||
|
||||
|
|
@ -308,7 +377,9 @@ class ConfigureStandard(ConfigureBasic):
|
|||
self.name_filter = log.FilterName(logger) if logger else None
|
||||
|
||||
def configureColors(self, colors, force_colors, levels_taints_dict):
|
||||
super(ConfigureStandard, self).configureColors(colors, force_colors, levels_taints_dict)
|
||||
super(ConfigureStandard, self).configureColors(
|
||||
colors, force_colors, levels_taints_dict
|
||||
)
|
||||
self.formatterClass.with_colors = colors
|
||||
self.formatterClass.force_colors = force_colors
|
||||
if not colors and force_colors:
|
||||
|
|
@ -323,6 +394,7 @@ class ConfigureStandard(ConfigureBasic):
|
|||
|
||||
def postTreatment(self):
|
||||
import logging
|
||||
|
||||
root_logger = logging.getLogger()
|
||||
if len(root_logger.handlers) == 0:
|
||||
for handler, options in log.handlers.items():
|
||||
|
|
@ -335,14 +407,21 @@ class ConfigureStandard(ConfigureBasic):
|
|||
self._addHandler(root_logger, hdlr, can_colors=can_colors)
|
||||
elif handler == C.LOG_OPT_OUTPUT_MEMORY:
|
||||
from logging.handlers import BufferingHandler
|
||||
|
||||
class SatMemoryHandler(BufferingHandler):
|
||||
def emit(self, record):
|
||||
super(SatMemoryHandler, self).emit(self.format(record))
|
||||
|
||||
hdlr = SatMemoryHandler(options)
|
||||
log.handlers[handler] = hdlr # we keep a reference to the handler to read the buffer later
|
||||
log.handlers[
|
||||
handler
|
||||
] = (
|
||||
hdlr
|
||||
) # we keep a reference to the handler to read the buffer later
|
||||
self._addHandler(root_logger, hdlr, can_colors=False)
|
||||
elif handler == C.LOG_OPT_OUTPUT_FILE:
|
||||
import os.path
|
||||
|
||||
for path in options:
|
||||
hdlr = logging.FileHandler(os.path.expanduser(path))
|
||||
self._addHandler(root_logger, hdlr, can_colors=False)
|
||||
|
|
@ -358,13 +437,16 @@ class ConfigureStandard(ConfigureBasic):
|
|||
@param size: number of logs to return
|
||||
"""
|
||||
mem_handler = log.handlers[C.LOG_OPT_OUTPUT_MEMORY]
|
||||
return (log_msg for log_msg in mem_handler.buffer[size if size is None else -size:])
|
||||
return (
|
||||
log_msg for log_msg in mem_handler.buffer[size if size is None else -size :]
|
||||
)
|
||||
|
||||
|
||||
log.configure_cls[C.LOG_BACKEND_BASIC] = ConfigureBasic
|
||||
log.configure_cls[C.LOG_BACKEND_TWISTED] = ConfigureTwisted
|
||||
log.configure_cls[C.LOG_BACKEND_STANDARD] = ConfigureStandard
|
||||
|
||||
|
||||
def configure(backend, **options):
|
||||
"""Configure logging behaviour
|
||||
@param backend: can be:
|
||||
|
|
@ -375,6 +457,7 @@ def configure(backend, **options):
|
|||
"""
|
||||
return log.configure(backend, **options)
|
||||
|
||||
|
||||
def _parseOptions(options):
|
||||
"""Parse string options as given in conf or environment variable, and return expected python value
|
||||
|
||||
|
|
@ -384,11 +467,11 @@ def _parseOptions(options):
|
|||
LEVEL = C.LOG_OPT_LEVEL[0]
|
||||
|
||||
if COLORS in options:
|
||||
if options[COLORS].lower() in ('1', 'true'):
|
||||
if options[COLORS].lower() in ("1", "true"):
|
||||
options[COLORS] = True
|
||||
elif options[COLORS] == 'force':
|
||||
elif options[COLORS] == "force":
|
||||
options[COLORS] = True
|
||||
options['force_colors'] = True
|
||||
options["force_colors"] = True
|
||||
else:
|
||||
options[COLORS] = False
|
||||
if LEVEL in options:
|
||||
|
|
@ -397,6 +480,7 @@ def _parseOptions(options):
|
|||
level = C.LOG_LVL_INFO
|
||||
options[LEVEL] = level
|
||||
|
||||
|
||||
def satConfigure(backend=C.LOG_BACKEND_STANDARD, const=None, backend_data=None):
|
||||
"""Configure logging system for SàT, can be used by frontends
|
||||
|
||||
|
|
@ -413,13 +497,18 @@ def satConfigure(backend=C.LOG_BACKEND_STANDARD, const=None, backend_data=None):
|
|||
log.C = const
|
||||
from sat.tools import config
|
||||
import os
|
||||
|
||||
log_conf = {}
|
||||
sat_conf = config.parseMainConf()
|
||||
for opt_name, opt_default in C.LOG_OPTIONS():
|
||||
try:
|
||||
log_conf[opt_name] = os.environ[''.join((C.ENV_PREFIX, C.LOG_OPT_PREFIX.upper(), opt_name.upper()))]
|
||||
log_conf[opt_name] = os.environ[
|
||||
"".join((C.ENV_PREFIX, C.LOG_OPT_PREFIX.upper(), opt_name.upper()))
|
||||
]
|
||||
except KeyError:
|
||||
log_conf[opt_name] = config.getConfig(sat_conf, C.LOG_OPT_SECTION, C.LOG_OPT_PREFIX + opt_name, opt_default)
|
||||
log_conf[opt_name] = config.getConfig(
|
||||
sat_conf, C.LOG_OPT_SECTION, C.LOG_OPT_PREFIX + opt_name, opt_default
|
||||
)
|
||||
|
||||
_parseOptions(log_conf)
|
||||
configure(backend, backend_data=backend_data, **log_conf)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue