provider support

This commit is contained in:
Emmanuel Garette 2021-12-10 23:35:44 +01:00
parent 757d9ec5c2
commit 8cf8c9b8eb
21 changed files with 212 additions and 15 deletions

View File

@ -32,7 +32,7 @@ from rougail.annotator.target import TargetAnnotator
from rougail.annotator.param import ParamAnnotator from rougail.annotator.param import ParamAnnotator
CALC_MULTI = ('calc_value', 'calc_list', 'get_range', 'calc_val_first_value', 'unbound_filename', 'zone_information', 'get_certificates', 'nsd_filename', 'get_linked_configuration') CALC_MULTI = ('calc_value', 'calc_list', 'get_range', 'calc_val_first_value', 'unbound_filename', 'zone_information', 'get_certificates', 'nsd_filename', 'get_linked_configuration', 'get_internal_zones', 'nsd_concat_lists', 'get_internal_info_in_zone')
class Annotator(TargetAnnotator, ParamAnnotator): class Annotator(TargetAnnotator, ParamAnnotator):

View File

@ -102,8 +102,11 @@ class ParamAnnotator:
if param.type == 'suffix': if param.type == 'suffix':
for target in obj.target: for target in obj.target:
if not self.objectspace.paths.variable_is_dynamic(target.name.path): if not self.objectspace.paths.variable_is_dynamic(target.name.path):
target_name = target.name
if isinstance(target_name, self.objectspace.variable):
target_name = target_name.name
msg = _(f'"{param.type}" parameter cannot be set with target ' msg = _(f'"{param.type}" parameter cannot be set with target '
f'"{target.name}" which is not a dynamic variable') f'"{target_name}" which is not a dynamic variable')
raise DictConsistencyError(msg, 53, obj.xmlfiles) raise DictConsistencyError(msg, 53, obj.xmlfiles)
elif param.type == 'index': elif param.type == 'index':
for target in obj.target: for target in obj.target:

View File

@ -86,6 +86,7 @@ class RougailConvert:
) )
self.output = TiramisuReflector(rougailobjspace, self.output = TiramisuReflector(rougailobjspace,
functions_file, functions_file,
rougailconfig['internal_functions'],
).get_text() + '\n' ).get_text() + '\n'
@staticmethod @staticmethod

View File

@ -90,7 +90,6 @@
<!ATTLIST family hidden (True|False) "False"> <!ATTLIST family hidden (True|False) "False">
<!ATTLIST family dynamic CDATA #IMPLIED> <!ATTLIST family dynamic CDATA #IMPLIED>
<!ATTLIST family leadership (True|False) "False"> <!ATTLIST family leadership (True|False) "False">
<!ATTLIST family provider CDATA #IMPLIED>
<!ELEMENT variable ((choice*|value*)*)> <!ELEMENT variable ((choice*|value*)*)>
<!ATTLIST variable name CDATA #REQUIRED> <!ATTLIST variable name CDATA #REQUIRED>

View File

@ -179,6 +179,7 @@ class RougailObjSpace:
self.space, self.space,
namespace, namespace,
redefine_variables, redefine_variables,
False,
) )
def _xml_parse(self, # pylint: disable=R0913 def _xml_parse(self, # pylint: disable=R0913
@ -187,10 +188,15 @@ class RougailObjSpace:
space, space,
namespace, namespace,
redefine_variables, redefine_variables,
is_dynamic,
) -> None: ) -> None:
# var to check unique family name in a XML file # var to check unique family name in a XML file
family_names = [] family_names = []
for child in document: for child in document:
if is_dynamic:
is_sub_dynamic = True
else:
is_sub_dynamic = document.attrib.get('dynamic') is not None
if not isinstance(child.tag, str): if not isinstance(child.tag, str):
# doesn't proceed the XML commentaries # doesn't proceed the XML commentaries
continue continue
@ -225,6 +231,7 @@ class RougailObjSpace:
document, document,
variableobj, variableobj,
space, space,
is_sub_dynamic,
) )
self.add_to_tree_structure(variableobj, self.add_to_tree_structure(variableobj,
space, space,
@ -237,6 +244,7 @@ class RougailObjSpace:
variableobj, variableobj,
namespace, namespace,
redefine_variables, redefine_variables,
is_sub_dynamic,
) )
def get_variableobj(self, def get_variableobj(self,
@ -472,6 +480,7 @@ class RougailObjSpace:
document, document,
variableobj, variableobj,
space, space,
is_dynamic,
): ):
"""Fill self.paths attributes """Fill self.paths attributes
""" """
@ -488,7 +497,7 @@ class RougailObjSpace:
self.paths.add_variable(namespace, self.paths.add_variable(namespace,
variableobj.name, variableobj.name,
space.path, space.path,
document.attrib.get('dynamic') is not None, is_dynamic,
variableobj, variableobj,
leader, leader,
) )

View File

@ -125,6 +125,8 @@ class Path:
) -> str: # pylint: disable=C0111 ) -> str: # pylint: disable=C0111
"""Add a new variable (with path) """Add a new variable (with path)
""" """
if name == 'hostname_' and not is_dynamic:
raise Exception('pffff')
if '.' not in name: if '.' not in name:
full_path = '.'.join([family, name]) full_path = '.'.join([family, name])
if namespace == self.variable_namespace: if namespace == self.variable_namespace:

View File

@ -236,6 +236,7 @@ class RougailBaseTemplate:
def patch_template(self, def patch_template(self,
filename: str, filename: str,
templates_dir: str,
) -> None: ) -> None:
"""Apply patch to a template """Apply patch to a template
""" """
@ -251,7 +252,7 @@ class RougailBaseTemplate:
msg = _(f"Error applying patch: '{patch_file}'\n" msg = _(f"Error applying patch: '{patch_file}'\n"
f"To reproduce and fix this error {patch_cmd_err}") f"To reproduce and fix this error {patch_cmd_err}")
self.log.error(_(msg)) self.log.error(_(msg))
copy(join(self.templates_dir, filename), self.tmp_dir) copy(join(templates_dir, filename), self.tmp_dir)
def prepare_template(self, def prepare_template(self,
filename: str, filename: str,
@ -263,7 +264,7 @@ class RougailBaseTemplate:
if not isdir(self.tmp_dir): if not isdir(self.tmp_dir):
raise TemplateError(_(f'cannot find tmp_dir {self.tmp_dir}')) raise TemplateError(_(f'cannot find tmp_dir {self.tmp_dir}'))
copy(join(templates_dir, filename), self.tmp_dir) copy(join(templates_dir, filename), self.tmp_dir)
self.patch_template(filename) self.patch_template(filename, templates_dir)
def instance_file(self, def instance_file(self,
filevar: Dict, filevar: Dict,

View File

@ -84,7 +84,7 @@ class RougailSystemdTemplate(RougailBaseTemplate):
) -> tuple: ) -> tuple:
source = filevar['source'] source = filevar['source']
if not isfile(source): # pragma: no cover if not isfile(source): # pragma: no cover
raise FileNotFound(_(f"File {source} does not exist.")) raise FileNotFound(_(f'Source file "{source}" does not exist in {", ".join(self.templates_dir)}'))
tmp_file = join(self.tmp_dir, source) tmp_file = join(self.tmp_dir, source)
#self.instance_file(fill, 'files') #self.instance_file(fill, 'files')
if variable: if variable:
@ -102,7 +102,7 @@ class RougailSystemdTemplate(RougailBaseTemplate):
) -> tuple: ) -> tuple:
source = filevar['source'] source = filevar['source']
if not isfile(source): # pragma: no cover if not isfile(source): # pragma: no cover
raise FileNotFound(_(f"File {source} does not exist.")) raise FileNotFound(_(f'Override source file "{source}" does not exist in {", ".join(self.templates_dir)}'))
tmp_file = join(self.tmp_dir, source) tmp_file = join(self.tmp_dir, source)
service_name = filevar['name'] service_name = filevar['name']
destfile = f'/systemd/system/{service_name}.{service_type}.d/rougail.conf' destfile = f'/systemd/system/{service_name}.{service_type}.d/rougail.conf'

View File

@ -32,12 +32,6 @@ from .annotator import CONVERT_OPTION
from .objspace import RootRougailObject from .objspace import RootRougailObject
class Root(): # pylint: disable=R0903
"""Root classes
"""
path = '.'
class BaseElt: # pylint: disable=R0903 class BaseElt: # pylint: disable=R0903
"""Base element """Base element
""" """
@ -52,6 +46,7 @@ class TiramisuReflector:
def __init__(self, def __init__(self,
objectspace, objectspace,
funcs_paths, funcs_paths,
internal_functions,
): ):
self.index = 0 self.index = 0
self.text = [] self.text = []
@ -73,6 +68,9 @@ class TiramisuReflector:
" continue", " continue",
" setattr(func, function, getattr(_func, function))", " setattr(func, function, getattr(_func, function))",
]) ])
if internal_functions:
for func in internal_functions:
self.text.append(f"setattr(func, '{func}', {func})")
self.text.extend(["try:", self.text.extend(["try:",
" from tiramisu3 import *", " from tiramisu3 import *",
"except:", "except:",
@ -86,8 +84,11 @@ class TiramisuReflector:
def make_tiramisu_objects(self) -> None: def make_tiramisu_objects(self) -> None:
"""make tiramisu objects """make tiramisu objects
""" """
providers = {}
baseelt = BaseElt() baseelt = BaseElt()
self.set_name(baseelt) self.set_name(baseelt)
dynamic_path = ''
dynamic = False
basefamily = Family(baseelt, basefamily = Family(baseelt,
self.text, self.text,
self.objectspace, self.objectspace,
@ -95,7 +96,12 @@ class TiramisuReflector:
for elt in self.reorder_family(): for elt in self.reorder_family():
self.populate_family(basefamily, self.populate_family(basefamily,
elt, elt,
providers,
dynamic,
dynamic_path,
) )
basefamily.elt.information = providers
basefamily.populate_informations()
self.baseelt = baseelt self.baseelt = baseelt
def reorder_family(self): def reorder_family(self):
@ -115,6 +121,9 @@ class TiramisuReflector:
def populate_family(self, def populate_family(self,
parent_family, parent_family,
elt, elt,
providers,
dynamic,
dynamic_path,
): ):
"""Populate family """Populate family
""" """
@ -123,11 +132,21 @@ class TiramisuReflector:
self.text, self.text,
self.objectspace, self.objectspace,
) )
if not dynamic_path:
dynamic_path = elt.name
else:
dynamic_path = dynamic_path + '.' + elt.name
if dynamic or hasattr(elt, 'suffixes'):
dynamic_path += '{suffix}'
dynamic = True
parent_family.add(family) parent_family.add(family)
for children in vars(elt).values(): for children in vars(elt).values():
if isinstance(children, self.objectspace.family): if isinstance(children, self.objectspace.family):
self.populate_family(family, self.populate_family(family,
children, children,
providers,
dynamic,
dynamic_path,
) )
continue continue
if isinstance(children, dict): if isinstance(children, dict):
@ -139,13 +158,21 @@ class TiramisuReflector:
continue continue
if isinstance(child, self.objectspace.variable): if isinstance(child, self.objectspace.variable):
self.set_name(child) self.set_name(child)
sub_dynamic_path = dynamic_path + '.' + child.name
if dynamic:
sub_dynamic_path += '{suffix}'
family.add(Variable(child, family.add(Variable(child,
self.text, self.text,
self.objectspace, self.objectspace,
providers,
sub_dynamic_path,
)) ))
else: else:
self.populate_family(family, self.populate_family(family,
child, child,
providers,
dynamic,
dynamic_path,
) )
def set_name(self, def set_name(self,
@ -185,6 +212,8 @@ class Common:
self.option_name = self.elt.reflector_name self.option_name = self.elt.reflector_name
self.populate_attrib() self.populate_attrib()
self.populate_informations() self.populate_informations()
if hasattr(self.elt, 'provider'):
self.providers['provider:' + self.elt.provider] = self.dynamic_path
return self.option_name return self.option_name
def populate_attrib(self): def populate_attrib(self):
@ -239,7 +268,11 @@ class Common:
""" """
if not hasattr(self.elt, 'information'): if not hasattr(self.elt, 'information'):
return return
for key, value in vars(self.elt.information).items(): if isinstance(self.elt.information, dict):
informations = self.elt.information
else:
informations = vars(self.elt.information)
for key, value in informations.items():
if key == 'xmlfiles': if key == 'xmlfiles':
continue continue
if isinstance(value, str): if isinstance(value, str):
@ -297,7 +330,11 @@ class Variable(Common):
elt, elt,
text, text,
objectspace, objectspace,
providers,
dynamic_path,
): ):
self.providers = providers
self.dynamic_path = dynamic_path
super().__init__(elt, text, objectspace) super().__init__(elt, text, objectspace)
self.object_type = CONVERT_OPTION[elt.type]['opttype'] self.object_type = CONVERT_OPTION[elt.type]['opttype']

View File

@ -0,0 +1,13 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail version="0.10">
<variables>
<family name="general">
<variable name="float" type="float" description="Description" provider="float">
<value>0.527</value>
</variable>
<variable name="float_multi" type="float" description="Description" multi="True">
<value>0.527</value>
</variable>
</family>
</variables>
</rougail>

View File

@ -0,0 +1,12 @@
{
"rougail.general.float": {
"owner": "default",
"value": 0.527
},
"rougail.general.float_multi": {
"owner": "default",
"value": [
0.527
]
}
}

View File

@ -0,0 +1,6 @@
{
"rougail.general.float": 0.527,
"rougail.general.float_multi": [
0.527
]
}

View File

@ -0,0 +1,12 @@
{
"rougail.general.float": {
"owner": "default",
"value": 0.527
},
"rougail.general.float_multi": {
"owner": "default",
"value": [
0.527
]
}
}

View File

@ -0,0 +1,22 @@
from importlib.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
class func:
pass
_loader = _SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
_spec = _spec_from_loader(_loader.name, _loader)
_func = _module_from_spec(_spec)
_loader.exec_module(_func)
for function in dir(_func):
if function.startswith('_'):
continue
setattr(func, function, getattr(_func, function))
try:
from tiramisu3 import *
except:
from tiramisu import *
option_3 = FloatOption(name="float", doc="Description", default=0.527, properties=frozenset({"mandatory", "normal"}))
option_4 = FloatOption(name="float_multi", doc="Description", multi=True, default=[0.527], default_multi=0.527, properties=frozenset({"mandatory", "normal"}))
option_2 = OptionDescription(name="general", doc="general", children=[option_3, option_4], properties=frozenset({"normal"}))
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])
option_0.impl_set_information('provider:float', "rougail.general.float")

View File

@ -0,0 +1,14 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail version="0.10">
<variables>
<family name="general">
<variable name="varname" type="string" description="No change" multi="True">
<value>val1</value>
<value>val2</value>
</variable>
</family>
<family name="dyn" dynamic="varname">
<variable name="vardyn" type="string" description="No change" provider="dyn"/>
</family>
</variables>
</rougail>

View File

@ -0,0 +1,17 @@
{
"rougail.general.varname": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.dynval1.vardynval1": {
"owner": "default",
"value": null
},
"rougail.dynval2.vardynval2": {
"owner": "default",
"value": null
}
}

View File

@ -0,0 +1,8 @@
{
"rougail.general.varname": [
"val1",
"val2"
],
"rougail.dynval1.vardynval1": null,
"rougail.dynval2.vardynval2": null
}

View File

@ -0,0 +1,17 @@
{
"rougail.general.varname": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.dynval1.vardynval1": {
"owner": "default",
"value": null
},
"rougail.dynval2.vardynval2": {
"owner": "default",
"value": null
}
}

View File

@ -0,0 +1,24 @@
from importlib.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
class func:
pass
_loader = _SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
_spec = _spec_from_loader(_loader.name, _loader)
_func = _module_from_spec(_spec)
_loader.exec_module(_func)
for function in dir(_func):
if function.startswith('_'):
continue
setattr(func, function, getattr(_func, function))
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = StrOption(name="varname", doc="No change", multi=True, default=['val1', 'val2'], default_multi="val1", properties=frozenset({"mandatory", "normal"}))
option_2 = OptionDescription(name="general", doc="general", children=[option_3], properties=frozenset({"normal"}))
option_5 = StrOption(name="vardyn", doc="No change", properties=frozenset({"normal"}))
option_4 = ConvertDynOptionDescription(name="dyn", doc="dyn", suffixes=Calculation(func.calc_value, Params((ParamOption(option_3, notraisepropertyerror=True)))), children=[option_5], properties=frozenset({"normal"}))
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2, option_4])
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])
option_0.impl_set_information('provider:dyn', "rougail.dyn{suffix}.vardyn{suffix}")