Merge branch 'master' into develop
This commit is contained in:
commit
f65e772b39
|
@ -1,5 +1,5 @@
|
||||||
from .loader import load
|
#from .loader import load
|
||||||
from .objspace import CreoleObjSpace
|
from .objspace import CreoleObjSpace
|
||||||
from .annotator import modes
|
from .annotator import modes
|
||||||
|
|
||||||
__ALL__ = ('load', 'CreoleObjSpace', 'modes')
|
__ALL__ = ('CreoleObjSpace', 'modes')
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from os.path import join, basename
|
from os.path import join, basename
|
||||||
|
@ -9,8 +10,7 @@ import imp
|
||||||
|
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
from .error import CreoleDictConsistencyError
|
from .error import DictConsistencyError
|
||||||
from .xmlreflector import HIGH_COMPATIBILITY
|
|
||||||
|
|
||||||
#mode order is important
|
#mode order is important
|
||||||
modes_level = ('basic', 'normal', 'expert')
|
modes_level = ('basic', 'normal', 'expert')
|
||||||
|
@ -20,25 +20,9 @@ class Mode(object):
|
||||||
def __init__(self, name, level):
|
def __init__(self, name, level):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.level = level
|
self.level = level
|
||||||
|
|
||||||
def __cmp__(self, other):
|
|
||||||
return cmp(self.level, other.level)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.level == other.level
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
return self.level != other.level
|
|
||||||
|
|
||||||
def __gt__(self, other):
|
def __gt__(self, other):
|
||||||
return other.level < self.level
|
return other.level < self.level
|
||||||
|
|
||||||
def __ge__(self, other):
|
|
||||||
return not self.level < other.level
|
|
||||||
|
|
||||||
def __le__(self, other):
|
|
||||||
return not other.level < self.level
|
|
||||||
|
|
||||||
|
|
||||||
def mode_factory():
|
def mode_factory():
|
||||||
mode_obj = {}
|
mode_obj = {}
|
||||||
|
@ -49,11 +33,12 @@ def mode_factory():
|
||||||
|
|
||||||
modes = mode_factory()
|
modes = mode_factory()
|
||||||
|
|
||||||
|
|
||||||
# a CreoleObjSpace's attribute has some annotations
|
# a CreoleObjSpace's attribute has some annotations
|
||||||
# that shall not be present in the exported (flatened) XML
|
# that shall not be present in the exported (flatened) XML
|
||||||
ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace',
|
ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace',
|
||||||
'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership',
|
'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership',
|
||||||
'level', 'submulti') # , '_real_container')
|
'level') # , '_real_container')
|
||||||
ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group')
|
ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group')
|
||||||
|
|
||||||
FORCE_CHOICE = {'oui/non': ['oui', 'non'],
|
FORCE_CHOICE = {'oui/non': ['oui', 'non'],
|
||||||
|
@ -71,212 +56,235 @@ KEY_TYPE = {'variable': 'symlink',
|
||||||
'URLOption': 'web_address',
|
'URLOption': 'web_address',
|
||||||
'FilenameOption': 'filename'}
|
'FilenameOption': 'filename'}
|
||||||
|
|
||||||
TYPE_PARAM_CHECK = ('string', 'python', 'eole', 'variable')
|
TYPE_PARAM_CHECK = ('string', 'python', 'variable')
|
||||||
TYPE_PARAM_CONDITION = ('string', 'python', 'number', 'eole', 'variable')
|
TYPE_PARAM_CONDITION = ('string', 'python', 'number', 'variable')
|
||||||
TYPE_PARAM_FILL = ('string', 'eole', 'number', 'context', 'variable')
|
TYPE_PARAM_FILL = ('string', 'number', 'variable')
|
||||||
|
CONVERSION = {'number': int}
|
||||||
ERASED_FAMILY_ACTION_ATTRIBUTES = ('index', 'action')
|
|
||||||
|
|
||||||
FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
|
FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
|
||||||
|
|
||||||
|
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
|
||||||
|
'force_store_value', 'disabled', 'mandatory')
|
||||||
|
CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']}
|
||||||
|
|
||||||
|
RENAME_ATTIBUTES = {'description': 'doc'}
|
||||||
|
INTERNAL_FUNCTIONS = ['valid_enum', 'valid_in_network', 'valid_differ', 'valid_entier']
|
||||||
|
|
||||||
|
class SpaceAnnotator:
|
||||||
|
"""Transformations applied on a CreoleObjSpace instance
|
||||||
|
"""
|
||||||
|
def __init__(self, objectspace, eosfunc_file):
|
||||||
|
self.objectspace = objectspace
|
||||||
|
GroupAnnotator(objectspace)
|
||||||
|
ServiceAnnotator(objectspace)
|
||||||
|
VariableAnnotator(objectspace)
|
||||||
|
ConstraintAnnotator(objectspace,
|
||||||
|
eosfunc_file,
|
||||||
|
)
|
||||||
|
FamilyAnnotator(objectspace)
|
||||||
|
PropertyAnnotator(objectspace)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAnnotator:
|
||||||
|
def __init__(self,
|
||||||
|
objectspace,
|
||||||
|
):
|
||||||
|
self.objectspace = objectspace
|
||||||
|
if not hasattr(self.objectspace.space, 'constraints') or not hasattr(self.objectspace.space.constraints, 'group'):
|
||||||
|
return
|
||||||
|
self.convert_groups()
|
||||||
|
|
||||||
|
def convert_groups(self): # pylint: disable=C0111
|
||||||
|
for group in self.objectspace.space.constraints.group:
|
||||||
|
leader_fullname = group.leader
|
||||||
|
leader_family_name = self.objectspace.paths.get_variable_family_name(leader_fullname)
|
||||||
|
leader_name = self.objectspace.paths.get_variable_name(leader_fullname)
|
||||||
|
namespace = self.objectspace.paths.get_variable_namespace(leader_fullname)
|
||||||
|
if '.' not in leader_fullname:
|
||||||
|
leader_fullname = '.'.join([namespace, leader_family_name, leader_fullname])
|
||||||
|
follower_names = list(group.follower.keys())
|
||||||
|
has_a_leader = False
|
||||||
|
ori_leader_family = self.objectspace.paths.get_family_obj(leader_fullname.rsplit('.', 1)[0])
|
||||||
|
for variable in list(ori_leader_family.variable.values()):
|
||||||
|
if has_a_leader:
|
||||||
|
# it's a follower
|
||||||
|
self.manage_follower(namespace,
|
||||||
|
leader_family_name,
|
||||||
|
variable,
|
||||||
|
leader_name,
|
||||||
|
follower_names,
|
||||||
|
leader_space,
|
||||||
|
leader_is_hidden,
|
||||||
|
)
|
||||||
|
ori_leader_family.variable.pop(variable.name)
|
||||||
|
if follower_names == []:
|
||||||
|
# no more follower
|
||||||
|
break
|
||||||
|
elif variable.name == leader_name:
|
||||||
|
# it's a leader
|
||||||
|
if isinstance(variable, self.objectspace.Leadership):
|
||||||
|
# append follower to an existed leadership
|
||||||
|
leader_space = variable
|
||||||
|
# if variable.hidden:
|
||||||
|
# leader_is_hidden = True
|
||||||
|
else:
|
||||||
|
leader_space = self.objectspace.Leadership()
|
||||||
|
leader_is_hidden = self.manage_leader(leader_space,
|
||||||
|
leader_family_name,
|
||||||
|
leader_name,
|
||||||
|
namespace,
|
||||||
|
variable,
|
||||||
|
group,
|
||||||
|
leader_fullname,
|
||||||
|
)
|
||||||
|
has_a_leader = True
|
||||||
|
else:
|
||||||
|
raise DictConsistencyError(_('cannot found followers {}').format(follower_names))
|
||||||
|
del self.objectspace.space.constraints.group
|
||||||
|
|
||||||
|
def manage_leader(self,
|
||||||
|
leader_space: 'Leadership',
|
||||||
|
leader_family_name: str,
|
||||||
|
leader_name: str,
|
||||||
|
namespace: str,
|
||||||
|
variable: 'Variable',
|
||||||
|
group: 'Group',
|
||||||
|
leader_fullname: str,
|
||||||
|
) -> None:
|
||||||
|
# manage leader's variable
|
||||||
|
if variable.multi is not True:
|
||||||
|
raise DictConsistencyError(_('the variable {} in a group must be multi').format(variable.name))
|
||||||
|
leader_space.variable = []
|
||||||
|
leader_space.name = leader_name
|
||||||
|
leader_space.hidden = variable.hidden
|
||||||
|
if variable.hidden:
|
||||||
|
leader_is_hidden = True
|
||||||
|
variable.frozen = True
|
||||||
|
variable.force_default_on_freeze = True
|
||||||
|
else:
|
||||||
|
leader_is_hidden = False
|
||||||
|
variable.hidden = None
|
||||||
|
if hasattr(group, 'description'):
|
||||||
|
leader_space.doc = group.description
|
||||||
|
elif hasattr(variable, 'description'):
|
||||||
|
leader_space.doc = variable.description
|
||||||
|
else:
|
||||||
|
leader_space.doc = variable.name
|
||||||
|
leader_path = namespace + '.' + leader_family_name + '.' + leader_name
|
||||||
|
self.objectspace.paths.add_family(namespace,
|
||||||
|
leader_path,
|
||||||
|
leader_space,
|
||||||
|
)
|
||||||
|
leader_family = self.objectspace.space.variables[namespace].family[leader_family_name]
|
||||||
|
leader_family.variable[leader_name] = leader_space
|
||||||
|
leader_space.variable.append(variable)
|
||||||
|
self.objectspace.paths.set_leader(namespace,
|
||||||
|
leader_family_name,
|
||||||
|
leader_name,
|
||||||
|
leader_name,
|
||||||
|
)
|
||||||
|
leader_space.path = leader_fullname
|
||||||
|
return leader_is_hidden
|
||||||
|
|
||||||
|
def manage_follower(self,
|
||||||
|
namespace: str,
|
||||||
|
leader_family_name: str,
|
||||||
|
variable: 'Variable',
|
||||||
|
leader_name: str,
|
||||||
|
follower_names: List[str],
|
||||||
|
leader_space: 'Leadership',
|
||||||
|
leader_is_hidden: bool,
|
||||||
|
) -> None:
|
||||||
|
if variable.name != follower_names[0]:
|
||||||
|
raise DictConsistencyError(_('cannot found this follower {}').format(follower_names[0]))
|
||||||
|
follower_names.remove(variable.name)
|
||||||
|
if leader_is_hidden:
|
||||||
|
variable.frozen = True
|
||||||
|
variable.force_default_on_freeze = True
|
||||||
|
leader_space.variable.append(variable) # pylint: disable=E1101
|
||||||
|
self.objectspace.paths.set_leader(namespace,
|
||||||
|
leader_family_name,
|
||||||
|
variable.name,
|
||||||
|
leader_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ServiceAnnotator:
|
class ServiceAnnotator:
|
||||||
"""Manage service's object
|
"""Manage service's object
|
||||||
"""
|
for example::
|
||||||
def __init__(self, objectspace):
|
<services>
|
||||||
self.space = objectspace.space
|
<service name="test">
|
||||||
self.paths = objectspace.paths
|
|
||||||
self.objectspace = objectspace
|
|
||||||
"""for example::
|
|
||||||
<service_access service='ntp'>
|
<service_access service='ntp'>
|
||||||
<port protocol='udp' service_accesslist='ntp_udp'>123</port>
|
<port protocol='udp' service_accesslist='ntp_udp'>123</port>
|
||||||
<tcpwrapper>ntpd</tcpwrapper>
|
|
||||||
</service_access>
|
</service_access>
|
||||||
|
</service>
|
||||||
|
</services>
|
||||||
"""
|
"""
|
||||||
self.grouplist_conditions = {}
|
def __init__(self, objectspace):
|
||||||
|
self.objectspace = objectspace
|
||||||
self.convert_services()
|
self.convert_services()
|
||||||
|
|
||||||
def convert_services(self):
|
def convert_services(self):
|
||||||
if hasattr(self.space, 'services'):
|
if not hasattr(self.objectspace.space, 'services'):
|
||||||
if hasattr(self.space.services, 'service'):
|
return
|
||||||
subelts = dict()
|
if not hasattr(self.objectspace.space.services, 'service'):
|
||||||
for idx, service in enumerate(self.space.services.service.values()):
|
del self.objectspace.space.services
|
||||||
family = self.objectspace.family()
|
return
|
||||||
family.name = 'service{}'.format(idx)
|
self.objectspace.space.services.hidden = True
|
||||||
family.doc = service.name
|
self.objectspace.space.services.name = 'services'
|
||||||
family.family = OrderedDict()
|
self.objectspace.space.services.doc = 'services'
|
||||||
self.convert_service_to_family(family.name, family.family, service)
|
families = {}
|
||||||
setattr(self.space.services, family.name, family)
|
for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
|
||||||
del self.space.services.service
|
service = self.objectspace.space.services.service[service_name]
|
||||||
else:
|
new_service = self.objectspace.service()
|
||||||
del self.space.services
|
|
||||||
|
|
||||||
def convert_service_to_family(self, service_name, service_family, service):
|
|
||||||
for elttype, values in vars(service).items():
|
for elttype, values in vars(service).items():
|
||||||
if elttype in ['name', 'index']:
|
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
|
||||||
|
setattr(new_service, elttype, values)
|
||||||
continue
|
continue
|
||||||
family = self.objectspace.family()
|
eltname = elttype + 's'
|
||||||
family.name = elttype + 's'
|
path = '.'.join(['services', service_name, eltname])
|
||||||
|
family = self.gen_family(eltname,
|
||||||
|
path,
|
||||||
|
)
|
||||||
if isinstance(values, dict):
|
if isinstance(values, dict):
|
||||||
values = list(values.values())
|
values = list(values.values())
|
||||||
family.family = self.convert_subelement_service(elttype,
|
family.family = self.make_group_from_elts(service_name,
|
||||||
|
elttype,
|
||||||
values,
|
values,
|
||||||
'services.{}.{}'.format(service_name, family.name))
|
path,
|
||||||
family.mode = None
|
)
|
||||||
service_family[family.name] = family
|
setattr(new_service, elttype, family)
|
||||||
|
new_service.doc = new_service.name
|
||||||
|
families[service_name] = new_service
|
||||||
|
self.objectspace.space.services.service = families
|
||||||
|
|
||||||
def convert_subelement_service(self, name, elts, path):
|
def gen_family(self,
|
||||||
families = []
|
name,
|
||||||
new_elts = self._reorder_elts(name, elts, True)
|
path,
|
||||||
for index, elt_info in enumerate(new_elts):
|
):
|
||||||
elt = elt_info['elt']
|
|
||||||
elt_name = elt_info['elt_name']
|
|
||||||
|
|
||||||
# try to launch _update_xxxx() function
|
|
||||||
update_elt = '_update_' + elt_name
|
|
||||||
if hasattr(self, update_elt):
|
|
||||||
getattr(self, update_elt)(elt, index, path)
|
|
||||||
variables = []
|
|
||||||
subpath = '{}.{}{}'.format(path, name, index)
|
|
||||||
listname = '{}list'.format(name)
|
|
||||||
activate_path = '.'.join([subpath, 'activate'])
|
|
||||||
if elt in self.grouplist_conditions:
|
|
||||||
# FIXME transformer le activate qui disparait en boolean
|
|
||||||
self.objectspace.list_conditions.setdefault(listname,
|
|
||||||
{}).setdefault(self.grouplist_conditions[elt],
|
|
||||||
[]).append(activate_path)
|
|
||||||
for key in dir(elt):
|
|
||||||
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES:
|
|
||||||
continue
|
|
||||||
value = getattr(elt, key)
|
|
||||||
if isinstance(value, list):
|
|
||||||
continue
|
|
||||||
if key == 'service':
|
|
||||||
value = value.name
|
|
||||||
if key == listname:
|
|
||||||
self.objectspace.list_conditions.setdefault(listname,
|
|
||||||
{}).setdefault(
|
|
||||||
value,
|
|
||||||
[]).append(activate_path)
|
|
||||||
continue
|
|
||||||
if key == 'name':
|
|
||||||
true_key = elt_name
|
|
||||||
else:
|
|
||||||
true_key = key
|
|
||||||
if true_key in self.objectspace.booleans_attributs:
|
|
||||||
type_ = 'boolean'
|
|
||||||
else:
|
|
||||||
type_ = 'string'
|
|
||||||
dtd_key_type = true_key + '_type'
|
|
||||||
|
|
||||||
if hasattr(elt, dtd_key_type):
|
|
||||||
type_ = KEY_TYPE[getattr(elt, dtd_key_type)]
|
|
||||||
multi = isinstance(value, list)
|
|
||||||
variables.append(self._generate_element(elt_name,
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
type_,
|
|
||||||
subpath,
|
|
||||||
multi))
|
|
||||||
# FIXME ne devrait pas etre True par défaut
|
|
||||||
variables.append(self._generate_element(name, 'activate', True, 'boolean', subpath))
|
|
||||||
family = self.objectspace.family()
|
family = self.objectspace.family()
|
||||||
family.name = '{}{}'.format(name, index)
|
family.name = normalize_family(name)
|
||||||
family.variable = variables
|
family.doc = name
|
||||||
family.mode = None
|
family.mode = None
|
||||||
self.paths.append('family', subpath, 'services', creoleobj=family)
|
self.objectspace.paths.add_family('services',
|
||||||
families.append(family)
|
path,
|
||||||
return families
|
family,
|
||||||
|
)
|
||||||
|
return family
|
||||||
|
|
||||||
def _generate_element(self, eltname, name, value, type_, subpath, multi=False):
|
def make_group_from_elts(self,
|
||||||
var_data = {'name': name, 'doc': '', 'value': value,
|
service_name,
|
||||||
'auto_freeze': False, 'mode': None, 'multi': multi}
|
name,
|
||||||
values = None
|
elts,
|
||||||
if type_ == 'string':
|
path,
|
||||||
values = self.objectspace.forced_choice_option.get(eltname, {}).get(name)
|
):
|
||||||
if values is not None:
|
|
||||||
type_ = 'choice'
|
|
||||||
var_data['type'] = type_
|
|
||||||
|
|
||||||
variable = self.objectspace.variable()
|
|
||||||
variable.mandatory = True
|
|
||||||
for key, value in var_data.items():
|
|
||||||
if key == 'value':
|
|
||||||
if value is None:
|
|
||||||
continue
|
|
||||||
if type_ == 'symlink':
|
|
||||||
key = 'opt'
|
|
||||||
else:
|
|
||||||
# Value is a list of objects
|
|
||||||
if not multi:
|
|
||||||
val = self.objectspace.value()
|
|
||||||
val.name = value
|
|
||||||
value = [val]
|
|
||||||
else:
|
|
||||||
value_list = []
|
|
||||||
for valiter in value:
|
|
||||||
val = self.objectspace.value()
|
|
||||||
val.name = valiter.name
|
|
||||||
value_list.append(val)
|
|
||||||
value = value_list
|
|
||||||
if key == 'doc' and type_ == 'symlink':
|
|
||||||
continue
|
|
||||||
setattr(variable, key, value)
|
|
||||||
if values is not None:
|
|
||||||
choices = []
|
|
||||||
for value in values:
|
|
||||||
choice = self.objectspace.choice()
|
|
||||||
choice.name = value
|
|
||||||
choices.append(choice)
|
|
||||||
variable.choice = choices
|
|
||||||
path = '{}.{}'.format(subpath, name)
|
|
||||||
self.paths.append('variable', path, 'services', 'service', variable)
|
|
||||||
return variable
|
|
||||||
|
|
||||||
def _update_file(self, file_, index, service_path):
|
|
||||||
if file_.file_type == "UnicodeOption":
|
|
||||||
if not hasattr(file_, 'source'):
|
|
||||||
file_.source = basename(file_.name)
|
|
||||||
elif not hasattr(file_, 'source'):
|
|
||||||
raise CreoleDictConsistencyError(_('attribute source mandatory for file with variable name '
|
|
||||||
'for {}').format(file_.name))
|
|
||||||
|
|
||||||
def _reorder_elts(self, name, elts, duplicate_list):
|
|
||||||
"""Reorders by index the elts
|
|
||||||
"""
|
|
||||||
dict_elts = OrderedDict()
|
|
||||||
# reorder elts by index
|
|
||||||
new_elts = {}
|
|
||||||
not_indexed = []
|
|
||||||
for elt in elts:
|
|
||||||
idx = elt.index
|
|
||||||
new_elts.setdefault(idx, []).append(elt)
|
|
||||||
idxes = list(new_elts.keys())
|
|
||||||
idxes.sort()
|
|
||||||
elts = not_indexed
|
|
||||||
for idx in idxes:
|
|
||||||
elts.extend(new_elts[idx])
|
|
||||||
for idx, elt in enumerate(elts):
|
|
||||||
elt_added = False
|
|
||||||
for key in dir(elt):
|
|
||||||
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES:
|
|
||||||
continue
|
|
||||||
value = getattr(elt, key)
|
|
||||||
if not elt_added:
|
|
||||||
eltname = elt.name
|
|
||||||
dict_elts.setdefault(eltname, []).append({'elt_name': name, 'elt': elt})
|
|
||||||
|
|
||||||
result_elts = []
|
|
||||||
for elt in dict_elts.values():
|
|
||||||
result_elts.extend(elt)
|
|
||||||
return result_elts
|
|
||||||
|
|
||||||
def make_group_from_elts(self, name, elts, path, duplicate_list):
|
|
||||||
"""Splits each objects into a group (and `OptionDescription`, in tiramisu terms)
|
"""Splits each objects into a group (and `OptionDescription`, in tiramisu terms)
|
||||||
and build elements and its attributes (the `Options` in tiramisu terms)
|
and build elements and its attributes (the `Options` in tiramisu terms)
|
||||||
"""
|
"""
|
||||||
families = []
|
families = []
|
||||||
new_elts = self._reorder_elts(name, elts, duplicate_list)
|
new_elts = self._reorder_elts(name,
|
||||||
|
elts,
|
||||||
|
)
|
||||||
for index, elt_info in enumerate(new_elts):
|
for index, elt_info in enumerate(new_elts):
|
||||||
elt = elt_info['elt']
|
elt = elt_info['elt']
|
||||||
elt_name = elt_info['elt_name']
|
elt_name = elt_info['elt_name']
|
||||||
|
@ -284,241 +292,806 @@ class ServiceAnnotator:
|
||||||
# try to launch _update_xxxx() function
|
# try to launch _update_xxxx() function
|
||||||
update_elt = '_update_' + elt_name
|
update_elt = '_update_' + elt_name
|
||||||
if hasattr(self, update_elt):
|
if hasattr(self, update_elt):
|
||||||
getattr(self, update_elt)(elt, index, path)
|
getattr(self, update_elt)(elt,
|
||||||
variables = []
|
index,
|
||||||
subpath = '{}.{}{}'.format(path, name, index)
|
path,
|
||||||
|
service_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
idx = 0
|
||||||
|
while True:
|
||||||
|
if hasattr(elt, 'source'):
|
||||||
|
c_name = elt.source
|
||||||
|
else:
|
||||||
|
c_name = elt.name
|
||||||
|
if idx:
|
||||||
|
c_name += f'_{idx}'
|
||||||
|
subpath = '{}.{}'.format(path, c_name)
|
||||||
|
if not self.objectspace.paths.family_is_defined(subpath):
|
||||||
|
break
|
||||||
|
idx += 1
|
||||||
|
family = self.gen_family(c_name, subpath)
|
||||||
|
family.variable = []
|
||||||
listname = '{}list'.format(name)
|
listname = '{}list'.format(name)
|
||||||
activate_path = '.'.join([subpath, 'activate'])
|
activate_path = '.'.join([subpath, 'activate'])
|
||||||
if elt in self.grouplist_conditions:
|
|
||||||
# FIXME transformer le activate qui disparait en boolean
|
|
||||||
self.objectspace.list_conditions.setdefault(listname,
|
|
||||||
{}).setdefault(self.grouplist_conditions[elt],
|
|
||||||
[]).append(activate_path)
|
|
||||||
for key in dir(elt):
|
for key in dir(elt):
|
||||||
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES:
|
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES:
|
||||||
continue
|
continue
|
||||||
value = getattr(elt, key)
|
value = getattr(elt, key)
|
||||||
if isinstance(value, list) and duplicate_list:
|
|
||||||
# FIXME plusieurs fichier si calculé !
|
|
||||||
continue
|
|
||||||
if key == listname:
|
if key == listname:
|
||||||
self.objectspace.list_conditions.setdefault(listname,
|
self.objectspace.list_conditions.setdefault(listname,
|
||||||
{}).setdefault(
|
{}).setdefault(
|
||||||
value,
|
value,
|
||||||
[]).append(activate_path)
|
[]).append(activate_path)
|
||||||
continue
|
continue
|
||||||
if key in self.objectspace.booleans_attributs:
|
family.variable.append(self._generate_element(elt_name,
|
||||||
type_ = 'boolean'
|
|
||||||
else:
|
|
||||||
type_ = 'string'
|
|
||||||
dtd_key_type = key + '_type'
|
|
||||||
if hasattr(elt, dtd_key_type):
|
|
||||||
type_ = KEY_TYPE[getattr(elt, dtd_key_type)]
|
|
||||||
multi = isinstance(value, list)
|
|
||||||
variables.append(self._generate_element(elt_name,
|
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
type_,
|
elt,
|
||||||
subpath,
|
f'{subpath}.{key}'
|
||||||
multi))
|
))
|
||||||
# FIXME ne devrait pas etre True par défaut
|
# FIXME ne devrait pas etre True par défaut
|
||||||
variables.append(self._generate_element(name, 'activate', True, 'boolean', subpath))
|
# devrait etre un calcule
|
||||||
family = self.objectspace.family()
|
family.variable.append(self._generate_element(elt_name,
|
||||||
family.name = '{}{}'.format(name, index)
|
'activate',
|
||||||
family.variable = variables
|
True,
|
||||||
family.mode = None
|
elt,
|
||||||
self.paths.append('family', subpath, 'services', creoleobj=family)
|
activate_path,
|
||||||
|
))
|
||||||
families.append(family)
|
families.append(family)
|
||||||
return families
|
return families
|
||||||
|
|
||||||
|
def _generate_element(self,
|
||||||
class ActionAnnotator(ServiceAnnotator):
|
elt_name,
|
||||||
def __init__(self, objectspace):
|
key,
|
||||||
self.space = objectspace.space
|
value,
|
||||||
self.paths = objectspace.paths
|
elt,
|
||||||
self.objectspace = objectspace
|
path,
|
||||||
self.grouplist_conditions = {}
|
):
|
||||||
self.convert_family_action()
|
variable = self.objectspace.variable()
|
||||||
|
variable.name = normalize_family(key)
|
||||||
def convert_family_action(self):
|
variable.mode = None
|
||||||
if hasattr(self.space, 'family_action'):
|
if key == 'name':
|
||||||
actions = self.objectspace.family()
|
true_key = elt_name
|
||||||
actions.name = 'actions'
|
|
||||||
actions.mode = None
|
|
||||||
actions.family = []
|
|
||||||
self.space.actions = actions
|
|
||||||
namespaces = []
|
|
||||||
for name, actions in self.space.family_action.items():
|
|
||||||
subpath = 'actions.{}'.format(normalize_family(name))
|
|
||||||
for action in actions.action:
|
|
||||||
namespace = action.namespace
|
|
||||||
if namespace in namespaces:
|
|
||||||
raise CreoleDictConsistencyError(_('only one action allow for {}'
|
|
||||||
'').format(namespace))
|
|
||||||
namespaces.append(namespace)
|
|
||||||
action.name = action.namespace
|
|
||||||
new_actions = self.make_group_from_elts('action', actions.action, subpath, False)
|
|
||||||
family = self.objectspace.family()
|
|
||||||
family.name = actions.name
|
|
||||||
family.family = new_actions
|
|
||||||
family.mode = None
|
|
||||||
variables = []
|
|
||||||
for key, value in vars(actions).items():
|
|
||||||
if key not in ERASED_FAMILY_ACTION_ATTRIBUTES:
|
|
||||||
variables.append(self._generate_element('action', key, value, 'string',
|
|
||||||
subpath))
|
|
||||||
family.variable = variables
|
|
||||||
self.space.actions.family.append(family)
|
|
||||||
del self.space.family_action
|
|
||||||
|
|
||||||
|
|
||||||
class SpaceAnnotator(object):
|
|
||||||
"""Transformations applied on a CreoleObjSpace instance
|
|
||||||
"""
|
|
||||||
def __init__(self, objectspace, eosfunc_file):
|
|
||||||
self.paths = objectspace.paths
|
|
||||||
self.space = objectspace.space
|
|
||||||
self.objectspace = objectspace
|
|
||||||
self.valid_enums = {}
|
|
||||||
self.force_value = {}
|
|
||||||
self.has_calc = []
|
|
||||||
self.force_no_value = []
|
|
||||||
self.force_not_mandatory = []
|
|
||||||
if eosfunc_file:
|
|
||||||
self.eosfunc = imp.load_source('eosfunc', eosfunc_file)
|
|
||||||
else:
|
else:
|
||||||
self.eosfunc = None
|
true_key = key
|
||||||
if HIGH_COMPATIBILITY:
|
dtd_key_type = true_key + '_type'
|
||||||
self.default_has_no_value = []
|
if key == 'activate':
|
||||||
self.has_frozen_if_in_condition = []
|
type_ = 'boolean'
|
||||||
self.default_variable_options()
|
elif hasattr(elt, dtd_key_type):
|
||||||
self.variable_submulti()
|
type_ = KEY_TYPE[getattr(elt, dtd_key_type)]
|
||||||
|
elif key in self.objectspace.booleans_attributs:
|
||||||
|
type_ = 'boolean'
|
||||||
|
else:
|
||||||
|
type_ = 'string'
|
||||||
|
variable.type = type_
|
||||||
|
if type_ == 'symlink':
|
||||||
|
variable.opt = self.objectspace.paths.get_variable_path(value,
|
||||||
|
'services',
|
||||||
|
)
|
||||||
|
# variable.opt = value
|
||||||
|
variable.multi = None
|
||||||
|
else:
|
||||||
|
variable.doc = key
|
||||||
|
val = self.objectspace.value()
|
||||||
|
val.type = type_
|
||||||
|
val.name = value
|
||||||
|
variable.value = [val]
|
||||||
|
self.objectspace.paths.add_variable('services',
|
||||||
|
path,
|
||||||
|
'service',
|
||||||
|
False,
|
||||||
|
variable,
|
||||||
|
)
|
||||||
|
return variable
|
||||||
|
|
||||||
|
def _reorder_elts(self,
|
||||||
|
name,
|
||||||
|
elts,
|
||||||
|
):
|
||||||
|
"""Reorders by index the elts
|
||||||
|
"""
|
||||||
|
new_elts = {}
|
||||||
|
# reorder elts by index
|
||||||
|
for idx, elt in enumerate(elts):
|
||||||
|
new_elts.setdefault(idx, []).append(elt)
|
||||||
|
idxes = list(new_elts.keys())
|
||||||
|
idxes.sort()
|
||||||
|
result_elts = []
|
||||||
|
for idx in idxes:
|
||||||
|
for elt in new_elts[idx]:
|
||||||
|
result_elts.append({'elt_name': name, 'elt': elt})
|
||||||
|
return result_elts
|
||||||
|
|
||||||
|
def _update_override(self,
|
||||||
|
file_,
|
||||||
|
index,
|
||||||
|
service_path,
|
||||||
|
service_name,
|
||||||
|
):
|
||||||
|
file_.name = f'/systemd/system/{service_name}.service.d/rougail.conf'
|
||||||
|
# retrieve default value from File object
|
||||||
|
for attr in ['owner', 'group', 'mode']:
|
||||||
|
setattr(file_, attr, getattr(self.objectspace.file, attr))
|
||||||
|
if not hasattr(file_, 'source'):
|
||||||
|
file_.source = f'{service_name}.service'
|
||||||
|
self._update_file(file_,
|
||||||
|
index,
|
||||||
|
service_path,
|
||||||
|
service_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _update_file(self,
|
||||||
|
file_,
|
||||||
|
index,
|
||||||
|
service_path,
|
||||||
|
service_name,
|
||||||
|
):
|
||||||
|
if not hasattr(file_, 'file_type') or file_.file_type == "UnicodeOption":
|
||||||
|
if not hasattr(file_, 'source'):
|
||||||
|
file_.source = basename(file_.name)
|
||||||
|
elif not hasattr(file_, 'source'):
|
||||||
|
raise DictConsistencyError(_('attribute source mandatory for file with variable name '
|
||||||
|
'for {}').format(file_.name))
|
||||||
|
|
||||||
|
|
||||||
|
class VariableAnnotator:
|
||||||
|
def __init__(self,
|
||||||
|
objectspace,
|
||||||
|
):
|
||||||
|
self.objectspace = objectspace
|
||||||
|
self.convert_variable()
|
||||||
|
self.convert_helps()
|
||||||
self.convert_auto_freeze()
|
self.convert_auto_freeze()
|
||||||
self.convert_groups()
|
self.convert_separators()
|
||||||
self.filter_check()
|
|
||||||
self.filter_condition()
|
def convert_variable(self):
|
||||||
self.convert_valid_enums()
|
def _convert_variable(variable,
|
||||||
|
variable_type,
|
||||||
|
):
|
||||||
|
if not hasattr(variable, 'type'):
|
||||||
|
variable.type = 'string'
|
||||||
|
if variable.type != 'symlink' and not hasattr(variable, 'description'):
|
||||||
|
variable.description = variable.name
|
||||||
|
if hasattr(variable, 'value'):
|
||||||
|
for value in variable.value:
|
||||||
|
if not hasattr(value, 'type'):
|
||||||
|
value.type = variable.type
|
||||||
|
value.name = CONVERSION.get(value.type, str)(value.name)
|
||||||
|
for key, value in RENAME_ATTIBUTES.items():
|
||||||
|
setattr(variable, value, getattr(variable, key))
|
||||||
|
setattr(variable, key, None)
|
||||||
|
if variable_type == 'follower':
|
||||||
|
if variable.multi is True:
|
||||||
|
variable.multi = 'submulti'
|
||||||
|
else:
|
||||||
|
variable.multi = True
|
||||||
|
|
||||||
|
def _convert_valid_enum(namespace,
|
||||||
|
variable,
|
||||||
|
path,
|
||||||
|
):
|
||||||
|
if variable.type in FORCE_CHOICE:
|
||||||
|
check = self.objectspace.check()
|
||||||
|
check.name = 'valid_enum'
|
||||||
|
check.target = path
|
||||||
|
check.namespace = namespace
|
||||||
|
param = self.objectspace.param()
|
||||||
|
param.text = str(FORCE_CHOICE[variable.type])
|
||||||
|
check.param = [param]
|
||||||
|
if not hasattr(self.objectspace.space, 'constraints'):
|
||||||
|
self.objectspace.space.constraints = self.objectspace.constraints()
|
||||||
|
self.objectspace.space.constraints.namespace = namespace
|
||||||
|
if not hasattr(self.objectspace.space.constraints, 'check'):
|
||||||
|
self.objectspace.space.constraints.check = []
|
||||||
|
self.objectspace.space.constraints.check.append(check)
|
||||||
|
variable.type = 'string'
|
||||||
|
|
||||||
|
if not hasattr(self.objectspace.space, 'variables'):
|
||||||
|
return
|
||||||
|
for families in self.objectspace.space.variables.values():
|
||||||
|
namespace = families.name
|
||||||
|
if hasattr(families, 'family'):
|
||||||
|
families.doc = families.name
|
||||||
|
for family in families.family.values():
|
||||||
|
family.doc = family.name
|
||||||
|
for key, value in RENAME_ATTIBUTES.items():
|
||||||
|
if hasattr(family, key):
|
||||||
|
setattr(family, value, getattr(family, key))
|
||||||
|
setattr(family, key, None)
|
||||||
|
family.name = normalize_family(family.name)
|
||||||
|
if hasattr(family, 'variable'):
|
||||||
|
for variable in family.variable.values():
|
||||||
|
if isinstance(variable, self.objectspace.Leadership):
|
||||||
|
for idx, follower in enumerate(variable.variable):
|
||||||
|
if idx == 0:
|
||||||
|
variable_type = 'master'
|
||||||
|
else:
|
||||||
|
variable_type = 'follower'
|
||||||
|
path = '{}.{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name, follower.name)
|
||||||
|
_convert_variable(follower,
|
||||||
|
variable_type,
|
||||||
|
)
|
||||||
|
_convert_valid_enum(namespace,
|
||||||
|
follower,
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
path = '{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name)
|
||||||
|
_convert_variable(variable,
|
||||||
|
'variable',
|
||||||
|
)
|
||||||
|
_convert_valid_enum(namespace,
|
||||||
|
variable,
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
|
||||||
|
def convert_helps(self):
|
||||||
|
if not hasattr(self.objectspace.space, 'help'):
|
||||||
|
return
|
||||||
|
helps = self.objectspace.space.help
|
||||||
|
if hasattr(helps, 'variable'):
|
||||||
|
for hlp in helps.variable.values():
|
||||||
|
variable = self.objectspace.paths.get_variable_obj(hlp.name)
|
||||||
|
variable.help = hlp.text
|
||||||
|
if hasattr(helps, 'family'):
|
||||||
|
for hlp in helps.family.values():
|
||||||
|
variable = self.objectspace.paths.get_family_obj(hlp.name)
|
||||||
|
variable.help = hlp.text
|
||||||
|
del self.objectspace.space.help
|
||||||
|
|
||||||
|
def convert_auto_freeze(self): # pylint: disable=C0111
|
||||||
|
def _convert_auto_freeze(variable, namespace):
|
||||||
|
if variable.auto_freeze:
|
||||||
|
new_condition = self.objectspace.condition()
|
||||||
|
new_condition.name = 'auto_hidden_if_not_in'
|
||||||
|
new_condition.namespace = namespace
|
||||||
|
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
|
||||||
|
new_param = self.objectspace.param()
|
||||||
|
new_param.text = 'oui'
|
||||||
|
new_condition.param = [new_param]
|
||||||
|
new_target = self.objectspace.target()
|
||||||
|
new_target.type = 'variable'
|
||||||
|
path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name
|
||||||
|
new_target.name = path
|
||||||
|
new_condition.target = [new_target]
|
||||||
|
if not hasattr(self.objectspace.space.constraints, 'condition'):
|
||||||
|
self.objectspace.space.constraints.condition = []
|
||||||
|
self.objectspace.space.constraints.condition.append(new_condition)
|
||||||
|
if hasattr(self.objectspace.space, 'variables'):
|
||||||
|
for variables in self.objectspace.space.variables.values():
|
||||||
|
if hasattr(variables, 'family'):
|
||||||
|
namespace = variables.name
|
||||||
|
for family in variables.family.values():
|
||||||
|
if hasattr(family, 'variable'):
|
||||||
|
for variable in family.variable.values():
|
||||||
|
if isinstance(variable, self.objectspace.Leadership):
|
||||||
|
for follower in variable.variable:
|
||||||
|
_convert_auto_freeze(follower, namespace)
|
||||||
|
else:
|
||||||
|
_convert_auto_freeze(variable, namespace)
|
||||||
|
|
||||||
|
def convert_separators(self): # pylint: disable=C0111,R0201
|
||||||
|
if not hasattr(self.objectspace.space, 'variables'):
|
||||||
|
return
|
||||||
|
for family in self.objectspace.space.variables.values():
|
||||||
|
if not hasattr(family, 'separators'):
|
||||||
|
continue
|
||||||
|
if hasattr(family.separators, 'separator'):
|
||||||
|
for idx, separator in enumerate(family.separators.separator):
|
||||||
|
option = self.objectspace.paths.get_variable_obj(separator.name)
|
||||||
|
if hasattr(option, 'separator'):
|
||||||
|
subpath = self.objectspace.paths.get_variable_path(separator.name,
|
||||||
|
separator.namespace,
|
||||||
|
)
|
||||||
|
raise DictConsistencyError(_('{} already has a separator').format(subpath))
|
||||||
|
option.separator = separator.text
|
||||||
|
del family.separators
|
||||||
|
|
||||||
|
|
||||||
|
class ConstraintAnnotator:
|
||||||
|
def __init__(self,
|
||||||
|
objectspace,
|
||||||
|
eosfunc_file,
|
||||||
|
):
|
||||||
|
if not hasattr(objectspace.space, 'constraints'):
|
||||||
|
return
|
||||||
|
self.objectspace = objectspace
|
||||||
|
self.eosfunc = imp.load_source('eosfunc', eosfunc_file)
|
||||||
|
self.valid_enums = {}
|
||||||
|
if hasattr(self.objectspace.space.constraints, 'check'):
|
||||||
|
self.check_check()
|
||||||
|
self.check_replace_text()
|
||||||
|
self.check_valid_enum()
|
||||||
|
self.check_change_warning()
|
||||||
self.convert_check()
|
self.convert_check()
|
||||||
self.convert_autofill()
|
if hasattr(self.objectspace.space.constraints, 'condition'):
|
||||||
|
self.check_params_target()
|
||||||
|
self.filter_targets()
|
||||||
|
self.convert_xxxlist_to_variable()
|
||||||
|
self.check_condition_fallback_optional()
|
||||||
|
self.check_choice_option_condition()
|
||||||
|
self.remove_condition_with_empty_target()
|
||||||
|
self.convert_condition()
|
||||||
|
if hasattr(self.objectspace.space.constraints, 'fill'):
|
||||||
|
self.convert_fill()
|
||||||
|
self.remove_constraints()
|
||||||
|
|
||||||
|
def check_check(self):
|
||||||
|
remove_indexes = []
|
||||||
|
functions = dir(self.eosfunc)
|
||||||
|
functions.extend(INTERNAL_FUNCTIONS)
|
||||||
|
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
|
||||||
|
if not check.name in functions:
|
||||||
|
raise DictConsistencyError(_('cannot find check function {}').format(check.name))
|
||||||
|
if hasattr(check, 'param'):
|
||||||
|
param_option_indexes = []
|
||||||
|
for idx, param in enumerate(check.param):
|
||||||
|
if param.type not in TYPE_PARAM_CHECK:
|
||||||
|
raise DictConsistencyError(_('cannot use {} type as a param in check for {}').format(param.type, check.target))
|
||||||
|
if param.type == 'variable' and not self.objectspace.paths.path_is_defined(param.text):
|
||||||
|
if param.optional is True:
|
||||||
|
param_option_indexes.append(idx)
|
||||||
|
else:
|
||||||
|
raise DictConsistencyError(_(f'unknown param {param.text} in check'))
|
||||||
|
if param.type != 'variable':
|
||||||
|
param.notraisepropertyerror = None
|
||||||
|
param_option_indexes = list(set(param_option_indexes))
|
||||||
|
param_option_indexes.sort(reverse=True)
|
||||||
|
for idx in param_option_indexes:
|
||||||
|
check.param.pop(idx)
|
||||||
|
if check.param == []:
|
||||||
|
remove_indexes.append(check_idx)
|
||||||
|
remove_indexes.sort(reverse=True)
|
||||||
|
for idx in remove_indexes:
|
||||||
|
del self.objectspace.space.constraints.check[idx]
|
||||||
|
|
||||||
|
def check_replace_text(self):
|
||||||
|
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
|
||||||
|
namespace = check.namespace
|
||||||
|
if hasattr(check, 'param'):
|
||||||
|
for idx, param in enumerate(check.param):
|
||||||
|
if param.type == 'variable':
|
||||||
|
param.text = self.objectspace.paths.get_variable_path(param.text, namespace)
|
||||||
|
check.is_in_leadership = self.objectspace.paths.get_leader(check.target) != None
|
||||||
|
# let's replace the target by the path
|
||||||
|
check.target = self.objectspace.paths.get_variable_path(check.target, namespace)
|
||||||
|
|
||||||
|
def check_valid_enum(self):
|
||||||
|
remove_indexes = []
|
||||||
|
for idx, check in enumerate(self.objectspace.space.constraints.check):
|
||||||
|
if check.name == 'valid_enum':
|
||||||
|
if len(check.param) != 1:
|
||||||
|
raise DictConsistencyError(_(f'cannot set more than one param for valid_enum for variable {check.target}'))
|
||||||
|
param = check.param[0]
|
||||||
|
if check.target in self.valid_enums:
|
||||||
|
raise DictConsistencyError(_(f'valid_enum already set for {check.target}'))
|
||||||
|
if param.type not in ['string', 'python', 'number']:
|
||||||
|
raise DictConsistencyError(_(f'unknown type {param.type} for param in valid_enum for {check.target}'))
|
||||||
|
variable = self.objectspace.paths.get_variable_obj(check.target)
|
||||||
|
values = self.load_params_in_validenum(param,
|
||||||
|
variable.name,
|
||||||
|
variable.type,
|
||||||
|
)
|
||||||
|
self.valid_enums[check.target] = {'type': param.type,
|
||||||
|
'values': values}
|
||||||
|
self._set_valid_enum(variable,
|
||||||
|
values,
|
||||||
|
variable.type,
|
||||||
|
)
|
||||||
|
remove_indexes.append(idx)
|
||||||
|
remove_indexes.sort(reverse=True)
|
||||||
|
for idx in remove_indexes:
|
||||||
|
del self.objectspace.space.constraints.check[idx]
|
||||||
|
|
||||||
|
def load_params_in_validenum(self,
|
||||||
|
param,
|
||||||
|
variable_name,
|
||||||
|
variable_type,
|
||||||
|
):
|
||||||
|
if not hasattr(param, 'text') and (param.type == 'python' or param.type == 'number'):
|
||||||
|
raise DictConsistencyError(_(f"All '{param.type}' variables shall be set in order to calculate valid_enum for variable {variable_name}"))
|
||||||
|
if variable_type == 'string' and param.type == 'number':
|
||||||
|
raise DictConsistencyError(_(f'Unconsistency valid_enum type ({param.type}), for variable {variable_name}'))
|
||||||
|
if param.type == 'python':
|
||||||
|
try:
|
||||||
|
values = eval(param.text, {'eosfunc': self.eosfunc, '__builtins__': {'range': range, 'str': str}})
|
||||||
|
except NameError:
|
||||||
|
raise DictConsistencyError(_('The function {} is unknown').format(param.text))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
values = literal_eval(param.text)
|
||||||
|
except ValueError:
|
||||||
|
raise DictConsistencyError(_(f'Cannot load {param.text} in valid_enum'))
|
||||||
|
if not isinstance(values, list):
|
||||||
|
raise DictConsistencyError(_('Function {} shall return a list').format(param.text))
|
||||||
|
for value in values:
|
||||||
|
if variable_type == 'string' and not isinstance(value, str):
|
||||||
|
raise DictConsistencyError(_(f'Cannot load "{param.text}", "{value}" is not a string'))
|
||||||
|
if variable_type == 'number' and not isinstance(value, int):
|
||||||
|
raise DictConsistencyError(_(f'Cannot load "{param.text}", "{value}" is not a number'))
|
||||||
|
return values
|
||||||
|
|
||||||
|
def check_change_warning(self):
|
||||||
|
#convert level to "warnings_only"
|
||||||
|
for check in self.objectspace.space.constraints.check:
|
||||||
|
if check.level == 'warning':
|
||||||
|
check.warnings_only = True
|
||||||
|
else:
|
||||||
|
check.warnings_only = False
|
||||||
|
check.level = None
|
||||||
|
|
||||||
|
def _get_family_variables_from_target(self,
|
||||||
|
target,
|
||||||
|
):
|
||||||
|
if target.type == 'variable':
|
||||||
|
variable = self.objectspace.paths.get_variable_obj(target.name)
|
||||||
|
family = self.objectspace.paths.get_family_obj(target.name.rsplit('.', 1)[0])
|
||||||
|
if isinstance(family, self.objectspace.Leadership) and family.name == variable.name:
|
||||||
|
return family, family.variable
|
||||||
|
return variable, [variable]
|
||||||
|
# it's a family
|
||||||
|
variable = self.objectspace.paths.get_family_obj(target.name)
|
||||||
|
return variable, list(variable.variable.values())
|
||||||
|
|
||||||
|
def check_params_target(self):
|
||||||
|
for condition in self.objectspace.space.constraints.condition:
|
||||||
|
for param in condition.param:
|
||||||
|
if param.type not in TYPE_PARAM_CONDITION:
|
||||||
|
raise DictConsistencyError(_(f'cannot use {param.type} type as a param in a condition'))
|
||||||
|
if not hasattr(condition, 'target'):
|
||||||
|
raise DictConsistencyError(_('target is mandatory in condition'))
|
||||||
|
for target in condition.target:
|
||||||
|
if target.type.endswith('list') and condition.name not in ['disabled_if_in', 'disabled_if_not_in']:
|
||||||
|
raise DictConsistencyError(_(f'target in condition for {target.type} not allow in {condition.name}'))
|
||||||
|
|
||||||
|
def filter_targets(self): # pylint: disable=C0111
|
||||||
|
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||||
|
namespace = condition.namespace
|
||||||
|
for idx, target in enumerate(condition.target):
|
||||||
|
if target.type == 'variable':
|
||||||
|
if condition.source == target.name:
|
||||||
|
raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source))
|
||||||
|
try:
|
||||||
|
target.name = self.objectspace.paths.get_variable_path(target.name, namespace)
|
||||||
|
except DictConsistencyError:
|
||||||
|
# for optional variable
|
||||||
|
pass
|
||||||
|
elif target.type == 'family':
|
||||||
|
try:
|
||||||
|
target.name = self.objectspace.paths.get_family_path(target.name, namespace)
|
||||||
|
except KeyError:
|
||||||
|
raise DictConsistencyError(_('cannot found family {}').format(target.name))
|
||||||
|
|
||||||
|
def convert_xxxlist_to_variable(self): # pylint: disable=C0111
|
||||||
|
# transform *list to variable or family
|
||||||
|
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||||
|
new_targets = []
|
||||||
|
remove_targets = []
|
||||||
|
for target_idx, target in enumerate(condition.target):
|
||||||
|
if target.type.endswith('list'):
|
||||||
|
listname = target.type
|
||||||
|
listvars = self.objectspace.list_conditions.get(listname,
|
||||||
|
{}).get(target.name)
|
||||||
|
if listvars:
|
||||||
|
for listvar in listvars:
|
||||||
|
variable = self.objectspace.paths.get_variable_obj(listvar)
|
||||||
|
type_ = 'variable'
|
||||||
|
new_target = self.objectspace.target()
|
||||||
|
new_target.type = type_
|
||||||
|
new_target.name = listvar
|
||||||
|
new_target.index = target.index
|
||||||
|
new_targets.append(new_target)
|
||||||
|
remove_targets.append(target_idx)
|
||||||
|
remove_targets.sort(reverse=True)
|
||||||
|
for target_idx in remove_targets:
|
||||||
|
condition.target.pop(target_idx)
|
||||||
|
condition.target.extend(new_targets)
|
||||||
|
|
||||||
|
def check_condition_fallback_optional(self):
|
||||||
|
# a condition with a fallback **and** the source variable doesn't exist
|
||||||
|
remove_conditions = []
|
||||||
|
for idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||||
|
# fallback
|
||||||
|
if condition.fallback is True and not self.objectspace.paths.path_is_defined(condition.source):
|
||||||
|
apply_action = False
|
||||||
|
if condition.name in ['disabled_if_in', 'mandatory_if_in', 'hidden_if_in']:
|
||||||
|
apply_action = not condition.force_condition_on_fallback
|
||||||
|
else:
|
||||||
|
apply_action = condition.force_inverse_condition_on_fallback
|
||||||
|
if apply_action:
|
||||||
|
actions = self._get_condition_actions(condition.name)
|
||||||
|
for target in condition.target:
|
||||||
|
leader_or_variable, variables = self._get_family_variables_from_target(target)
|
||||||
|
for action_idx, action in enumerate(actions):
|
||||||
|
if action_idx == 0:
|
||||||
|
setattr(leader_or_variable, action, True)
|
||||||
|
else:
|
||||||
|
for variable in variables:
|
||||||
|
setattr(variable, action, True)
|
||||||
|
remove_conditions.append(idx)
|
||||||
|
continue
|
||||||
|
|
||||||
|
remove_targets = []
|
||||||
|
# optional
|
||||||
|
for idx, target in enumerate(condition.target):
|
||||||
|
if target.optional is True and not self.objectspace.paths.path_is_defined(target.name):
|
||||||
|
remove_targets.append(idx)
|
||||||
|
remove_targets = list(set(remove_targets))
|
||||||
|
remove_targets.sort(reverse=True)
|
||||||
|
for idx in remove_targets:
|
||||||
|
condition.target.pop(idx)
|
||||||
|
remove_conditions = list(set(remove_conditions))
|
||||||
|
remove_conditions.sort(reverse=True)
|
||||||
|
for idx in remove_conditions:
|
||||||
|
self.objectspace.space.constraints.condition.pop(idx)
|
||||||
|
|
||||||
|
def _get_condition_actions(self, condition_name):
|
||||||
|
if condition_name.startswith('disabled_if_'):
|
||||||
|
return ['disabled']
|
||||||
|
elif condition_name.startswith('hidden_if_'):
|
||||||
|
return ['hidden', 'frozen', 'force_default_on_freeze']
|
||||||
|
elif condition_name.startswith('mandatory_if_'):
|
||||||
|
return ['mandatory']
|
||||||
|
elif condition_name == 'auto_hidden_if_not_in':
|
||||||
|
return ['auto_frozen']
|
||||||
|
|
||||||
|
def check_choice_option_condition(self):
|
||||||
|
# remove condition for ChoiceOption that don't have param
|
||||||
|
remove_conditions = []
|
||||||
|
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||||
|
namespace = condition.namespace
|
||||||
|
condition.source = self.objectspace.paths.get_variable_path(condition.source, namespace, allow_source=True)
|
||||||
|
src_variable = self.objectspace.paths.get_variable_obj(condition.source)
|
||||||
|
valid_enum = None
|
||||||
|
if condition.source in self.valid_enums and self.valid_enums[condition.source]['type'] == 'string':
|
||||||
|
valid_enum = self.valid_enums[condition.source]['values']
|
||||||
|
if valid_enum is not None:
|
||||||
|
remove_param = []
|
||||||
|
for param_idx, param in enumerate(condition.param):
|
||||||
|
if param.text not in valid_enum:
|
||||||
|
remove_param.append(param_idx)
|
||||||
|
remove_param.sort(reverse=True)
|
||||||
|
for idx in remove_param:
|
||||||
|
del condition.param[idx]
|
||||||
|
if condition.param == []:
|
||||||
|
remove_targets = []
|
||||||
|
for target in condition.target:
|
||||||
|
leader_or_variable, variables = self._get_family_variables_from_target(target)
|
||||||
|
if condition.name == 'disabled_if_not_in':
|
||||||
|
leader_or_variable.disabled = True
|
||||||
|
elif condition.name == 'hidden_if_not_in':
|
||||||
|
leader_or_variable.hidden = True
|
||||||
|
for variable in variables:
|
||||||
|
variable.frozen = True
|
||||||
|
variable.force_default_on_freeze = True
|
||||||
|
elif condition.name == 'mandatory_if_not_in':
|
||||||
|
variable.mandatory = True
|
||||||
|
remove_targets = list(set(remove_targets))
|
||||||
|
remove_targets.sort(reverse=True)
|
||||||
|
for target_idx in remove_targets:
|
||||||
|
condition.target.pop(target_idx)
|
||||||
|
remove_conditions.append(condition_idx)
|
||||||
|
remove_conditions = list(set(remove_conditions))
|
||||||
|
remove_conditions.sort(reverse=True)
|
||||||
|
for idx in remove_conditions:
|
||||||
|
self.objectspace.space.constraints.condition.pop(idx)
|
||||||
|
|
||||||
|
def remove_condition_with_empty_target(self):
|
||||||
|
remove_conditions = []
|
||||||
|
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
|
||||||
|
if not condition.target:
|
||||||
|
remove_conditions.append(condition_idx)
|
||||||
|
remove_conditions = list(set(remove_conditions))
|
||||||
|
remove_conditions.sort(reverse=True)
|
||||||
|
for idx in remove_conditions:
|
||||||
|
self.objectspace.space.constraints.condition.pop(idx)
|
||||||
|
|
||||||
|
def convert_condition(self):
|
||||||
|
for condition in self.objectspace.space.constraints.condition:
|
||||||
|
inverse = condition.name.endswith('_if_not_in')
|
||||||
|
actions = self._get_condition_actions(condition.name)
|
||||||
|
for param in condition.param:
|
||||||
|
if hasattr(param, 'text'):
|
||||||
|
param = param.text
|
||||||
|
else:
|
||||||
|
param = None
|
||||||
|
for target in condition.target:
|
||||||
|
leader_or_variable, variables = self._get_family_variables_from_target(target)
|
||||||
|
# if option is already disable, do not apply disable_if_in
|
||||||
|
if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True:
|
||||||
|
continue
|
||||||
|
for idx, action in enumerate(actions):
|
||||||
|
prop = self.objectspace.property_()
|
||||||
|
prop.type = 'calculation'
|
||||||
|
prop.inverse = inverse
|
||||||
|
prop.source = condition.source
|
||||||
|
prop.expected = param
|
||||||
|
prop.name = action
|
||||||
|
if idx == 0:
|
||||||
|
if not hasattr(leader_or_variable, 'property'):
|
||||||
|
leader_or_variable.property = []
|
||||||
|
leader_or_variable.property.append(prop)
|
||||||
|
else:
|
||||||
|
for variable in variables:
|
||||||
|
if not hasattr(variable, 'property'):
|
||||||
|
variable.property = []
|
||||||
|
variable.property.append(prop)
|
||||||
|
del self.objectspace.space.constraints.condition
|
||||||
|
|
||||||
|
def _set_valid_enum(self, variable, values, type_):
|
||||||
|
# value for choice's variable is mandatory
|
||||||
|
variable.mandatory = True
|
||||||
|
# build choice
|
||||||
|
variable.choice = []
|
||||||
|
choices = []
|
||||||
|
for value in values:
|
||||||
|
choice = self.objectspace.choice()
|
||||||
|
try:
|
||||||
|
choice.name = CONVERSION.get(type_, str)(value)
|
||||||
|
except:
|
||||||
|
raise DictConsistencyError(_(f'unable to change type of a valid_enum entry "{value}" is not a valid "{type_}" for "{variable.name}"'))
|
||||||
|
if choice.name == '':
|
||||||
|
choice.name = None
|
||||||
|
choices.append(choice.name)
|
||||||
|
choice.type = type_
|
||||||
|
variable.choice.append(choice)
|
||||||
|
if not variable.choice:
|
||||||
|
raise DictConsistencyError(_('empty valid enum is not allowed for variable {}').format(variable.name))
|
||||||
|
# check value or set first choice value has default value
|
||||||
|
if hasattr(variable, 'value'):
|
||||||
|
for value in variable.value:
|
||||||
|
value.type = type_
|
||||||
|
try:
|
||||||
|
cvalue = CONVERSION.get(type_, str)(value.name)
|
||||||
|
except:
|
||||||
|
raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"'))
|
||||||
|
if cvalue not in choices:
|
||||||
|
raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
|
||||||
|
else:
|
||||||
|
new_value = self.objectspace.value()
|
||||||
|
new_value.name = values[0]
|
||||||
|
new_value.type = type_
|
||||||
|
variable.value = [new_value]
|
||||||
|
variable.type = 'choice'
|
||||||
|
|
||||||
|
def convert_check(self):
|
||||||
|
for check in self.objectspace.space.constraints.check:
|
||||||
|
variable = self.objectspace.paths.get_variable_obj(check.target)
|
||||||
|
name = check.name
|
||||||
|
if name == 'valid_entier':
|
||||||
|
if not hasattr(check, 'param'):
|
||||||
|
raise DictConsistencyError(_('{} must have, at least, 1 param').format(name))
|
||||||
|
for param in check.param:
|
||||||
|
if param.type not in ['string', 'number']:
|
||||||
|
raise DictConsistencyError(_(f'param in "valid_entier" must not be a "{param.type}"'))
|
||||||
|
if param.name == 'mini':
|
||||||
|
variable.min_number = int(param.text)
|
||||||
|
elif param.name == 'maxi':
|
||||||
|
variable.max_number = int(param.text)
|
||||||
|
else:
|
||||||
|
raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'))
|
||||||
|
else:
|
||||||
|
check_ = self.objectspace.check()
|
||||||
|
if name == 'valid_differ':
|
||||||
|
name = 'valid_not_equal'
|
||||||
|
elif name == 'valid_network_netmask':
|
||||||
|
params_len = 1
|
||||||
|
if len(check.param) != params_len:
|
||||||
|
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
|
||||||
|
elif name == 'valid_ipnetmask':
|
||||||
|
params_len = 1
|
||||||
|
if len(check.param) != params_len:
|
||||||
|
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
|
||||||
|
name = 'valid_ip_netmask'
|
||||||
|
elif name == 'valid_broadcast':
|
||||||
|
params_len = 2
|
||||||
|
if len(check.param) != params_len:
|
||||||
|
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
|
||||||
|
elif name == 'valid_in_network':
|
||||||
|
params_len = 2
|
||||||
|
if len(check.param) != params_len:
|
||||||
|
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
|
||||||
|
check_.name = name
|
||||||
|
check_.warnings_only = check.warnings_only
|
||||||
|
if hasattr(check, 'param'):
|
||||||
|
check_.param = check.param
|
||||||
|
if not hasattr(variable, 'check'):
|
||||||
|
variable.check = []
|
||||||
|
variable.check.append(check_)
|
||||||
|
del self.objectspace.space.constraints.check
|
||||||
|
|
||||||
|
def convert_fill(self): # pylint: disable=C0111,R0912
|
||||||
|
# sort fill/auto by index
|
||||||
|
fills = {fill.index: fill for idx, fill in enumerate(self.objectspace.space.constraints.fill)}
|
||||||
|
indexes = list(fills.keys())
|
||||||
|
indexes.sort()
|
||||||
|
targets = []
|
||||||
|
eosfunc = dir(self.eosfunc)
|
||||||
|
for idx in indexes:
|
||||||
|
fill = fills[idx]
|
||||||
|
# test if it's redefined calculation
|
||||||
|
if fill.target in targets and not fill.redefine:
|
||||||
|
raise DictConsistencyError(_(f"A fill already exists for the target: {fill.target}"))
|
||||||
|
targets.append(fill.target)
|
||||||
|
#
|
||||||
|
if fill.name not in eosfunc:
|
||||||
|
raise DictConsistencyError(_('cannot find fill function {}').format(fill.name))
|
||||||
|
|
||||||
|
namespace = fill.namespace
|
||||||
|
# let's replace the target by the path
|
||||||
|
fill.target = self.objectspace.paths.get_variable_path(fill.target,
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
|
|
||||||
|
value = self.objectspace.value()
|
||||||
|
value.type = 'calculation'
|
||||||
|
value.name = fill.name
|
||||||
|
if hasattr(fill, 'param'):
|
||||||
|
param_to_delete = []
|
||||||
|
for fill_idx, param in enumerate(fill.param):
|
||||||
|
if param.type not in TYPE_PARAM_FILL:
|
||||||
|
raise DictConsistencyError(_(f'cannot use {param.type} type as a param in a fill/auto'))
|
||||||
|
if param.type != 'string' and not hasattr(param, 'text'):
|
||||||
|
raise DictConsistencyError(_(f"All '{param.type}' variables shall have a value in order to calculate {fill.target}"))
|
||||||
|
if param.type == 'variable':
|
||||||
|
try:
|
||||||
|
param.text, suffix = self.objectspace.paths.get_variable_path(param.text,
|
||||||
|
namespace,
|
||||||
|
with_suffix=True,
|
||||||
|
)
|
||||||
|
if suffix:
|
||||||
|
param.suffix = suffix
|
||||||
|
except DictConsistencyError as err:
|
||||||
|
if param.optional is False:
|
||||||
|
raise err
|
||||||
|
param_to_delete.append(fill_idx)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
param.notraisepropertyerror = None
|
||||||
|
param_to_delete.sort(reverse=True)
|
||||||
|
for param_idx in param_to_delete:
|
||||||
|
fill.param.pop(param_idx)
|
||||||
|
value.param = fill.param
|
||||||
|
variable = self.objectspace.paths.get_variable_obj(fill.target)
|
||||||
|
variable.value = [value]
|
||||||
|
del self.objectspace.space.constraints.fill
|
||||||
|
|
||||||
|
def remove_constraints(self):
|
||||||
|
if hasattr(self.objectspace.space.constraints, 'index'):
|
||||||
|
del self.objectspace.space.constraints.index
|
||||||
|
del self.objectspace.space.constraints.namespace
|
||||||
|
if vars(self.objectspace.space.constraints):
|
||||||
|
raise Exception('constraints again?')
|
||||||
|
del self.objectspace.space.constraints
|
||||||
|
|
||||||
|
|
||||||
|
class FamilyAnnotator:
|
||||||
|
def __init__(self,
|
||||||
|
objectspace,
|
||||||
|
):
|
||||||
|
self.objectspace = objectspace
|
||||||
self.remove_empty_families()
|
self.remove_empty_families()
|
||||||
self.change_variable_mode()
|
self.change_variable_mode()
|
||||||
self.change_family_mode()
|
self.change_family_mode()
|
||||||
self.dynamic_families()
|
self.dynamic_families()
|
||||||
self.filter_separators()
|
|
||||||
self.absolute_path_for_symlink_in_services()
|
|
||||||
self.convert_helps()
|
|
||||||
if hasattr(self.space, 'constraints'):
|
|
||||||
del self.space.constraints.index
|
|
||||||
if vars(self.space.constraints):
|
|
||||||
raise Exception('constraints again?')
|
|
||||||
del self.space.constraints
|
|
||||||
|
|
||||||
def absolute_path_for_symlink_in_services(self):
|
|
||||||
if not hasattr(self.space, 'services'):
|
|
||||||
return
|
|
||||||
families = vars(self.space.services).values()
|
|
||||||
for family in families:
|
|
||||||
if hasattr(family, 'family'):
|
|
||||||
for fam in family.family.values():
|
|
||||||
for fam1 in fam.family:
|
|
||||||
for variable in fam1.variable:
|
|
||||||
if variable.type == 'symlink' and '.' not in variable.name:
|
|
||||||
variable.opt = self.paths.get_variable_path(variable.opt, 'creole')
|
|
||||||
|
|
||||||
def convert_helps(self):
|
|
||||||
# FIXME l'aide doit etre dans la variable!
|
|
||||||
if not hasattr(self.space, 'help'):
|
|
||||||
return
|
|
||||||
helps = self.space.help
|
|
||||||
if hasattr(helps, 'variable'):
|
|
||||||
for hlp in helps.variable.values():
|
|
||||||
variable = self.paths.get_variable_obj(hlp.name)
|
|
||||||
variable.help = hlp.text
|
|
||||||
if hasattr(helps, 'family'):
|
|
||||||
for hlp in helps.family.values():
|
|
||||||
variable = self.paths.get_family_obj(hlp.name)
|
|
||||||
variable.help = hlp.text
|
|
||||||
del self.space.help
|
|
||||||
|
|
||||||
def convert_groups(self): # pylint: disable=C0111
|
|
||||||
if hasattr(self.space, 'constraints'):
|
|
||||||
if hasattr(self.space.constraints, 'group'):
|
|
||||||
for group in self.space.constraints.group:
|
|
||||||
leader_fullname = group.master
|
|
||||||
follower_names = list(group.slave.keys())
|
|
||||||
leader_family_name = self.paths.get_variable_family_name(leader_fullname)
|
|
||||||
namespace = self.paths.get_variable_namespace(leader_fullname)
|
|
||||||
leader_name = self.paths.get_variable_name(leader_fullname)
|
|
||||||
leader_family = self.space.variables[namespace].family[leader_family_name]
|
|
||||||
leader_path = namespace + '.' + leader_family_name
|
|
||||||
is_leader = False
|
|
||||||
for variable in list(leader_family.variable.values()):
|
|
||||||
if isinstance(variable, self.objectspace.Leadership):
|
|
||||||
# append follower to an existed leadership
|
|
||||||
if variable.name == leader_name:
|
|
||||||
leader_space = variable
|
|
||||||
is_leader = True
|
|
||||||
else:
|
|
||||||
if is_leader:
|
|
||||||
if variable.name == follower_names[0]:
|
|
||||||
# followers are multi
|
|
||||||
if not variable.multi:
|
|
||||||
raise CreoleDictConsistencyError(_('the variable {} in a group must be multi or submulti').format(variable.name))
|
|
||||||
follower_names.remove(variable.name)
|
|
||||||
leader_family.variable.pop(variable.name)
|
|
||||||
leader_space.variable.append(variable) # pylint: disable=E1101
|
|
||||||
if namespace == 'creole':
|
|
||||||
variable_fullpath = variable.name
|
|
||||||
else:
|
|
||||||
variable_fullpath = leader_path + '.' + variable.name
|
|
||||||
self.paths.set_leader(variable_fullpath, leader_name)
|
|
||||||
if follower_names == []:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot found this follower {}').format(follower_names[0]))
|
|
||||||
if is_leader is False and variable.name == leader_name:
|
|
||||||
leader_space = self.objectspace.Leadership()
|
|
||||||
leader_space.variable = []
|
|
||||||
leader_space.name = leader_name
|
|
||||||
leader_space.hidden = variable.hidden
|
|
||||||
if hasattr(group, 'description'):
|
|
||||||
leader_space.doc = group.description
|
|
||||||
else:
|
|
||||||
leader_space.doc = variable.description
|
|
||||||
variable.hidden = None
|
|
||||||
self.paths.append('family', leader_path + '.' + leader_name, namespace, creoleobj=leader_space)
|
|
||||||
# manage leader's variable
|
|
||||||
if variable.multi is not True:
|
|
||||||
raise CreoleDictConsistencyError(_('the variable {} in a group must be multi').format(variable.name))
|
|
||||||
leader_family.variable[leader_name] = leader_space
|
|
||||||
leader_space.variable.append(variable) # pylint: disable=E1101
|
|
||||||
self.paths.set_leader(leader_fullname, leader_name)
|
|
||||||
leader_space.path = leader_fullname
|
|
||||||
is_leader = True
|
|
||||||
else:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot found followers {}').format(follower_names))
|
|
||||||
del self.space.constraints.group
|
|
||||||
|
|
||||||
def remove_empty_families(self): # pylint: disable=C0111,R0201
|
def remove_empty_families(self): # pylint: disable=C0111,R0201
|
||||||
if hasattr(self.space, 'variables'):
|
if hasattr(self.objectspace.space, 'variables'):
|
||||||
for family in self.space.variables.values():
|
for family in self.objectspace.space.variables.values():
|
||||||
if hasattr(family, 'family'):
|
if hasattr(family, 'family'):
|
||||||
space = family.family
|
space = family.family
|
||||||
removed_families = []
|
removed_families = []
|
||||||
for family_name, family in space.items():
|
for family_name, family in space.items():
|
||||||
if not hasattr(family, 'variable') or len(family.variable) == 0:
|
if not hasattr(family, 'variable') or len(family.variable) == 0:
|
||||||
removed_families.append(family_name)
|
removed_families.append(family_name)
|
||||||
|
for family_name in removed_families:
|
||||||
del space[family_name]
|
del space[family_name]
|
||||||
# remove help too
|
|
||||||
if hasattr(self.space, 'help') and hasattr(self.space.help, 'family'):
|
|
||||||
for family in self.space.help.family.keys():
|
|
||||||
if family in removed_families:
|
|
||||||
del self.space.help.family[family]
|
|
||||||
|
|
||||||
def change_family_mode(self): # pylint: disable=C0111
|
def change_family_mode(self): # pylint: disable=C0111
|
||||||
if not hasattr(self.space, 'variables'):
|
if not hasattr(self.objectspace.space, 'variables'):
|
||||||
return
|
return
|
||||||
for family in self.space.variables.values():
|
for family in self.objectspace.space.variables.values():
|
||||||
if hasattr(family, 'family'):
|
if hasattr(family, 'family'):
|
||||||
for family in family.family.values():
|
for family in family.family.values():
|
||||||
mode = modes_level[-1]
|
mode = modes_level[-1]
|
||||||
|
@ -534,158 +1107,55 @@ class SpaceAnnotator(object):
|
||||||
family.mode = mode
|
family.mode = mode
|
||||||
|
|
||||||
def dynamic_families(self): # pylint: disable=C0111
|
def dynamic_families(self): # pylint: disable=C0111
|
||||||
if not hasattr(self.space, 'variables'):
|
if not hasattr(self.objectspace.space, 'variables'):
|
||||||
return
|
return
|
||||||
for family in self.space.variables.values():
|
for family in self.objectspace.space.variables.values():
|
||||||
if hasattr(family, 'family'):
|
if hasattr(family, 'family'):
|
||||||
for family in family.family.values():
|
for family in family.family.values():
|
||||||
if 'dynamic' in vars(family):
|
if 'dynamic' in vars(family):
|
||||||
namespace = self.paths.get_variable_namespace(family.dynamic)
|
namespace = self.objectspace.paths.get_variable_namespace(family.dynamic)
|
||||||
varpath = self.paths.get_variable_path(family.dynamic, namespace)
|
varpath = self.objectspace.paths.get_variable_path(family.dynamic, namespace)
|
||||||
family.dynamic = varpath
|
family.dynamic = varpath
|
||||||
|
|
||||||
def _annotate_variable(self, variable, family_mode, path, is_follower=False):
|
def annotate_variable(self, variable, family_mode, path, is_follower=False):
|
||||||
if (HIGH_COMPATIBILITY and variable.type == 'choice' and variable.mode != modes_level[-1] and variable.mandatory is True and path in self.default_has_no_value):
|
|
||||||
variable.mode = modes_level[0]
|
|
||||||
if variable.type == 'choice' and is_follower and family_mode == modes_level[0] and variable.mandatory is True:
|
|
||||||
variable.mode = modes_level[0]
|
|
||||||
# if the variable is mandatory and doesn't have any value
|
# if the variable is mandatory and doesn't have any value
|
||||||
# then the variable's mode is set to 'basic'
|
# then the variable's mode is set to 'basic'
|
||||||
has_value = hasattr(variable, 'value')
|
if not hasattr(variable, 'value') and variable.type == 'boolean':
|
||||||
if (path not in self.has_calc and variable.mandatory is True and
|
new_value = self.objectspace.value()
|
||||||
(not has_value or is_follower) and variable.type != 'choice'):
|
new_value.name = True
|
||||||
variable.mode = modes_level[0]
|
new_value.type = 'boolean'
|
||||||
if has_value:
|
variable.value = [new_value]
|
||||||
if not HIGH_COMPATIBILITY or (not path.startswith('creole.services.') \
|
if hasattr(variable, 'value') and variable.value:
|
||||||
and path not in self.force_no_value and path not in self.force_not_mandatory):
|
has_value = True
|
||||||
|
for value in variable.value:
|
||||||
|
if value.type == 'calculation':
|
||||||
|
has_value = False
|
||||||
|
has_variable = False
|
||||||
|
if hasattr(value, 'param'):
|
||||||
|
for param in value.param:
|
||||||
|
if param.type == 'variable':
|
||||||
|
has_variable = True
|
||||||
|
break
|
||||||
|
if not has_variable:
|
||||||
|
# if one parameter is a variable, let variable choice if it's mandatory
|
||||||
variable.mandatory = True
|
variable.mandatory = True
|
||||||
|
if has_value:
|
||||||
|
# if has value but without any calculation
|
||||||
|
variable.mandatory = True
|
||||||
|
if variable.mandatory is True and (not hasattr(variable, 'value') or is_follower):
|
||||||
|
variable.mode = modes_level[0]
|
||||||
|
if variable.mode != None and modes[variable.mode] < modes[family_mode] and (not is_follower or variable.mode != modes_level[0]):
|
||||||
|
variable.mode = family_mode
|
||||||
if variable.hidden is True:
|
if variable.hidden is True:
|
||||||
variable.frozen = True
|
variable.frozen = True
|
||||||
if not variable.auto_save is True and 'force_default_on_freeze' not in vars(variable):
|
if not variable.auto_save is True and 'force_default_on_freeze' not in vars(variable):
|
||||||
variable.force_default_on_freeze = True
|
variable.force_default_on_freeze = True
|
||||||
if variable.name == 'frozen' and not variable.auto_save is True:
|
|
||||||
variable.force_default_on_freeze = True
|
|
||||||
if variable.mode != None and not is_follower and modes[variable.mode] < modes[family_mode]:
|
|
||||||
variable.mode = family_mode
|
|
||||||
if variable.mode != None and variable.mode != modes_level[0] and modes[variable.mode] < modes[family_mode]:
|
|
||||||
variable.mode = family_mode
|
|
||||||
|
|
||||||
def default_variable_options(self):
|
|
||||||
if hasattr(self.space, 'variables'):
|
|
||||||
for families in self.space.variables.values():
|
|
||||||
if hasattr(families, 'family'):
|
|
||||||
for family in families.family.values():
|
|
||||||
if hasattr(family, 'variable'):
|
|
||||||
for variable in family.variable.values():
|
|
||||||
if not hasattr(variable, 'type'):
|
|
||||||
variable.type = 'string'
|
|
||||||
if variable.type != 'symlink' and not hasattr(variable, 'description'):
|
|
||||||
variable.description = variable.name
|
|
||||||
|
|
||||||
def variable_submulti(self):
|
|
||||||
if hasattr(self.space, 'variables'):
|
|
||||||
for families in self.space.variables.values():
|
|
||||||
if hasattr(families, 'family'):
|
|
||||||
for family in families.family.values():
|
|
||||||
if hasattr(family, 'variable'):
|
|
||||||
for variable in family.variable.values():
|
|
||||||
if variable.submulti:
|
|
||||||
variable.multi = 'submulti'
|
|
||||||
|
|
||||||
def convert_auto_freeze(self): # pylint: disable=C0111
|
|
||||||
if hasattr(self.space, 'variables'):
|
|
||||||
for variables in self.space.variables.values():
|
|
||||||
if hasattr(variables, 'family'):
|
|
||||||
for family in variables.family.values():
|
|
||||||
if hasattr(family, 'variable'):
|
|
||||||
for variable in family.variable.values():
|
|
||||||
if variable.auto_freeze:
|
|
||||||
new_condition = self.objectspace.condition()
|
|
||||||
new_condition.name = 'auto_frozen_if_in'
|
|
||||||
new_condition.namespace = variables.name
|
|
||||||
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
|
|
||||||
new_param = self.objectspace.param()
|
|
||||||
new_param.text = 'oui'
|
|
||||||
new_condition.param = [new_param]
|
|
||||||
new_target = self.objectspace.target()
|
|
||||||
new_target.type = 'variable'
|
|
||||||
if variables.name == 'creole':
|
|
||||||
path = variable.name
|
|
||||||
else:
|
|
||||||
path = variable.namespace + '.' + family.name + '.' + variable.name
|
|
||||||
new_target.name = path
|
|
||||||
new_condition.target = [new_target]
|
|
||||||
if not hasattr(self.space.constraints, 'condition'):
|
|
||||||
self.space.constraints.condition = []
|
|
||||||
self.space.constraints.condition.append(new_condition)
|
|
||||||
|
|
||||||
def _set_valid_enum(self, variable, values, type_):
|
|
||||||
if isinstance(values, list):
|
|
||||||
variable.mandatory = True
|
|
||||||
variable.choice = []
|
|
||||||
choices = []
|
|
||||||
for value in values:
|
|
||||||
choice = self.objectspace.choice()
|
|
||||||
choice.name = str(value)
|
|
||||||
choices.append(choice.name)
|
|
||||||
choice.type = type_
|
|
||||||
variable.choice.append(choice)
|
|
||||||
if not variable.choice:
|
|
||||||
raise CreoleDictConsistencyError(_('empty valid enum is not allowed for variable {}').format(variable.name))
|
|
||||||
if hasattr(variable, 'value'):
|
|
||||||
for value in variable.value:
|
|
||||||
value.type = type_
|
|
||||||
if value.name not in choices:
|
|
||||||
raise CreoleDictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
|
|
||||||
else:
|
|
||||||
new_value = self.objectspace.value()
|
|
||||||
new_value.name = values[0]
|
|
||||||
new_value.type = type_
|
|
||||||
variable.value = [new_value]
|
|
||||||
else:
|
|
||||||
# probe choice
|
|
||||||
variable.choice = values
|
|
||||||
variable.type = 'choice'
|
|
||||||
|
|
||||||
def _convert_valid_enum(self, variable, path):
|
|
||||||
if variable.type in FORCE_CHOICE:
|
|
||||||
if path in self.valid_enums:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot set valid enum for variable with type {}').format(variable.type))
|
|
||||||
self._set_valid_enum(variable, FORCE_CHOICE[variable.type], 'string')
|
|
||||||
if path in self.valid_enums:
|
|
||||||
values = self.valid_enums[path]['values']
|
|
||||||
self._set_valid_enum(variable, values, variable.type)
|
|
||||||
del self.valid_enums[path]
|
|
||||||
if path in self.force_value:
|
|
||||||
new_value = self.objectspace.value()
|
|
||||||
new_value.name = self.force_value[path]
|
|
||||||
variable.value = [new_value]
|
|
||||||
del self.force_value[path]
|
|
||||||
|
|
||||||
def convert_valid_enums(self): # pylint: disable=C0111
|
|
||||||
if not hasattr(self.space, 'variables'):
|
|
||||||
return
|
|
||||||
for variables in self.space.variables.values():
|
|
||||||
namespace = variables.name
|
|
||||||
if hasattr(variables, 'family'):
|
|
||||||
for family in variables.family.values():
|
|
||||||
if hasattr(family, 'variable'):
|
|
||||||
for variable in family.variable.values():
|
|
||||||
if isinstance(variable, self.objectspace.Leadership):
|
|
||||||
for follower in variable.variable:
|
|
||||||
path = '{}.{}.{}.{}'.format(namespace, family.name, variable.name, follower.name)
|
|
||||||
self._convert_valid_enum(follower, path)
|
|
||||||
else:
|
|
||||||
path = '{}.{}.{}'.format(namespace, family.name, variable.name)
|
|
||||||
self._convert_valid_enum(variable, path)
|
|
||||||
# valid_enums must be empty now (all information are store in objects)
|
|
||||||
if self.valid_enums:
|
|
||||||
raise CreoleDictConsistencyError(_('valid_enum sets for unknown variables {}').format(self.valid_enums.keys()))
|
|
||||||
|
|
||||||
def change_variable_mode(self): # pylint: disable=C0111
|
def change_variable_mode(self): # pylint: disable=C0111
|
||||||
if not hasattr(self.space, 'variables'):
|
if not hasattr(self.objectspace.space, 'variables'):
|
||||||
return
|
return
|
||||||
for variables in self.space.variables.values():
|
for variables in self.objectspace.space.variables.values():
|
||||||
|
namespace = variables.name
|
||||||
if hasattr(variables, 'family'):
|
if hasattr(variables, 'family'):
|
||||||
for family in variables.family.values():
|
for family in variables.family.values():
|
||||||
family_mode = family.mode
|
family_mode = family.mode
|
||||||
|
@ -694,21 +1164,14 @@ class SpaceAnnotator(object):
|
||||||
|
|
||||||
if isinstance(variable, self.objectspace.Leadership):
|
if isinstance(variable, self.objectspace.Leadership):
|
||||||
mode = modes_level[-1]
|
mode = modes_level[-1]
|
||||||
for follower in variable.variable:
|
for idx, follower in enumerate(variable.variable):
|
||||||
if follower.auto_save is True:
|
if follower.auto_save is True:
|
||||||
raise CreoleDictConsistencyError(_('leader/followers {} '
|
raise DictConsistencyError(_(f'leader/followers {follower.name} could not be auto_save'))
|
||||||
'could not be '
|
|
||||||
'auto_save').format(follower.name))
|
|
||||||
if follower.auto_freeze is True:
|
if follower.auto_freeze is True:
|
||||||
raise CreoleDictConsistencyError(_('leader/followers {} '
|
raise DictConsistencyError(_('leader/followers {follower.name} could not be auto_freeze'))
|
||||||
'could not be '
|
is_follower = idx != 0
|
||||||
'auto_freeze').format(follower.name))
|
|
||||||
if HIGH_COMPATIBILITY and variable.name != follower.name: # and variable.variable[0].mode != modes_level[0]:
|
|
||||||
is_follower = True
|
|
||||||
else:
|
|
||||||
is_follower = False
|
|
||||||
path = '{}.{}.{}'.format(family.path, variable.name, follower.name)
|
path = '{}.{}.{}'.format(family.path, variable.name, follower.name)
|
||||||
self._annotate_variable(follower, family_mode, path, is_follower)
|
self.annotate_variable(follower, family_mode, path, is_follower)
|
||||||
# leader's mode is minimum level
|
# leader's mode is minimum level
|
||||||
if modes[variable.variable[0].mode] > modes[follower.mode]:
|
if modes[variable.variable[0].mode] > modes[follower.mode]:
|
||||||
follower.mode = variable.variable[0].mode
|
follower.mode = variable.variable[0].mode
|
||||||
|
@ -721,685 +1184,54 @@ class SpaceAnnotator(object):
|
||||||
if variable.auto_freeze is True and variable.mode != modes_level[-1]:
|
if variable.auto_freeze is True and variable.mode != modes_level[-1]:
|
||||||
variable.mode = modes_level[0]
|
variable.mode = modes_level[0]
|
||||||
path = '{}.{}'.format(family.path, variable.name)
|
path = '{}.{}'.format(family.path, variable.name)
|
||||||
self._annotate_variable(variable, family_mode, path)
|
self.annotate_variable(variable, family_mode, path)
|
||||||
|
|
||||||
def get_variable(self, name): # pylint: disable=C0111
|
class PropertyAnnotator:
|
||||||
return self.paths.get_variable_obj(name)
|
def __init__(self, objectspace):
|
||||||
|
self.objectspace = objectspace
|
||||||
|
self.convert_annotator()
|
||||||
|
|
||||||
def convert_autofill(self): # pylint: disable=C0111
|
def convert_property(self,
|
||||||
if hasattr(self.space, 'constraints'):
|
variable,
|
||||||
self.convert_duplicate_autofill(self.space.constraints)
|
):
|
||||||
if 'auto' in vars(self.space.constraints):
|
properties = []
|
||||||
self.convert_auto(self.space.constraints.auto, self.space)
|
for prop in PROPERTIES:
|
||||||
if 'fill' in vars(self.space.constraints):
|
if hasattr(variable, prop):
|
||||||
self.convert_fill(self.space.constraints.fill, self.space)
|
if getattr(variable, prop) == True:
|
||||||
|
for subprop in CONVERT_PROPERTIES.get(prop, [prop]):
|
||||||
|
properties.append(subprop)
|
||||||
|
setattr(variable, prop, None)
|
||||||
|
if hasattr(variable, 'mode') and variable.mode:
|
||||||
|
properties.append(variable.mode)
|
||||||
|
variable.mode = None
|
||||||
|
if properties:
|
||||||
|
variable.properties = frozenset(properties)
|
||||||
|
|
||||||
def convert_duplicate_autofill(self, constraints):
|
def convert_annotator(self): # pylint: disable=C0111
|
||||||
""" Remove duplicate auto or fill for a variable
|
if hasattr(self.objectspace.space, 'services'):
|
||||||
This variable must be redefined
|
self.convert_property(self.objectspace.space.services)
|
||||||
"""
|
for services in self.objectspace.space.services.service.values():
|
||||||
fills = {}
|
self.convert_property(services)
|
||||||
# sort fill/auto by index
|
for service in vars(services).values():
|
||||||
if 'fill' in vars(constraints):
|
if isinstance(service, self.objectspace.family):
|
||||||
for idx, fill in enumerate(constraints.fill):
|
self.convert_property(service)
|
||||||
fills[fill.index] = {'idx': idx, 'fill': fill, 'type': 'fill'}
|
if hasattr(service, 'family'):
|
||||||
if 'auto' in vars(constraints):
|
self.convert_property(service)
|
||||||
for idx, fill in enumerate(constraints.auto):
|
for family in service.family:
|
||||||
fills[fill.index] = {'idx': idx, 'fill': fill, 'type': 'auto'}
|
self.convert_property(family)
|
||||||
indexes = list(fills.keys())
|
if hasattr(family, 'variable'):
|
||||||
indexes.sort()
|
for variable in family.variable:
|
||||||
targets = {}
|
self.convert_property(variable)
|
||||||
remove_autos = []
|
if hasattr(self.objectspace.space, 'variables'):
|
||||||
remove_fills = []
|
for variables in self.objectspace.space.variables.values():
|
||||||
for idx in indexes:
|
if hasattr(variables, 'family'):
|
||||||
fill = fills[idx]['fill']
|
for family in variables.family.values():
|
||||||
redefine = bool(fill.redefine)
|
self.convert_property(family)
|
||||||
if fill.target in targets:
|
if hasattr(family, 'variable'):
|
||||||
if redefine:
|
for variable in family.variable.values():
|
||||||
if targets[fill.target][1] == 'auto':
|
if isinstance(variable, self.objectspace.Leadership):
|
||||||
remove_autos.append(targets[fill.target][0])
|
self.convert_property(variable)
|
||||||
|
for follower in variable.variable:
|
||||||
|
self.convert_property(follower)
|
||||||
else:
|
else:
|
||||||
remove_fills.append(targets[fill.target][0])
|
self.convert_property(variable)
|
||||||
else:
|
|
||||||
raise CreoleDictConsistencyError(_("An auto or fill already exists "
|
|
||||||
"for the target: {}").format(
|
|
||||||
fill.target))
|
|
||||||
targets[fill.target] = (fills[idx]['idx'], fills[idx]['type'])
|
|
||||||
remove_autos.sort(reverse=True)
|
|
||||||
for idx in remove_autos:
|
|
||||||
constraints.auto.pop(idx)
|
|
||||||
remove_fills.sort(reverse=True)
|
|
||||||
for idx in remove_fills:
|
|
||||||
constraints.fill.pop(idx)
|
|
||||||
|
|
||||||
def convert_auto(self, auto_space, space): # pylint: disable=C0111
|
|
||||||
for auto in auto_space:
|
|
||||||
if HIGH_COMPATIBILITY and auto.target in self.has_frozen_if_in_condition:
|
|
||||||
# if a variable has a 'frozen_if_in' condition
|
|
||||||
# then we change the 'auto' variable as a 'fill' variable
|
|
||||||
continue
|
|
||||||
# an auto is a fill with "hidden" and "frozen" properties
|
|
||||||
variable = self.get_variable(auto.target)
|
|
||||||
if variable.auto_freeze:
|
|
||||||
raise CreoleDictConsistencyError(_('variable with auto value '
|
|
||||||
'cannot be auto_freeze').format(auto.target))
|
|
||||||
if variable.auto_save:
|
|
||||||
raise CreoleDictConsistencyError(_('variable with auto value '
|
|
||||||
'cannot be auto_save').format(auto.target))
|
|
||||||
leader = self.paths.get_leader(auto.target)
|
|
||||||
if leader is None or variable.name != leader:
|
|
||||||
variable.hidden = True
|
|
||||||
else:
|
|
||||||
leadership = self.paths.get_family_obj(self.paths.get_variable_family_path(auto.target))
|
|
||||||
leadership.hidden = True
|
|
||||||
variable.frozen = True
|
|
||||||
variable.force_default_on_freeze = True
|
|
||||||
if 'fill' not in vars(space.constraints):
|
|
||||||
space.constraints.fill = []
|
|
||||||
space.constraints.fill.extend(auto_space)
|
|
||||||
del space.constraints.auto
|
|
||||||
|
|
||||||
def filter_separators(self): # pylint: disable=C0111,R0201
|
|
||||||
# FIXME devrait etre dans la variable
|
|
||||||
if not hasattr(self.space, 'variables'):
|
|
||||||
return
|
|
||||||
for family in self.space.variables.values():
|
|
||||||
if (hasattr(family, 'separators') and hasattr(family.separators, 'separator')):
|
|
||||||
space = family.separators.separator
|
|
||||||
names = []
|
|
||||||
for idx, separator in enumerate(space):
|
|
||||||
namespace = self.paths.get_variable_namespace(separator.name)
|
|
||||||
subpath = self.paths.get_variable_path(separator.name, namespace)
|
|
||||||
separator.name = subpath
|
|
||||||
if separator.name in names:
|
|
||||||
raise CreoleDictConsistencyError(_('{} already has a separator').format(separator.name))
|
|
||||||
names.append(separator.name)
|
|
||||||
|
|
||||||
|
|
||||||
def load_params_in_validenum(self, param):
|
|
||||||
if param.type in ['string', 'python', 'number']:
|
|
||||||
if not hasattr(param, 'text') and (param.type == 'python' or param.type == 'number'):
|
|
||||||
raise CreoleDictConsistencyError(_("All '{}' variables shall be set in order to calculate {}").format(param.type, 'valid_enum'))
|
|
||||||
if param.type in ['string', 'number']:
|
|
||||||
try:
|
|
||||||
values = literal_eval(param.text)
|
|
||||||
except ValueError:
|
|
||||||
raise CreoleDictConsistencyError(_('Cannot load {}').format(param.text))
|
|
||||||
elif param.type == 'python':
|
|
||||||
try:
|
|
||||||
values = eval(param.text, {'eosfunc': self.eosfunc, '__builtins__': {'range': range, 'str': str}})
|
|
||||||
#FIXME : eval('[str(i) for i in range(3, 13)]', {'eosfunc': eosfunc, '__builtins__': {'range': range, 'str': str}})
|
|
||||||
except NameError:
|
|
||||||
raise CreoleDictConsistencyError(_('The function {} is unknown').format(param.text))
|
|
||||||
if not isinstance(values, list):
|
|
||||||
raise CreoleDictConsistencyError(_('Function {} shall return a list').format(param.text))
|
|
||||||
new_values = []
|
|
||||||
for val in values:
|
|
||||||
new_values.append(val)
|
|
||||||
values = new_values
|
|
||||||
else:
|
|
||||||
values = param.text
|
|
||||||
return values
|
|
||||||
|
|
||||||
def filter_check(self): # pylint: disable=C0111
|
|
||||||
# valid param in check
|
|
||||||
if not hasattr(self.space, 'constraints') or not hasattr(self.space.constraints, 'check'):
|
|
||||||
return
|
|
||||||
space = self.space.constraints.check
|
|
||||||
remove_indexes = []
|
|
||||||
for check_idx, check in enumerate(space):
|
|
||||||
namespace = check.namespace
|
|
||||||
if hasattr(check, 'param'):
|
|
||||||
param_option_indexes = []
|
|
||||||
for idx, param in enumerate(check.param):
|
|
||||||
if param.type not in TYPE_PARAM_CHECK:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot use {} type as a param in check for {}').format(param.type, check.target))
|
|
||||||
if param.type == 'eole':
|
|
||||||
param.type = 'variable'
|
|
||||||
if param.type == 'variable':
|
|
||||||
# if HIGH_COMPATIBILITY and param.text.startswith('container_ip'):
|
|
||||||
# if param.optional is True:
|
|
||||||
# param_option_indexes.append(idx)
|
|
||||||
try:
|
|
||||||
param.text = self.paths.get_variable_path(param.text, namespace)
|
|
||||||
except CreoleDictConsistencyError as err:
|
|
||||||
if param.optional is True:
|
|
||||||
param_option_indexes.append(idx)
|
|
||||||
else:
|
|
||||||
raise err
|
|
||||||
param_option_indexes = list(set(param_option_indexes))
|
|
||||||
param_option_indexes.sort(reverse=True)
|
|
||||||
for idx in param_option_indexes:
|
|
||||||
check.param.pop(idx)
|
|
||||||
if not HIGH_COMPATIBILITY and check.param == []:
|
|
||||||
remove_indexes.append(check_idx)
|
|
||||||
remove_indexes.sort(reverse=True)
|
|
||||||
for idx in remove_indexes:
|
|
||||||
del space[idx]
|
|
||||||
variables = {}
|
|
||||||
for index, check in enumerate(space):
|
|
||||||
namespace = check.namespace
|
|
||||||
if HIGH_COMPATIBILITY:
|
|
||||||
if not self.paths.path_is_defined(check.target):
|
|
||||||
continue
|
|
||||||
check.is_in_leadership = self.paths.get_leader(check.target) != None
|
|
||||||
# let's replace the target by the path
|
|
||||||
check.target = self.paths.get_variable_path(check.target, namespace)
|
|
||||||
if check.target not in variables:
|
|
||||||
variables[check.target] = []
|
|
||||||
variables[check.target].append((index, check))
|
|
||||||
# remove check already set for a variable
|
|
||||||
remove_indexes = []
|
|
||||||
for checks in variables.values():
|
|
||||||
names = {}
|
|
||||||
for idx, check in checks:
|
|
||||||
if HIGH_COMPATIBILITY and check.name == 'valid_enum':
|
|
||||||
redefine = True
|
|
||||||
else:
|
|
||||||
redefine = False
|
|
||||||
#redefine = bool(check.redefine)
|
|
||||||
if redefine and check.name in names:
|
|
||||||
remove_indexes.append(names[check.name])
|
|
||||||
del names[check.name]
|
|
||||||
names[check.name] = idx
|
|
||||||
del check.index
|
|
||||||
remove_indexes.sort(reverse=True)
|
|
||||||
for idx in remove_indexes:
|
|
||||||
del space[idx]
|
|
||||||
remove_indexes = []
|
|
||||||
functions = dir(self.eosfunc)
|
|
||||||
functions.extend(['valid_enum', 'valid_in_network', 'valid_differ'])
|
|
||||||
for idx, check in enumerate(space):
|
|
||||||
if not check.name in functions:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot find check function {}').format(check.name))
|
|
||||||
#is_probe = not check.name in self.eosfunc.func_on_zephir_context
|
|
||||||
#if is_probe:
|
|
||||||
# raise CreoleDictConsistencyError(_('cannot have a check with probe function ({})').format(check.name))
|
|
||||||
if check.name == 'valid_enum':
|
|
||||||
proposed_value_type = False
|
|
||||||
remove_params = []
|
|
||||||
for param_idx, param in enumerate(check.param):
|
|
||||||
if hasattr(param, 'name') and param.name == 'checkval':
|
|
||||||
try:
|
|
||||||
proposed_value_type = self.objectspace._convert_boolean(param.text) == False
|
|
||||||
remove_params.append(param_idx)
|
|
||||||
except TypeError as err:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot load checkval value for variable {}: {}').format(check.target, err))
|
|
||||||
if proposed_value_type:
|
|
||||||
# no more supported
|
|
||||||
raise CreoleDictConsistencyError(_('cannot load checkval value for variable {}, no more supported').format(check.target))
|
|
||||||
remove_params.sort(reverse=True)
|
|
||||||
for param_idx in remove_params:
|
|
||||||
del check.param[param_idx]
|
|
||||||
if len(check.param) != 1:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot set more than one param '
|
|
||||||
'for valid_enum for variable {}'
|
|
||||||
'').format(check.target))
|
|
||||||
param = check.param[0]
|
|
||||||
if proposed_value_type:
|
|
||||||
if param.type == 'variable':
|
|
||||||
try:
|
|
||||||
values = self.load_params_in_validenum(param)
|
|
||||||
except NameError as err:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot load value for variable {}: {}').format(check.target, err))
|
|
||||||
add_value = True
|
|
||||||
if HIGH_COMPATIBILITY and check.is_in_leadership:
|
|
||||||
add_value = False
|
|
||||||
if add_value and values:
|
|
||||||
self.force_value[check.target] = values[0]
|
|
||||||
else:
|
|
||||||
if check.target in self.valid_enums:
|
|
||||||
raise CreoleDictConsistencyError(_('valid_enum already set for {}'
|
|
||||||
'').format(check.target))
|
|
||||||
values = self.load_params_in_validenum(param)
|
|
||||||
self.valid_enums[check.target] = {'type': param.type,
|
|
||||||
'values': values}
|
|
||||||
remove_indexes.append(idx)
|
|
||||||
remove_indexes.sort(reverse=True)
|
|
||||||
for idx in remove_indexes:
|
|
||||||
del space[idx]
|
|
||||||
#convert level to "warnings_only" and hidden to "transitive"
|
|
||||||
for check in space:
|
|
||||||
if check.level == 'warning':
|
|
||||||
check.warnings_only = True
|
|
||||||
else:
|
|
||||||
check.warnings_only = False
|
|
||||||
check.level = None
|
|
||||||
if hasattr(check, 'param'):
|
|
||||||
for param in check.param:
|
|
||||||
if not param.hidden is True:
|
|
||||||
check.transitive = False
|
|
||||||
param.hidden = None
|
|
||||||
|
|
||||||
if not self.space.constraints.check:
|
|
||||||
del self.space.constraints.check
|
|
||||||
|
|
||||||
|
|
||||||
def convert_check(self):
|
|
||||||
if not hasattr(self.space, 'constraints') or not hasattr(self.space.constraints, 'check'):
|
|
||||||
return
|
|
||||||
for check in self.space.constraints.check:
|
|
||||||
variable = self.paths.get_variable_obj(check.target)
|
|
||||||
check_ = self.objectspace.check()
|
|
||||||
name = check.name
|
|
||||||
if name == 'valid_differ':
|
|
||||||
name = 'valid_not_equal'
|
|
||||||
elif name == 'valid_network_netmask':
|
|
||||||
params_len = 1
|
|
||||||
if len(check.param) != params_len:
|
|
||||||
raise CreoleDictConsistencyError(_('{} must have {} param').format(name, params_len))
|
|
||||||
elif name == 'valid_ipnetmask':
|
|
||||||
params_len = 1
|
|
||||||
if len(check.param) != params_len:
|
|
||||||
raise CreoleDictConsistencyError(_('{} must have {} param').format(name, params_len))
|
|
||||||
name = 'valid_ip_netmask'
|
|
||||||
elif name == 'valid_broadcast':
|
|
||||||
params_len = 2
|
|
||||||
if len(check.param) != params_len:
|
|
||||||
raise CreoleDictConsistencyError(_('{} must have {} param').format(name, params_len))
|
|
||||||
elif name == 'valid_in_network':
|
|
||||||
params_len = 2
|
|
||||||
if len(check.param) != params_len:
|
|
||||||
raise CreoleDictConsistencyError(_('{} must have {} param').format(name, params_len))
|
|
||||||
check_.name = name
|
|
||||||
check_.warnings_only = check.warnings_only
|
|
||||||
if hasattr(check, 'param'):
|
|
||||||
check_.param = check.param
|
|
||||||
if not hasattr(variable, 'check'):
|
|
||||||
variable.check = []
|
|
||||||
variable.check.append(check_)
|
|
||||||
del self.space.constraints.check
|
|
||||||
|
|
||||||
|
|
||||||
def convert_fill(self, fill_space, space): # pylint: disable=C0111,R0912
|
|
||||||
fills = {}
|
|
||||||
# sort fill/auto by index
|
|
||||||
for idx, fill in enumerate(fill_space):
|
|
||||||
fills[fill.index] = {'idx': idx, 'fill': fill}
|
|
||||||
del fill.index
|
|
||||||
indexes = list(fills.keys())
|
|
||||||
indexes.sort()
|
|
||||||
del_idx = []
|
|
||||||
for idx in indexes:
|
|
||||||
fill = fills[idx]['fill']
|
|
||||||
variable = self.get_variable(fill.target)
|
|
||||||
if hasattr(variable, 'value'):
|
|
||||||
del variable.value
|
|
||||||
namespace = fill.namespace
|
|
||||||
# let's replace the target by the path
|
|
||||||
fill.target = self.paths.get_variable_path(fill.target, namespace)
|
|
||||||
if not fill.name in dir(self.eosfunc):
|
|
||||||
raise CreoleDictConsistencyError(_('cannot find fill function {}').format(fill.name))
|
|
||||||
#is_probe = not fill.name in self.eosfunc.func_on_zephir_context
|
|
||||||
if hasattr(fill, 'param'):
|
|
||||||
for param in fill.param:
|
|
||||||
if param.type not in TYPE_PARAM_FILL:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot use {} type as a param '
|
|
||||||
'in a fill/auto').format(param.type))
|
|
||||||
if param.type == 'eole':
|
|
||||||
param.type = 'variable'
|
|
||||||
param_option_indexes = []
|
|
||||||
for fill_idx, param in enumerate(fill.param):
|
|
||||||
if not hasattr(param, 'text') and \
|
|
||||||
(param.type == 'variable' or param.type == 'number' or \
|
|
||||||
param.type == 'python'):
|
|
||||||
raise CreoleDictConsistencyError(_("All '{}' variables shall be set in "
|
|
||||||
"order to calculate {}").format(
|
|
||||||
param.type,
|
|
||||||
fill.target))
|
|
||||||
# if param.type == 'container':
|
|
||||||
# param.type = 'eole'
|
|
||||||
# param.text = 'container_ip_{}'.format(param.text)
|
|
||||||
if param.type == 'variable':
|
|
||||||
#if is_probe:
|
|
||||||
# raise CreoleDictConsistencyError(_('Function {0} used to calculate {1} '
|
|
||||||
# 'is executed on remote server, '
|
|
||||||
# 'so cannot depends to an '
|
|
||||||
# 'other variable'
|
|
||||||
# ).format(fill.name, fill.target))
|
|
||||||
# if HIGH_COMPATIBILITY and param.text.startswith('container_ip'):
|
|
||||||
# if param.optional is True:
|
|
||||||
# param_option_indexes.append(fill_idx)
|
|
||||||
try:
|
|
||||||
param.text = self.paths.get_variable_path(param.text, namespace)
|
|
||||||
except CreoleDictConsistencyError as err:
|
|
||||||
if param.optional is True:
|
|
||||||
param_option_indexes.append(fill_idx)
|
|
||||||
else:
|
|
||||||
raise err
|
|
||||||
param_option_indexes = list(set(param_option_indexes))
|
|
||||||
param_option_indexes.sort(reverse=True)
|
|
||||||
for param_idx in param_option_indexes:
|
|
||||||
fill.param.pop(param_idx)
|
|
||||||
self.has_calc.append(fill.target)
|
|
||||||
|
|
||||||
#if is_probe:
|
|
||||||
# variable.force_default_on_freeze = False
|
|
||||||
# self.objectspace.probe_variables.append(fill)
|
|
||||||
# del_idx.append(fills[idx]['idx'])
|
|
||||||
del_idx.sort(reverse=True)
|
|
||||||
for idx in del_idx:
|
|
||||||
space.constraints.fill.pop(idx)
|
|
||||||
for fill in space.constraints.fill:
|
|
||||||
variable = self.paths.get_variable_obj(fill.target)
|
|
||||||
value = self.objectspace.value()
|
|
||||||
value.type = 'calculation'
|
|
||||||
value.name = fill.name
|
|
||||||
if hasattr(fill, 'param'):
|
|
||||||
for param in fill.param:
|
|
||||||
if param.hidden is True:
|
|
||||||
param.transitive = False
|
|
||||||
param.hidden = None
|
|
||||||
value.param = fill.param
|
|
||||||
if not hasattr(variable, 'value'):
|
|
||||||
variable.value = []
|
|
||||||
variable.value.append(value)
|
|
||||||
self.force_not_mandatory.append(fill.target)
|
|
||||||
del space.constraints.fill
|
|
||||||
|
|
||||||
def filter_targets(self): # pylint: disable=C0111
|
|
||||||
for condition_idx, condition in enumerate(self.space.constraints.condition):
|
|
||||||
namespace = condition.namespace
|
|
||||||
del_idx = []
|
|
||||||
for idx, target in enumerate(condition.target):
|
|
||||||
if target.type == 'variable':
|
|
||||||
if (hasattr(target, 'optional') and target.optional is True and
|
|
||||||
not self.paths.path_is_defined(target.name)):
|
|
||||||
del_idx.append(idx)
|
|
||||||
continue
|
|
||||||
if condition.source == target.name:
|
|
||||||
raise CreoleDictConsistencyError(_('target name and source name must be different: {}').format(condition.source))
|
|
||||||
target.name = self.paths.get_variable_path(target.name, namespace)
|
|
||||||
elif target.type == 'family':
|
|
||||||
try:
|
|
||||||
target.name = self.paths.get_family_path(target.name, namespace)
|
|
||||||
except KeyError:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot found family {}').format(target.name))
|
|
||||||
del_idx = list(set(del_idx))
|
|
||||||
del_idx.sort(reverse=True)
|
|
||||||
for idx in del_idx:
|
|
||||||
condition.target.pop(idx)
|
|
||||||
|
|
||||||
def filter_condition_servicelist(self):
|
|
||||||
# automatic generation of the service_access lists
|
|
||||||
# and the service_restriction lists from the servicelist
|
|
||||||
for condition in self.space.constraints.condition:
|
|
||||||
if hasattr(condition, 'target'):
|
|
||||||
new_targets = []
|
|
||||||
for target in condition.target:
|
|
||||||
if target.type == 'servicelist':
|
|
||||||
new_target = copy(target)
|
|
||||||
new_target.type = 'service_accesslist'
|
|
||||||
new_target.name = '___auto_{}'.format(new_target.name)
|
|
||||||
new_targets.append(new_target)
|
|
||||||
|
|
||||||
new_target = copy(target)
|
|
||||||
new_target.type = 'service_restrictionlist'
|
|
||||||
new_target.name = '___auto_{}'.format(new_target.name)
|
|
||||||
new_targets.append(new_target)
|
|
||||||
condition.target.extend(new_targets)
|
|
||||||
|
|
||||||
def check_condition_without_target(self):
|
|
||||||
for condition in self.space.constraints.condition:
|
|
||||||
if not hasattr(condition, 'target'):
|
|
||||||
raise CreoleDictConsistencyError(_('target is mandatory in condition'))
|
|
||||||
|
|
||||||
def check_condition_fallback_not_exists(self, fallback_variables, fallback_lists):
|
|
||||||
# a condition with a fallback **and** the source variable doesn't exist
|
|
||||||
remove_conditions = []
|
|
||||||
for idx, condition in enumerate(self.space.constraints.condition):
|
|
||||||
if (hasattr(condition, 'fallback') and condition.fallback is True and
|
|
||||||
not self.paths.path_is_defined(condition.source)):
|
|
||||||
for target in condition.target:
|
|
||||||
if target.type in ['variable', 'family']:
|
|
||||||
name = target.name.split('.')[-1]
|
|
||||||
if target.type == 'variable':
|
|
||||||
variable = self.get_variable(name)
|
|
||||||
else:
|
|
||||||
variable = self.paths.get_family_obj(name)
|
|
||||||
if condition.name in ['disabled_if_in']:
|
|
||||||
variable.disabled = True
|
|
||||||
if condition.name in ['mandatory_if_in']:
|
|
||||||
variable.mandatory = True
|
|
||||||
if condition.name in ['disabled_if_in', 'disabled_if_not_in',
|
|
||||||
'frozen_if_in', 'frozen_if_not_in']:
|
|
||||||
variable.hidden = False
|
|
||||||
if HIGH_COMPATIBILITY:
|
|
||||||
fallback_variables.append(name)
|
|
||||||
else:
|
|
||||||
listname = target.type
|
|
||||||
if not listname.endswith('list'):
|
|
||||||
raise Exception('not yet implemented')
|
|
||||||
listvars = self.objectspace.list_conditions.get(listname,
|
|
||||||
{}).get(target.name)
|
|
||||||
if listvars:
|
|
||||||
for listvar in listvars:
|
|
||||||
try:
|
|
||||||
variable = self.get_variable(listvar)
|
|
||||||
except CreoleDictConsistencyError:
|
|
||||||
variable = self.paths.get_family_obj(listvar)
|
|
||||||
if condition.name in ['disabled_if_in']:
|
|
||||||
variable.disabled = True
|
|
||||||
if condition.name in ['mandatory_if_in']:
|
|
||||||
variable.mandatory = True
|
|
||||||
if condition.name in ['disabled_if_in', 'disabled_if_not_in',
|
|
||||||
'frozen_if_in', 'frozen_if_not_in']:
|
|
||||||
variable.hidden = False
|
|
||||||
fallback_lists.append(listvar)
|
|
||||||
remove_conditions.append(idx)
|
|
||||||
remove_conditions = list(set(remove_conditions))
|
|
||||||
remove_conditions.sort(reverse=True)
|
|
||||||
for idx in remove_conditions:
|
|
||||||
self.space.constraints.condition.pop(idx)
|
|
||||||
|
|
||||||
def convert_xxxlist_to_variable(self, fallback_lists): # pylint: disable=C0111
|
|
||||||
# transform *list to variable or family
|
|
||||||
for condition_idx, condition in enumerate(self.space.constraints.condition):
|
|
||||||
new_targets = []
|
|
||||||
remove_targets = []
|
|
||||||
for target_idx, target in enumerate(condition.target):
|
|
||||||
if target.type not in ['variable', 'family']:
|
|
||||||
listname = target.type
|
|
||||||
if not listname.endswith('list'):
|
|
||||||
raise Exception('not yet implemented')
|
|
||||||
listvars = self.objectspace.list_conditions.get(listname,
|
|
||||||
{}).get(target.name)
|
|
||||||
if listvars:
|
|
||||||
for listvar in listvars:
|
|
||||||
if listvar in fallback_lists:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
variable = self.get_variable(listvar)
|
|
||||||
type_ = 'variable'
|
|
||||||
except CreoleDictConsistencyError:
|
|
||||||
variable = self.paths.get_family_obj(listvar)
|
|
||||||
type_ = 'family'
|
|
||||||
new_target = self.objectspace.target()
|
|
||||||
new_target.type = type_
|
|
||||||
new_target.name = listvar
|
|
||||||
new_target.index = target.index
|
|
||||||
new_targets.append(new_target)
|
|
||||||
remove_targets.append(target_idx)
|
|
||||||
remove_targets = list(set(remove_targets))
|
|
||||||
remove_targets.sort(reverse=True)
|
|
||||||
for target_idx in remove_targets:
|
|
||||||
condition.target.pop(target_idx)
|
|
||||||
condition.target.extend(new_targets)
|
|
||||||
|
|
||||||
def check_condition(self):
|
|
||||||
# if condition.name == 'hidden_if_in':
|
|
||||||
# condition.name = 'disabled_if_in'
|
|
||||||
# elif condition.name == 'hidden_if_not_in':
|
|
||||||
# condition.name = 'disabled_if_not_in'
|
|
||||||
for condition in self.space.constraints.condition:
|
|
||||||
if condition.name not in ['disabled_if_in', 'disabled_if_not_in', 'frozen_if_in', 'auto_frozen_if_in',
|
|
||||||
'frozen_if_not_in', 'mandatory_if_in', 'mandatory_if_not_in']:
|
|
||||||
raise CreoleDictConsistencyError(_('unknown condition {}').format(condition.name))
|
|
||||||
|
|
||||||
def check_params(self):
|
|
||||||
for condition in self.space.constraints.condition:
|
|
||||||
for param in condition.param:
|
|
||||||
if param.type not in TYPE_PARAM_CONDITION:
|
|
||||||
raise CreoleDictConsistencyError(_('cannot use {} type as a param '
|
|
||||||
'in a condition').format(param.type))
|
|
||||||
if param.type == 'eole':
|
|
||||||
param.type = 'variable'
|
|
||||||
|
|
||||||
def check_choice_option_condition(self, force_remove_targets):
|
|
||||||
# remove condition for ChoiceOption that don't have param
|
|
||||||
remove_conditions = []
|
|
||||||
for condition_idx, condition in enumerate(self.space.constraints.condition):
|
|
||||||
namespace = condition.namespace
|
|
||||||
src_variable = self.paths.get_variable_obj(condition.source)
|
|
||||||
condition.source = self.paths.get_variable_path(condition.source, namespace, allow_source=True)
|
|
||||||
valid_enum = None
|
|
||||||
if condition.source in self.valid_enums and \
|
|
||||||
self.valid_enums[condition.source]['type'] == 'string':
|
|
||||||
valid_enum = self.valid_enums[condition.source]['values']
|
|
||||||
if src_variable.type in FORCE_CHOICE:
|
|
||||||
valid_enum = FORCE_CHOICE[src_variable.type]
|
|
||||||
if valid_enum is not None:
|
|
||||||
remove_param = []
|
|
||||||
for param_idx, param in enumerate(condition.param):
|
|
||||||
if param.text not in valid_enum:
|
|
||||||
remove_param.append(param_idx)
|
|
||||||
remove_param.sort(reverse=True)
|
|
||||||
for idx in remove_param:
|
|
||||||
del condition.param[idx]
|
|
||||||
if condition.param == []:
|
|
||||||
for target in condition.target:
|
|
||||||
if target.name.startswith('creole.'):
|
|
||||||
name = target.name.split('.')[-1]
|
|
||||||
else:
|
|
||||||
name = target.name
|
|
||||||
if target.type == 'variable':
|
|
||||||
variable = self.get_variable(name)
|
|
||||||
else:
|
|
||||||
variable = self.paths.get_family_obj(name)
|
|
||||||
if condition.name == 'disabled_if_not_in':
|
|
||||||
variable.disabled = True
|
|
||||||
force_remove_targets.setdefault(condition.name,
|
|
||||||
[]).append(target.name)
|
|
||||||
elif condition.name == 'frozen_if_not_in':
|
|
||||||
variable.hidden = True
|
|
||||||
force_remove_targets.setdefault(condition.name,
|
|
||||||
[]).append(target.name)
|
|
||||||
elif condition.name == 'mandatory_if_not_in':
|
|
||||||
variable.mandatory = True
|
|
||||||
force_remove_targets.setdefault(condition.name,
|
|
||||||
[]).append(target.name)
|
|
||||||
elif HIGH_COMPATIBILITY and condition.name == 'disabled_if_in':
|
|
||||||
variable.hidden = False
|
|
||||||
remove_conditions.append(condition_idx)
|
|
||||||
remove_conditions = list(set(remove_conditions))
|
|
||||||
remove_conditions.sort(reverse=True)
|
|
||||||
for idx in remove_conditions:
|
|
||||||
self.space.constraints.condition.pop(idx)
|
|
||||||
|
|
||||||
def manage_variable_property(self, force_remove_targets, fallback_variables):
|
|
||||||
for condition in self.space.constraints.condition:
|
|
||||||
remove_targets = []
|
|
||||||
#parse each variable and family
|
|
||||||
for target_idx, target in enumerate(condition.target):
|
|
||||||
if target.name in force_remove_targets.get(condition.name, []):
|
|
||||||
remove_targets.append(target_idx)
|
|
||||||
if target.name.startswith('creole.'):
|
|
||||||
name = target.name.split('.')[-1]
|
|
||||||
else:
|
|
||||||
name = target.name
|
|
||||||
if target.type == 'variable':
|
|
||||||
variable = self.get_variable(name)
|
|
||||||
else:
|
|
||||||
variable = self.paths.get_family_obj(name)
|
|
||||||
if name in fallback_variables:
|
|
||||||
remove_targets.append(target_idx)
|
|
||||||
continue
|
|
||||||
if condition.name in ['disabled_if_in', 'disabled_if_not_in',
|
|
||||||
'frozen_if_in', 'frozen_if_not_in']:
|
|
||||||
variable.hidden = False
|
|
||||||
if condition.name in ['mandatory_if_in', 'mandatory_if_not_in']:
|
|
||||||
variable.mandatory = False
|
|
||||||
if HIGH_COMPATIBILITY and condition.name in ['frozen_if_in',
|
|
||||||
'frozen_if_not_in']:
|
|
||||||
self.has_frozen_if_in_condition.append(name)
|
|
||||||
if condition.name in ['mandatory_if_in', 'mandatory_if_not_in']:
|
|
||||||
self.force_not_mandatory.append(target.name)
|
|
||||||
|
|
||||||
remove_targets = list(set(remove_targets))
|
|
||||||
remove_targets.sort(reverse=True)
|
|
||||||
for target_idx in remove_targets:
|
|
||||||
condition.target.pop(target_idx)
|
|
||||||
|
|
||||||
def remove_condition_with_empty_target(self):
|
|
||||||
remove_conditions = []
|
|
||||||
for condition_idx, condition in enumerate(self.space.constraints.condition):
|
|
||||||
if not condition.target:
|
|
||||||
remove_conditions.append(condition_idx)
|
|
||||||
remove_conditions = list(set(remove_conditions))
|
|
||||||
remove_conditions.sort(reverse=True)
|
|
||||||
for idx in remove_conditions:
|
|
||||||
self.space.constraints.condition.pop(idx)
|
|
||||||
|
|
||||||
def filter_condition(self): # pylint: disable=C0111
|
|
||||||
if not hasattr(self.space, 'constraints') or not hasattr(self.space.constraints, 'condition'):
|
|
||||||
return
|
|
||||||
fallback_variables = []
|
|
||||||
fallback_lists = []
|
|
||||||
force_remove_targets = {}
|
|
||||||
self.check_condition()
|
|
||||||
self.check_params()
|
|
||||||
self.check_condition_without_target()
|
|
||||||
self.filter_condition_servicelist()
|
|
||||||
self.check_condition_fallback_not_exists(fallback_variables, fallback_lists)
|
|
||||||
self.filter_targets()
|
|
||||||
self.convert_xxxlist_to_variable(fallback_lists)
|
|
||||||
self.check_choice_option_condition(force_remove_targets)
|
|
||||||
self.manage_variable_property(force_remove_targets, fallback_variables)
|
|
||||||
self.remove_condition_with_empty_target()
|
|
||||||
for condition in self.space.constraints.condition:
|
|
||||||
if condition.name == 'disabled_if_in':
|
|
||||||
actions = ['disabled']
|
|
||||||
inverse = False
|
|
||||||
elif condition.name == 'disabled_if_not_in':
|
|
||||||
actions = ['disabled']
|
|
||||||
inverse = True
|
|
||||||
elif condition.name == 'frozen_if_in':
|
|
||||||
actions = ['frozen', 'hidden', 'force_default_on_freeze']
|
|
||||||
inverse = False
|
|
||||||
elif condition.name == 'frozen_if_not_in':
|
|
||||||
actions = ['frozen', 'hidden', 'force_default_on_freeze']
|
|
||||||
inverse = True
|
|
||||||
elif condition.name == 'mandatory_if_in':
|
|
||||||
actions = ['mandatory']
|
|
||||||
inverse = False
|
|
||||||
elif condition.name == 'mandatory_if_not_in':
|
|
||||||
actions = ['mandatory']
|
|
||||||
inverse = True
|
|
||||||
elif condition.name == 'auto_frozen_if_in':
|
|
||||||
actions = ['auto_frozen']
|
|
||||||
inverse = True
|
|
||||||
for param in condition.param:
|
|
||||||
if hasattr(param, 'text'):
|
|
||||||
param = param.text
|
|
||||||
else:
|
|
||||||
param = None
|
|
||||||
for target in condition.target:
|
|
||||||
if target.name.startswith('creole.'):
|
|
||||||
name = target.name.split('.')[-1]
|
|
||||||
else:
|
|
||||||
name = target.name
|
|
||||||
if target.type == 'variable':
|
|
||||||
variable = self.get_variable(name)
|
|
||||||
else:
|
|
||||||
variable = self.paths.get_family_obj(name)
|
|
||||||
if not hasattr(variable, 'property'):
|
|
||||||
variable.property = []
|
|
||||||
for action in actions:
|
|
||||||
prop = self.objectspace.property_()
|
|
||||||
prop.type = 'calculation'
|
|
||||||
prop.inverse = inverse
|
|
||||||
prop.source = condition.source
|
|
||||||
prop.expected = param
|
|
||||||
prop.name = action
|
|
||||||
variable.property.append(prop)
|
|
||||||
del self.space.constraints.condition
|
|
||||||
|
|
|
@ -15,3 +15,5 @@ dtdfilename = join(dtddir, 'rougail.dtd')
|
||||||
|
|
||||||
# chemin du répertoire source des fichiers templates
|
# chemin du répertoire source des fichiers templates
|
||||||
patch_dir = '/srv/rougail/patch'
|
patch_dir = '/srv/rougail/patch'
|
||||||
|
|
||||||
|
variable_namespace = 'rougail'
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
# Forked by:
|
# Forked by:
|
||||||
# Cadoles (http://www.cadoles.com)
|
# Cadoles (http://www.cadoles.com)
|
||||||
# Copyright (C) 2019
|
# Copyright (C) 2019-2020
|
||||||
|
|
||||||
# distribued with GPL-2 or later license
|
# distribued with GPL-2 or later license
|
||||||
|
|
||||||
|
@ -37,54 +37,23 @@
|
||||||
<!-- root element -->
|
<!-- root element -->
|
||||||
<!-- =============== -->
|
<!-- =============== -->
|
||||||
|
|
||||||
<!ELEMENT rougail (services | family_action | variables | constraints | help)*>
|
<!ELEMENT rougail (services | variables | constraints | help)*>
|
||||||
|
|
||||||
<!-- ============== -->
|
<!-- ============== -->
|
||||||
<!-- files element -->
|
<!-- files element -->
|
||||||
<!-- ============== -->
|
<!-- ============== -->
|
||||||
|
|
||||||
<!ELEMENT family_action (action)>
|
|
||||||
<!ATTLIST family_action name CDATA #REQUIRED>
|
|
||||||
<!ATTLIST family_action description CDATA #IMPLIED>
|
|
||||||
<!ATTLIST family_action color CDATA #IMPLIED>
|
|
||||||
<!ATTLIST family_action image CDATA #IMPLIED>
|
|
||||||
<!ELEMENT action ((input* | profile* | ewtapp* | tag* | saltaction*)*)>
|
|
||||||
<!ATTLIST action type (form|custom|external|reader|apache) "custom">
|
|
||||||
<!ATTLIST action title CDATA #REQUIRED>
|
|
||||||
<!ATTLIST action description CDATA #REQUIRED>
|
|
||||||
<!ATTLIST action rewrite CDATA #IMPLIED>
|
|
||||||
<!ATTLIST action image CDATA #IMPLIED>
|
|
||||||
<!ATTLIST action actionlist CDATA #IMPLIED>
|
|
||||||
<!-- for apache action -->
|
|
||||||
<!ATTLIST action apache_path CDATA #IMPLIED>
|
|
||||||
<!ATTLIST action apache_path_type (FilenameOption|SymLinkOption|variable) "FilenameOption">
|
|
||||||
<!-- for external action -->
|
|
||||||
<!ATTLIST action url CDATA #IMPLIED>
|
|
||||||
<!ATTLIST action url_type (URLOption|SymLinkOption|variable) "URLOption">
|
|
||||||
<!-- for form action -->
|
|
||||||
<!ATTLIST action save (True|False) "False">
|
|
||||||
|
|
||||||
<!ELEMENT services (service*)>
|
<!ELEMENT services (service*)>
|
||||||
|
|
||||||
<!ELEMENT service ((port* | tcpwrapper* | ip* | interface* | package* | file* | digitalcertificate*)*) >
|
<!ELEMENT service ((port* | tcpwrapper* | ip* | interface* | package* | file* | digitalcertificate* | override*)*) >
|
||||||
<!ATTLIST service name CDATA #REQUIRED>
|
<!ATTLIST service name CDATA #REQUIRED>
|
||||||
<!ATTLIST service method (systemd|upstart|apache|network) "systemd">
|
<!ATTLIST service manage (True|False) "True">
|
||||||
|
|
||||||
<!ELEMENT input (#PCDATA)>
|
|
||||||
<!ELEMENT profile (#PCDATA)>
|
|
||||||
<!ELEMENT ewtapp (#PCDATA)>
|
|
||||||
<!ELEMENT tag (#PCDATA)>
|
|
||||||
<!ELEMENT saltaction (#PCDATA)>
|
|
||||||
|
|
||||||
<!ELEMENT port (#PCDATA)>
|
<!ELEMENT port (#PCDATA)>
|
||||||
<!ATTLIST port port_type (PortOption|SymLinkOption|variable) "PortOption">
|
<!ATTLIST port port_type (PortOption|SymLinkOption|variable) "PortOption">
|
||||||
<!ATTLIST port portlist CDATA #IMPLIED >
|
<!ATTLIST port portlist CDATA #IMPLIED >
|
||||||
<!ATTLIST port protocol (tcp|udp) "tcp">
|
<!ATTLIST port protocol (tcp|udp) "tcp">
|
||||||
|
|
||||||
<!ELEMENT tcpwrapper (#PCDATA)>
|
|
||||||
<!ATTLIST tcpwrapper tcpwrapper_type (UnicodeOption|SymLinkOption|variable) "UnicodeOption">
|
|
||||||
<!ATTLIST tcpwrapper tcpwrapperlist CDATA #IMPLIED >
|
|
||||||
|
|
||||||
<!ELEMENT ip (#PCDATA)>
|
<!ELEMENT ip (#PCDATA)>
|
||||||
<!ATTLIST ip iplist CDATA #IMPLIED >
|
<!ATTLIST ip iplist CDATA #IMPLIED >
|
||||||
<!ATTLIST ip ip_type (NetworkOption|SymLinkOption|variable) "NetworkOption">
|
<!ATTLIST ip ip_type (NetworkOption|SymLinkOption|variable) "NetworkOption">
|
||||||
|
@ -93,9 +62,6 @@
|
||||||
<!ATTLIST ip netmask_type (NetmaskOption|SymLinkOption|variable) "NetmaskOption">
|
<!ATTLIST ip netmask_type (NetmaskOption|SymLinkOption|variable) "NetmaskOption">
|
||||||
<!ATTLIST ip netmask CDATA "255.255.255.255">
|
<!ATTLIST ip netmask CDATA "255.255.255.255">
|
||||||
|
|
||||||
<!ELEMENT package (#PCDATA)>
|
|
||||||
<!ATTLIST package packagelist CDATA #IMPLIED >
|
|
||||||
|
|
||||||
<!ELEMENT file EMPTY>
|
<!ELEMENT file EMPTY>
|
||||||
<!ATTLIST file name CDATA #REQUIRED >
|
<!ATTLIST file name CDATA #REQUIRED >
|
||||||
<!ATTLIST file file_type (UnicodeOption|SymLinkOption|variable) "UnicodeOption">
|
<!ATTLIST file file_type (UnicodeOption|SymLinkOption|variable) "UnicodeOption">
|
||||||
|
@ -106,9 +72,8 @@
|
||||||
<!ATTLIST file owner CDATA "root">
|
<!ATTLIST file owner CDATA "root">
|
||||||
<!ATTLIST file group CDATA "root">
|
<!ATTLIST file group CDATA "root">
|
||||||
<!ATTLIST file filelist CDATA #IMPLIED >
|
<!ATTLIST file filelist CDATA #IMPLIED >
|
||||||
<!ATTLIST file mkdir (True|False) "False">
|
|
||||||
<!ATTLIST file rm (True|False) "False">
|
|
||||||
<!ATTLIST file redefine (True|False) "False">
|
<!ATTLIST file redefine (True|False) "False">
|
||||||
|
<!ATTLIST file templating (True|False) "True">
|
||||||
|
|
||||||
<!ELEMENT digitalcertificate EMPTY>
|
<!ELEMENT digitalcertificate EMPTY>
|
||||||
<!ATTLIST digitalcertificate name CDATA #REQUIRED >
|
<!ATTLIST digitalcertificate name CDATA #REQUIRED >
|
||||||
|
@ -118,12 +83,15 @@
|
||||||
<!ATTLIST digitalcertificate type CDATA #REQUIRED >
|
<!ATTLIST digitalcertificate type CDATA #REQUIRED >
|
||||||
<!ATTLIST digitalcertificate ca CDATA #REQUIRED >
|
<!ATTLIST digitalcertificate ca CDATA #REQUIRED >
|
||||||
|
|
||||||
|
<!ELEMENT override EMPTY>
|
||||||
|
<!ATTLIST override source CDATA #IMPLIED >
|
||||||
|
<!ATTLIST override templating (True|False) "True">
|
||||||
|
|
||||||
<!ELEMENT variables (family*, separators*)>
|
<!ELEMENT variables (family*, separators*)>
|
||||||
<!ELEMENT family (#PCDATA | variable)*>
|
<!ELEMENT family (#PCDATA | variable)*>
|
||||||
<!ATTLIST family name CDATA #REQUIRED>
|
<!ATTLIST family name CDATA #REQUIRED>
|
||||||
<!ATTLIST family description CDATA #IMPLIED>
|
<!ATTLIST family description CDATA #IMPLIED>
|
||||||
<!ATTLIST family mode (basic|normal|expert) "basic">
|
<!ATTLIST family mode (basic|normal|expert) "basic">
|
||||||
<!ATTLIST family icon CDATA #IMPLIED>
|
|
||||||
<!ATTLIST family hidden (True|False) "False">
|
<!ATTLIST family hidden (True|False) "False">
|
||||||
<!ATTLIST family dynamic CDATA #IMPLIED>
|
<!ATTLIST family dynamic CDATA #IMPLIED>
|
||||||
|
|
||||||
|
@ -134,7 +102,6 @@
|
||||||
<!ATTLIST variable hidden (True|False) "False">
|
<!ATTLIST variable hidden (True|False) "False">
|
||||||
<!ATTLIST variable disabled (True|False) "False">
|
<!ATTLIST variable disabled (True|False) "False">
|
||||||
<!ATTLIST variable multi (True|False) "False">
|
<!ATTLIST variable multi (True|False) "False">
|
||||||
<!ATTLIST variable submulti (True|False) "False">
|
|
||||||
<!ATTLIST variable redefine (True|False) "False">
|
<!ATTLIST variable redefine (True|False) "False">
|
||||||
<!ATTLIST variable exists (True|False) "True">
|
<!ATTLIST variable exists (True|False) "True">
|
||||||
<!ATTLIST variable mandatory (True|False) "False">
|
<!ATTLIST variable mandatory (True|False) "False">
|
||||||
|
@ -149,11 +116,10 @@
|
||||||
|
|
||||||
<!ELEMENT separator (#PCDATA)>
|
<!ELEMENT separator (#PCDATA)>
|
||||||
<!ATTLIST separator name CDATA #REQUIRED>
|
<!ATTLIST separator name CDATA #REQUIRED>
|
||||||
<!ATTLIST separator never_hidden CDATA #IMPLIED>
|
|
||||||
|
|
||||||
<!ELEMENT value (#PCDATA)>
|
<!ELEMENT value (#PCDATA)>
|
||||||
|
|
||||||
<!ELEMENT constraints ((fill* | check* | condition* | auto* | group*)*)>
|
<!ELEMENT constraints ((fill* | check* | condition* | group*)*)>
|
||||||
<!ELEMENT fill (param*)>
|
<!ELEMENT fill (param*)>
|
||||||
<!ATTLIST fill name CDATA #REQUIRED>
|
<!ATTLIST fill name CDATA #REQUIRED>
|
||||||
<!ATTLIST fill target CDATA #REQUIRED>
|
<!ATTLIST fill target CDATA #REQUIRED>
|
||||||
|
@ -163,29 +129,27 @@
|
||||||
<!ATTLIST check target CDATA #REQUIRED>
|
<!ATTLIST check target CDATA #REQUIRED>
|
||||||
<!ATTLIST check level (error|warning) "error">
|
<!ATTLIST check level (error|warning) "error">
|
||||||
|
|
||||||
<!ELEMENT auto ((param)*)>
|
|
||||||
<!ATTLIST auto name CDATA #REQUIRED>
|
|
||||||
<!ATTLIST auto target CDATA #REQUIRED>
|
|
||||||
|
|
||||||
<!ELEMENT condition ((target | param)+ )>
|
<!ELEMENT condition ((target | param)+ )>
|
||||||
<!ATTLIST condition name CDATA #REQUIRED>
|
<!ATTLIST condition name (disabled_if_in|disabled_if_not_in|hidden_if_in|auto_hidden_if_not_in|hidden_if_not_in|mandatory_if_in|mandatory_if_not_in) #REQUIRED>
|
||||||
<!ATTLIST condition source CDATA #REQUIRED>
|
<!ATTLIST condition source CDATA #REQUIRED>
|
||||||
<!ATTLIST condition fallback (True|False) "False">
|
<!ATTLIST condition fallback (True|False) "False">
|
||||||
|
<!ATTLIST condition force_condition_on_fallback (True|False) "False">
|
||||||
|
<!ATTLIST condition force_inverse_condition_on_fallback (True|False) "False">
|
||||||
|
|
||||||
<!ELEMENT group (slave+)>
|
<!ELEMENT group (follower+)>
|
||||||
<!ATTLIST group master CDATA #REQUIRED>
|
<!ATTLIST group leader CDATA #REQUIRED>
|
||||||
<!ATTLIST group description CDATA #IMPLIED>
|
<!ATTLIST group description CDATA #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT param (#PCDATA)>
|
<!ELEMENT param (#PCDATA)>
|
||||||
<!ATTLIST param type (string|variable|number|python) "string">
|
<!ATTLIST param type (string|variable|number|python) "string">
|
||||||
<!ATTLIST param name CDATA #IMPLIED>
|
<!ATTLIST param name CDATA #IMPLIED>
|
||||||
<!ATTLIST param hidden (True|False) "True">
|
<!ATTLIST param notraisepropertyerror (True|False) "False">
|
||||||
<!ATTLIST param optional (True|False) "False">
|
<!ATTLIST param optional (True|False) "False">
|
||||||
|
|
||||||
<!ELEMENT target (#PCDATA)>
|
<!ELEMENT target (#PCDATA)>
|
||||||
<!ATTLIST target type (family|variable|filelist|iplist|portlist|tcpwrapperlist|packagelist|actionlist) "variable">
|
<!ATTLIST target type (family|variable|filelist|iplist|portlist) "variable">
|
||||||
<!ATTLIST target optional (True|False) "False">
|
<!ATTLIST target optional (True|False) "False">
|
||||||
|
|
||||||
<!ELEMENT slave (#PCDATA)>
|
<!ELEMENT follower (#PCDATA)>
|
||||||
|
|
||||||
<!ELEMENT help ((variable* | family*)*)>
|
<!ELEMENT help ((variable* | family*)*)>
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
|
||||||
Erreurs Creole
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigError(Exception):
|
class ConfigError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -19,7 +14,7 @@ class TemplateDisabled(TemplateError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CreoleOperationError(Exception):
|
class OperationError(Exception):
|
||||||
"""Type error or value Error for Creole variable's type or values
|
"""Type error or value Error for Creole variable's type or values
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -30,7 +25,11 @@ class SpaceObjShallNotBeUpdated(Exception):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class CreoleDictConsistencyError(Exception):
|
class DictConsistencyError(Exception):
|
||||||
"""It's not only that the Creole XML is valid against the Creole DTD
|
"""It's not only that the Creole XML is valid against the Creole DTD
|
||||||
it's that it is not consistent.
|
it's that it is not consistent.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class LoaderError(Exception):
|
||||||
|
pass
|
||||||
|
|
|
@ -24,7 +24,7 @@ import sys
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
# Application Name
|
# Application Name
|
||||||
APP_NAME = 'creole'
|
APP_NAME = 'rougail'
|
||||||
|
|
||||||
# Traduction dir
|
# Traduction dir
|
||||||
APP_DIR = os.path.join(sys.prefix, 'share')
|
APP_DIR = os.path.join(sys.prefix, 'share')
|
||||||
|
@ -44,8 +44,8 @@ mo_location = LOCALE_DIR
|
||||||
|
|
||||||
gettext.find(APP_NAME, mo_location)
|
gettext.find(APP_NAME, mo_location)
|
||||||
gettext.textdomain(APP_NAME)
|
gettext.textdomain(APP_NAME)
|
||||||
gettext.bind_textdomain_codeset(APP_NAME, "UTF-8")
|
#gettext.bind_textdomain_codeset(APP_NAME, "UTF-8")
|
||||||
gettext.translation(APP_NAME, fallback=True)
|
#gettext.translation(APP_NAME, fallback=True)
|
||||||
|
|
||||||
t = gettext.translation(APP_NAME, fallback=True)
|
t = gettext.translation(APP_NAME, fallback=True)
|
||||||
|
|
||||||
|
|
|
@ -1,594 +0,0 @@
|
||||||
"""creole loader
|
|
||||||
flattened XML specific
|
|
||||||
"""
|
|
||||||
from os.path import join, isfile, isdir
|
|
||||||
from os import listdir
|
|
||||||
#from ast import literal_eval
|
|
||||||
from lxml.etree import parse, DTD
|
|
||||||
|
|
||||||
from tiramisu import (StrOption, OptionDescription, DynOptionDescription, PortOption,
|
|
||||||
IntOption, ChoiceOption, BoolOption, SymLinkOption, IPOption,
|
|
||||||
NetworkOption, NetmaskOption, DomainnameOption, BroadcastOption,
|
|
||||||
URLOption, EmailOption, FilenameOption, UsernameOption, DateOption,
|
|
||||||
PasswordOption, BoolOption, MACOption, Leadership, submulti,
|
|
||||||
Params, ParamSelfOption, ParamOption, ParamValue, Calculation, calc_value,
|
|
||||||
groups, owners)
|
|
||||||
from tiramisu.error import ConfigError
|
|
||||||
|
|
||||||
from .config import dtdfilename
|
|
||||||
from .i18n import _
|
|
||||||
#For compatibility
|
|
||||||
from .xmlreflector import HIGH_COMPATIBILITY
|
|
||||||
#from . import eosfunc
|
|
||||||
from .objspace import CreoleObjSpace
|
|
||||||
from .utils import normalize_family
|
|
||||||
import imp
|
|
||||||
|
|
||||||
|
|
||||||
FUNC_TO_DICT = ['valid_not_equal']
|
|
||||||
|
|
||||||
|
|
||||||
class ConvertDynOptionDescription(DynOptionDescription):
|
|
||||||
def convert_suffix_to_path(self, suffix):
|
|
||||||
if not isinstance(suffix, str):
|
|
||||||
suffix = str(suffix)
|
|
||||||
return normalize_family(suffix,
|
|
||||||
check_name=False)
|
|
||||||
|
|
||||||
|
|
||||||
class CreoleLoaderError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def convert_tiramisu_value(value, obj):
|
|
||||||
"""
|
|
||||||
convertit les variables dans le bon type si nécessaire
|
|
||||||
"""
|
|
||||||
if value is None:
|
|
||||||
return value
|
|
||||||
def _convert_boolean(value):
|
|
||||||
if isinstance(value, bool):
|
|
||||||
return value
|
|
||||||
prop = {'True': True,
|
|
||||||
'False': False,
|
|
||||||
'None': None}
|
|
||||||
if value not in prop:
|
|
||||||
raise Exception('unknown value {} while trying to cast {} to boolean'.format(value, obj))
|
|
||||||
return prop[value]
|
|
||||||
|
|
||||||
func = {IntOption: int, StrOption: str, PortOption: str,
|
|
||||||
DomainnameOption: str, EmailOption: str, URLOption: str,
|
|
||||||
IPOption: str, NetmaskOption: str, NetworkOption: str,
|
|
||||||
BroadcastOption: str, FilenameOption: str,
|
|
||||||
BoolOption: _convert_boolean}.get(obj, None)
|
|
||||||
if func is None:
|
|
||||||
return value
|
|
||||||
if isinstance(value, list):
|
|
||||||
return [func(val) for val in value]
|
|
||||||
else:
|
|
||||||
return func(value)
|
|
||||||
|
|
||||||
|
|
||||||
CONVERT_OPTION = {'number': dict(opttype=IntOption),
|
|
||||||
'choice': dict(opttype=ChoiceOption),
|
|
||||||
'string': dict(opttype=StrOption),
|
|
||||||
'password': dict(opttype=PasswordOption),
|
|
||||||
'mail': dict(opttype=EmailOption),
|
|
||||||
'boolean': dict(opttype=BoolOption),
|
|
||||||
'symlink': dict(opttype=SymLinkOption),
|
|
||||||
'filename': dict(opttype=FilenameOption),
|
|
||||||
'date': dict(opttype=DateOption),
|
|
||||||
'unix_user': dict(opttype=UsernameOption),
|
|
||||||
'ip': dict(opttype=IPOption, initkwargs={'allow_reserved': True}),
|
|
||||||
'local_ip': dict(opttype=IPOption, initkwargs={'private_only': True, 'warnings_only': True}),
|
|
||||||
'netmask': dict(opttype=NetmaskOption),
|
|
||||||
'network': dict(opttype=NetworkOption),
|
|
||||||
'broadcast': dict(opttype=BroadcastOption),
|
|
||||||
'netbios': dict(opttype=DomainnameOption, initkwargs={'type': 'netbios', 'warnings_only': True}),
|
|
||||||
'domain': dict(opttype=DomainnameOption, initkwargs={'type': 'domainname', 'allow_ip': True, 'allow_without_dot': True}),
|
|
||||||
'domain_strict': dict(opttype=DomainnameOption, initkwargs={'type': 'domainname', 'allow_ip': False}),
|
|
||||||
'hostname': dict(opttype=DomainnameOption, initkwargs={'type': 'hostname', 'allow_ip': True}),
|
|
||||||
'hostname_strict': dict(opttype=DomainnameOption, initkwargs={'type': 'hostname', 'allow_ip': False}),
|
|
||||||
'web_address': dict(opttype=URLOption, initkwargs={'allow_ip': True, 'allow_without_dot': True}),
|
|
||||||
'port': dict(opttype=PortOption, initkwargs={'allow_private': True}),
|
|
||||||
'mac': dict(opttype=MACOption),
|
|
||||||
'cidr': dict(opttype=IPOption, initkwargs={'cidr': True}),
|
|
||||||
'network_cidr': dict(opttype=NetworkOption, initkwargs={'cidr': True}),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Elt(object):
|
|
||||||
def __init__(self, attrib):
|
|
||||||
self.attrib = attrib
|
|
||||||
|
|
||||||
|
|
||||||
class PopulateTiramisuObjects(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.storage = ElementStorage()
|
|
||||||
self.booleans = []
|
|
||||||
self.force_store_values = set()
|
|
||||||
self.separators = {}
|
|
||||||
self.groups = {}
|
|
||||||
|
|
||||||
def parse_dtd(self, dtdfilename):
|
|
||||||
"""Loads the Creole DTD
|
|
||||||
|
|
||||||
:raises IOError: if the DTD is not found
|
|
||||||
|
|
||||||
:param dtdfilename: the full filename of the Creole DTD
|
|
||||||
"""
|
|
||||||
if not isfile(dtdfilename):
|
|
||||||
raise IOError(_("no such DTD file: {}").format(dtdfilename))
|
|
||||||
with open(dtdfilename, 'r') as dtdfd:
|
|
||||||
dtd = DTD(dtdfd)
|
|
||||||
for elt in dtd.iterelements():
|
|
||||||
if elt.name == 'variable':
|
|
||||||
for attr in elt.iterattributes():
|
|
||||||
if set(attr.itervalues()) == set(['True', 'False']):
|
|
||||||
self.booleans.append(attr.name)
|
|
||||||
|
|
||||||
def make_tiramisu_objects(self, xmlroot, creolefunc_file):
|
|
||||||
elt = Elt({'name': 'baseoption'})
|
|
||||||
if creolefunc_file is None:
|
|
||||||
self.eosfunc = None
|
|
||||||
else:
|
|
||||||
self.eosfunc = imp.load_source('eosfunc', creolefunc_file)
|
|
||||||
family = Family(elt, self.booleans, self.storage, self.eosfunc)
|
|
||||||
self.storage.add('.', family)
|
|
||||||
|
|
||||||
elts = {}
|
|
||||||
for elt in xmlroot:
|
|
||||||
elts.setdefault(elt.tag, []).append(elt)
|
|
||||||
list_elts = list(elts.keys())
|
|
||||||
if 'family' in list_elts:
|
|
||||||
list_elts.remove('family')
|
|
||||||
list_elts.insert(0, 'family')
|
|
||||||
for elt in list_elts:
|
|
||||||
xmlelts_ = elts[elt]
|
|
||||||
if elt == 'family':
|
|
||||||
xmlelts = []
|
|
||||||
actions = None
|
|
||||||
# `creole` family has to be loaded before any other family
|
|
||||||
# because `extra` family could use `creole` variables.
|
|
||||||
# `actions` family has to be loaded at the very end
|
|
||||||
# because it may use `creole` or `extra` variables
|
|
||||||
for xml in xmlelts_:
|
|
||||||
if xml.attrib['name'] == 'creole':
|
|
||||||
xmlelts.insert(0, xml)
|
|
||||||
elif xml.attrib['name'] == 'actions':
|
|
||||||
actions = xml
|
|
||||||
else:
|
|
||||||
xmlelts.append(xml)
|
|
||||||
if actions is not None:
|
|
||||||
xmlelts.append(actions)
|
|
||||||
else:
|
|
||||||
xmlelts = xmlelts_
|
|
||||||
for xmlelt in xmlelts:
|
|
||||||
if xmlelt.tag != 'family':
|
|
||||||
raise CreoleLoaderError(_('unknown tag {}').format(xmlelt.tag))
|
|
||||||
self._iter_family(xmlelt, family)
|
|
||||||
|
|
||||||
def _populate_variable(self, elt, subpath, is_follower, is_leader):
|
|
||||||
variable = Variable(elt, self.booleans, self.storage, is_follower, is_leader, self.eosfunc)
|
|
||||||
path = self._build_path(subpath, elt)
|
|
||||||
properties = variable.attrib.get('properties', [])
|
|
||||||
if 'force_store_value' in properties or "auto_freeze" in properties:
|
|
||||||
self.force_store_values.add(path)
|
|
||||||
self.storage.add(path, variable)
|
|
||||||
return variable
|
|
||||||
|
|
||||||
def _populate_family(self, elt, subpath):
|
|
||||||
if subpath is None:
|
|
||||||
force_icon = False
|
|
||||||
else:
|
|
||||||
force_icon = not subpath.startswith('containers') and not subpath.startswith('actions')
|
|
||||||
family = Family(elt, self.booleans, self.storage, self.eosfunc, force_icon)
|
|
||||||
path = self._build_path(subpath, elt)
|
|
||||||
self.storage.add(path, family)
|
|
||||||
return family
|
|
||||||
|
|
||||||
def _build_path(self, subpath, elt):
|
|
||||||
if subpath is None:
|
|
||||||
subpath = elt.attrib['name']
|
|
||||||
else:
|
|
||||||
subpath += '.' + elt.attrib['name']
|
|
||||||
return subpath
|
|
||||||
|
|
||||||
def _iter_leader(self, leader, subpath):
|
|
||||||
subpath = self._build_path(subpath, leader)
|
|
||||||
family = Family(leader, self.booleans, self.storage, self.eosfunc)
|
|
||||||
family.set_leader()
|
|
||||||
self.storage.add(subpath, family)
|
|
||||||
leader_name = None
|
|
||||||
for var in leader:
|
|
||||||
if var.tag == 'property':
|
|
||||||
self._parse_properties(family, var)
|
|
||||||
elif var.tag == 'variable':
|
|
||||||
if leader_name is None:
|
|
||||||
leader_name = var.attrib['name']
|
|
||||||
self.groups[leader_name] = []
|
|
||||||
else:
|
|
||||||
self.groups[leader_name].append(var.attrib['name'])
|
|
||||||
self._iter_family(var, family, subpath=subpath)
|
|
||||||
else:
|
|
||||||
raise CreoleLoaderError(_('unknown tag {}').format(var.tag))
|
|
||||||
return family
|
|
||||||
|
|
||||||
def _iter_family(self, child, family, subpath=None):
|
|
||||||
if child.tag not in ['family', 'variable', 'separators', 'leader', 'property']:
|
|
||||||
raise CreoleLoaderError(_('unknown tag {}').format(child.tag))
|
|
||||||
if child.tag == 'family':
|
|
||||||
old_family = family
|
|
||||||
family = self._populate_family(child, subpath)
|
|
||||||
if old_family is not None:
|
|
||||||
old_family.add(family)
|
|
||||||
if len(child) != 0:
|
|
||||||
subpath = self._build_path(subpath, child)
|
|
||||||
for c in child:
|
|
||||||
self._iter_family(c, family, subpath=subpath)
|
|
||||||
elif child.tag == 'leader':
|
|
||||||
leader = self._iter_leader(child, subpath)
|
|
||||||
family.add(leader)
|
|
||||||
elif child.tag == 'separators':
|
|
||||||
self._parse_separators(child)
|
|
||||||
elif child.tag == 'variable':
|
|
||||||
if family is None:
|
|
||||||
raise CreoleLoaderError(_('variable without family'))
|
|
||||||
|
|
||||||
is_follower = False
|
|
||||||
is_leader = False
|
|
||||||
if family.is_leader:
|
|
||||||
if child.attrib['name'] != family.attrib['name']:
|
|
||||||
is_follower = True
|
|
||||||
else:
|
|
||||||
is_leader = True
|
|
||||||
variable = self._populate_variable(child, subpath, is_follower, is_leader)
|
|
||||||
family.add(variable)
|
|
||||||
elif child.tag == 'property':
|
|
||||||
self._parse_properties(family, child)
|
|
||||||
else:
|
|
||||||
raise Exception('unknown tag {}'.format(child.tag))
|
|
||||||
|
|
||||||
def _parse_properties(self, family, child):
|
|
||||||
if child.get('type') == 'calculation':
|
|
||||||
kwargs = {'condition': child.attrib['source'],
|
|
||||||
'expected': ParamValue(child.attrib.get('expected'))}
|
|
||||||
if child.attrib['inverse'] == 'True':
|
|
||||||
kwargs['reverse_condition'] = ParamValue(True)
|
|
||||||
family.attrib['properties'].append((ParamValue(child.text), kwargs))
|
|
||||||
else:
|
|
||||||
family.attrib['properties'].append(child.text)
|
|
||||||
|
|
||||||
def _parse_separators(self, separators):
|
|
||||||
for separator in separators:
|
|
||||||
elt = self.storage.get(separator.attrib['name'])
|
|
||||||
never_hidden = separator.attrib.get('never_hidden')
|
|
||||||
if never_hidden == 'True':
|
|
||||||
never_hidden = True
|
|
||||||
else:
|
|
||||||
never_hidden = None
|
|
||||||
info = (separator.text, never_hidden)
|
|
||||||
self.separators[separator.attrib['name']] = info
|
|
||||||
elt.add_information('separator', info)
|
|
||||||
|
|
||||||
|
|
||||||
class ElementStorage:
|
|
||||||
def __init__(self):
|
|
||||||
self.paths = {}
|
|
||||||
|
|
||||||
def add(self, path, elt):
|
|
||||||
if path in self.paths:
|
|
||||||
raise CreoleLoaderError(_('path already loaded {}').format(path))
|
|
||||||
self.paths[path] = elt
|
|
||||||
|
|
||||||
def add_information(self, path, name, information):
|
|
||||||
elt = self.get(path)
|
|
||||||
elt.add_information(name, information)
|
|
||||||
|
|
||||||
def get(self, path):
|
|
||||||
if path not in self.paths:
|
|
||||||
raise CreoleLoaderError(_('there is no element for path {}').format(path))
|
|
||||||
return self.paths[path]
|
|
||||||
|
|
||||||
|
|
||||||
class Common:
|
|
||||||
def build_properties(self):
|
|
||||||
for index, prop in enumerate(self.attrib['properties']):
|
|
||||||
if isinstance(prop, tuple):
|
|
||||||
action, kwargs = prop
|
|
||||||
kwargs['condition'] = ParamOption(self.storage.get(kwargs['condition']).get(), todict=True)
|
|
||||||
prop = Calculation(calc_value,
|
|
||||||
Params(action,
|
|
||||||
kwargs=kwargs))
|
|
||||||
self.attrib['properties'][index] = prop
|
|
||||||
if self.attrib['properties']:
|
|
||||||
self.attrib['properties'] = tuple(self.attrib['properties'])
|
|
||||||
else:
|
|
||||||
del self.attrib['properties']
|
|
||||||
|
|
||||||
|
|
||||||
class Variable(Common):
|
|
||||||
def __init__(self, elt, booleans, storage, is_follower, is_leader, eosfunc):
|
|
||||||
self.option = None
|
|
||||||
self.informations = {}
|
|
||||||
self.attrib = {}
|
|
||||||
self.attrib['properties'] = []
|
|
||||||
self.attrib['validators'] = []
|
|
||||||
self.eosfunc = eosfunc
|
|
||||||
self.storage = storage
|
|
||||||
is_submulti = False
|
|
||||||
for key, value in elt.attrib.items():
|
|
||||||
if key in booleans:
|
|
||||||
if value == 'True':
|
|
||||||
value = True
|
|
||||||
elif value == 'False':
|
|
||||||
value = False
|
|
||||||
elif key == 'multi' and value == 'submulti':
|
|
||||||
is_submulti = True
|
|
||||||
value = submulti
|
|
||||||
else:
|
|
||||||
raise CreoleLoaderError(_('unknown value {} for {}').format(value, key))
|
|
||||||
if key in ['help', 'test']:
|
|
||||||
self.add_information(key, value)
|
|
||||||
elif key == 'type':
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.attrib[key] = value
|
|
||||||
convert_option = CONVERT_OPTION[elt.attrib['type']]
|
|
||||||
self.object_type = convert_option['opttype']
|
|
||||||
if elt.attrib['type'] == 'choice':
|
|
||||||
if self.attrib.get('choice'):
|
|
||||||
self.attrib['values'] = getattr(self.eosfunc, self.attrib.get('choice'))
|
|
||||||
else:
|
|
||||||
self.attrib['values'] = []
|
|
||||||
for child in elt:
|
|
||||||
if child.tag == 'choice':
|
|
||||||
value = child.text
|
|
||||||
if 'type' in child.attrib and child.attrib['type'] == 'number':
|
|
||||||
value = int(value)
|
|
||||||
if value is None:
|
|
||||||
value = u''
|
|
||||||
self.attrib['values'].append(value)
|
|
||||||
self.attrib['values'] = tuple(self.attrib['values'])
|
|
||||||
for child in elt:
|
|
||||||
if child.tag == 'property':
|
|
||||||
if child.get('type') == 'calculation':
|
|
||||||
kwargs = {'condition': child.attrib['source'],
|
|
||||||
'expected': ParamValue(child.attrib.get('expected'))}
|
|
||||||
if child.attrib['inverse'] == 'True':
|
|
||||||
kwargs['reverse_condition'] = ParamValue(True)
|
|
||||||
self.attrib['properties'].append((ParamValue(child.text), kwargs))
|
|
||||||
else:
|
|
||||||
self.attrib['properties'].append(child.text)
|
|
||||||
elif child.tag == 'value':
|
|
||||||
if child.attrib.get('type') == 'calculation':
|
|
||||||
if child.text is not None and child.text.strip():
|
|
||||||
self.attrib['default'] = (child.text.strip(),)
|
|
||||||
else:
|
|
||||||
params = []
|
|
||||||
for param in child:
|
|
||||||
params.append(self.parse_param(param))
|
|
||||||
self.attrib['default'] = (child.attrib['name'], params, False)
|
|
||||||
else:
|
|
||||||
if "type" in child.attrib:
|
|
||||||
type_ = CONVERT_OPTION[child.attrib['type']]['opttype']
|
|
||||||
else:
|
|
||||||
type_ = self.object_type
|
|
||||||
if self.attrib['multi'] is True and not is_follower:
|
|
||||||
if 'default' not in self.attrib:
|
|
||||||
self.attrib['default'] = []
|
|
||||||
value = convert_tiramisu_value(child.text, type_)
|
|
||||||
self.attrib['default'].append(value)
|
|
||||||
if 'default_multi' not in self.attrib and not is_leader:
|
|
||||||
self.attrib['default_multi'] = value
|
|
||||||
elif self.attrib['multi'] == submulti:
|
|
||||||
if 'default' not in self.attrib:
|
|
||||||
self.attrib['default'] = []
|
|
||||||
value = convert_tiramisu_value(child.text, type_)
|
|
||||||
if not isinstance(value, list) and not is_follower:
|
|
||||||
value = [value]
|
|
||||||
self.attrib['default'].append(value)
|
|
||||||
if 'default_multi' not in self.attrib and not is_leader:
|
|
||||||
self.attrib['default_multi'] = value
|
|
||||||
else:
|
|
||||||
if 'default' in self.attrib:
|
|
||||||
raise CreoleLoaderError(_('default value already set for {}'
|
|
||||||
'').format(self.attrib['path']))
|
|
||||||
value = convert_tiramisu_value(child.text, type_)
|
|
||||||
if value is None: # and (elt.attrib['type'] != 'choice' or value not in self.attrib['values']):
|
|
||||||
value = u''
|
|
||||||
if is_follower:
|
|
||||||
self.attrib['default_multi'] = value
|
|
||||||
else:
|
|
||||||
self.attrib['default'] = value
|
|
||||||
elif child.tag == 'choice':
|
|
||||||
# already load
|
|
||||||
pass
|
|
||||||
elif child.tag == 'check':
|
|
||||||
params = []
|
|
||||||
for param in child:
|
|
||||||
params.append(self.parse_param(param))
|
|
||||||
#check.params = params
|
|
||||||
self.attrib['validators'].append((child.attrib['name'], params, child.attrib['warnings_only']))
|
|
||||||
else:
|
|
||||||
raise Exception('unknown tag {}'.format(child.tag))
|
|
||||||
if 'initkwargs' in convert_option:
|
|
||||||
self.attrib.update(convert_option['initkwargs'])
|
|
||||||
if elt.attrib['type'] == 'symlink':
|
|
||||||
del self.attrib['properties']
|
|
||||||
del self.attrib['multi']
|
|
||||||
self.attrib['opt'] = storage.get(self.attrib['opt'])
|
|
||||||
|
|
||||||
def parse_param(self, param):
|
|
||||||
name = param.attrib.get('name', '')
|
|
||||||
if param.attrib['type'] == 'string':
|
|
||||||
value = param.text
|
|
||||||
elif param.attrib['type'] == 'variable':
|
|
||||||
transitive = param.attrib.get('transitive', 'False')
|
|
||||||
if transitive == 'True':
|
|
||||||
transitive = True
|
|
||||||
elif transitive == 'False':
|
|
||||||
transitive = False
|
|
||||||
else:
|
|
||||||
raise CreoleLoaderError(_('unknown transitive boolean {}').format(transitive))
|
|
||||||
value = [param.text, transitive]
|
|
||||||
elif param.attrib['type'] == 'number':
|
|
||||||
value = int(param.text)
|
|
||||||
else:
|
|
||||||
raise CreoleLoaderError(_('unknown param type {}').format(param.attrib['type']))
|
|
||||||
return(name, value)
|
|
||||||
|
|
||||||
def add_information(self, key, value):
|
|
||||||
if key in self.informations:
|
|
||||||
raise CreoleLoaderError(_('key already exists in information {}').format(key))
|
|
||||||
self.informations[key] = value
|
|
||||||
|
|
||||||
def build_calculator(self, key):
|
|
||||||
if key in self.attrib:
|
|
||||||
values = self.attrib[key]
|
|
||||||
if isinstance(values, list):
|
|
||||||
is_list = True
|
|
||||||
else:
|
|
||||||
is_list = False
|
|
||||||
values = [values]
|
|
||||||
ret = []
|
|
||||||
for value in values:
|
|
||||||
if isinstance(value, tuple):
|
|
||||||
if key == 'validators':
|
|
||||||
args = [ParamSelfOption()]
|
|
||||||
else:
|
|
||||||
args = []
|
|
||||||
kwargs = {}
|
|
||||||
if len(value) == 3:
|
|
||||||
for param in value[1]:
|
|
||||||
if isinstance(param[1], list):
|
|
||||||
if value[0] in FUNC_TO_DICT:
|
|
||||||
param_value = ParamOption(self.storage.get(param[1][0]).get(), notraisepropertyerror=param[1][1], todict=True)
|
|
||||||
else:
|
|
||||||
param_value = ParamOption(self.storage.get(param[1][0]).get(), notraisepropertyerror=param[1][1])
|
|
||||||
else:
|
|
||||||
param_value = ParamValue(param[1])
|
|
||||||
if not param[0]:
|
|
||||||
args.append(param_value)
|
|
||||||
else:
|
|
||||||
kwargs[param[0]] = param_value
|
|
||||||
|
|
||||||
ret.append(Calculation(getattr(self.eosfunc, value[0]),
|
|
||||||
Params(tuple(args),
|
|
||||||
kwargs=kwargs)))
|
|
||||||
else:
|
|
||||||
ret.append(value)
|
|
||||||
if not is_list:
|
|
||||||
self.attrib[key] = ret[0]
|
|
||||||
else:
|
|
||||||
self.attrib[key] = ret
|
|
||||||
|
|
||||||
|
|
||||||
def get(self):
|
|
||||||
if self.option is None:
|
|
||||||
if self.object_type is SymLinkOption:
|
|
||||||
self.attrib['opt'] = self.attrib['opt'].get()
|
|
||||||
else:
|
|
||||||
self.build_properties()
|
|
||||||
self.build_calculator('default')
|
|
||||||
self.build_calculator('validators')
|
|
||||||
if not self.attrib['validators']:
|
|
||||||
del self.attrib['validators']
|
|
||||||
try:
|
|
||||||
option = self.object_type(**self.attrib)
|
|
||||||
except Exception as err:
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
name = self.attrib['name']
|
|
||||||
raise CreoleLoaderError(_('cannot create option {}: {}').format(name, err))
|
|
||||||
for key, value in self.informations.items():
|
|
||||||
option.impl_set_information(key, value)
|
|
||||||
self.option = option
|
|
||||||
return self.option
|
|
||||||
|
|
||||||
|
|
||||||
class Family(Common):
|
|
||||||
def __init__(self, elt, booleans, storage, eosfunc, force_icon=False):
|
|
||||||
self.option = None
|
|
||||||
self.attrib = {}
|
|
||||||
self.is_leader = False
|
|
||||||
if force_icon:
|
|
||||||
self.informations = {'icon': None}
|
|
||||||
else:
|
|
||||||
self.informations = {}
|
|
||||||
self.children = []
|
|
||||||
self.storage = storage
|
|
||||||
self.eosfunc = eosfunc
|
|
||||||
self.attrib['properties'] = []
|
|
||||||
for key, value in elt.attrib.items():
|
|
||||||
if key in booleans:
|
|
||||||
if value == 'True':
|
|
||||||
value = True
|
|
||||||
elif value == 'False':
|
|
||||||
value = False
|
|
||||||
else:
|
|
||||||
raise CreoleLoaderError(_('unknown value {} for {}').format(value, key))
|
|
||||||
if key == 'icon':
|
|
||||||
self.add_information('icon', value)
|
|
||||||
continue
|
|
||||||
elif key == 'hidden':
|
|
||||||
if value:
|
|
||||||
self.attrib['properties'].append(key)
|
|
||||||
elif key == 'mode':
|
|
||||||
self.attrib['properties'].append(value)
|
|
||||||
elif key == 'help':
|
|
||||||
self.add_information(key, value)
|
|
||||||
elif key == 'type':
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.attrib[key] = value
|
|
||||||
if 'doc' not in self.attrib:
|
|
||||||
self.attrib['doc'] = u''
|
|
||||||
|
|
||||||
def add(self, child):
|
|
||||||
self.children.append(child)
|
|
||||||
|
|
||||||
def add_information(self, key, value):
|
|
||||||
if key in self.informations and not (key == 'icon' and self.informations[key] is None):
|
|
||||||
raise CreoleLoaderError(_('key already exists in information {}').format(key))
|
|
||||||
self.informations[key] = value
|
|
||||||
|
|
||||||
def set_leader(self):
|
|
||||||
self.is_leader = True
|
|
||||||
|
|
||||||
def get(self):
|
|
||||||
if self.option is None:
|
|
||||||
self.attrib['children'] = []
|
|
||||||
for child in self.children:
|
|
||||||
self.attrib['children'].append(child.get())
|
|
||||||
self.build_properties()
|
|
||||||
try:
|
|
||||||
if 'dynamic' in self.attrib:
|
|
||||||
dynamic = self.storage.get(self.attrib['dynamic']).get()
|
|
||||||
del self.attrib['dynamic']
|
|
||||||
self.attrib['suffixes'] = Calculation(self.eosfunc.calc_value,
|
|
||||||
Params((ParamOption(dynamic),)))
|
|
||||||
option = ConvertDynOptionDescription(**self.attrib)
|
|
||||||
elif not self.is_leader:
|
|
||||||
option = OptionDescription(**self.attrib)
|
|
||||||
else:
|
|
||||||
option = Leadership(**self.attrib)
|
|
||||||
except Exception as err:
|
|
||||||
raise CreoleLoaderError(_('cannot create optiondescription {}: {}').format(self.attrib['name'], err))
|
|
||||||
for key, value in self.informations.items():
|
|
||||||
option.impl_set_information(key, value)
|
|
||||||
self.option = option
|
|
||||||
#if self.is_leader:
|
|
||||||
# self.option.impl_set_group_type(groups.leader)
|
|
||||||
|
|
||||||
return self.option
|
|
||||||
|
|
||||||
|
|
||||||
def load(xmlroot: str,
|
|
||||||
dtd_path: str,
|
|
||||||
funcs_path: str):
|
|
||||||
tiramisu_objects = PopulateTiramisuObjects()
|
|
||||||
tiramisu_objects.parse_dtd(dtd_path)
|
|
||||||
tiramisu_objects.make_tiramisu_objects(xmlroot,
|
|
||||||
funcs_path)
|
|
||||||
return tiramisu_objects.storage.paths['.'].get()
|
|
|
@ -4,11 +4,11 @@ as an input and outputs a human readable flatened XML
|
||||||
|
|
||||||
Sample usage::
|
Sample usage::
|
||||||
|
|
||||||
>>> from creole.objspace import CreoleObjSpace
|
>>> from rougail.objspace import CreoleObjSpace
|
||||||
>>> eolobj = CreoleObjSpace('/usr/share/creole/creole.dtd')
|
>>> eolobj = CreoleObjSpace('/usr/share/rougail/rougail.dtd')
|
||||||
>>> eolobj.create_or_populate_from_xml('creole', ['/usr/share/eole/creole/dicos'])
|
>>> eolobj.create_or_populate_from_xml('rougail', ['/usr/share/eole/rougail/dicos'])
|
||||||
>>> eolobj.space_visitor()
|
>>> eolobj.space_visitor()
|
||||||
>>> eolobj.save('/tmp/creole_flatened_output.xml')
|
>>> eolobj.save('/tmp/rougail_flatened_output.xml')
|
||||||
|
|
||||||
The CreoleObjSpace
|
The CreoleObjSpace
|
||||||
|
|
||||||
|
@ -23,204 +23,234 @@ For example: a variable is redefined and shall be moved to another family
|
||||||
means that a variable1 = Variable() object in the object space who lives in the family1 parent
|
means that a variable1 = Variable() object in the object space who lives in the family1 parent
|
||||||
has to be moved in family2. The visit procedure changes the varable1's object space's parent.
|
has to be moved in family2. The visit procedure changes the varable1's object space's parent.
|
||||||
"""
|
"""
|
||||||
from collections import OrderedDict
|
|
||||||
from lxml.etree import Element, SubElement # pylint: disable=E0611
|
from lxml.etree import Element, SubElement # pylint: disable=E0611
|
||||||
from json import dump
|
|
||||||
|
|
||||||
|
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .xmlreflector import XMLReflector, HIGH_COMPATIBILITY
|
from .xmlreflector import XMLReflector
|
||||||
from .annotator import ERASED_ATTRIBUTES, ActionAnnotator, ServiceAnnotator, SpaceAnnotator
|
from .annotator import ERASED_ATTRIBUTES, SpaceAnnotator
|
||||||
|
from .tiramisureflector import TiramisuReflector
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
from .error import CreoleOperationError, SpaceObjShallNotBeUpdated, CreoleDictConsistencyError
|
from .error import OperationError, SpaceObjShallNotBeUpdated, DictConsistencyError
|
||||||
|
from .path import Path
|
||||||
|
from .config import variable_namespace
|
||||||
|
|
||||||
# CreoleObjSpace's elements like 'family' or 'slave', that shall be forced to the Redefinable type
|
# CreoleObjSpace's elements like 'family' or 'follower', that shall be forced to the Redefinable type
|
||||||
FORCE_REDEFINABLES = ('family', 'slave', 'service', 'disknod', 'variables', 'family_action')
|
FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables')
|
||||||
# CreoleObjSpace's elements that shall be forced to the UnRedefinable type
|
# CreoleObjSpace's elements that shall be forced to the UnRedefinable type
|
||||||
FORCE_UNREDEFINABLES = ('value', 'input', 'profile', 'ewtapp', 'tag', 'saltaction')
|
FORCE_UNREDEFINABLES = ('value',)
|
||||||
# CreoleObjSpace's elements that shall be set to the UnRedefinable type
|
# CreoleObjSpace's elements that shall be set to the UnRedefinable type
|
||||||
UNREDEFINABLE = ('submulti', 'multi', 'type')
|
UNREDEFINABLE = ('multi', 'type')
|
||||||
|
|
||||||
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
|
|
||||||
'force_store_value', 'disabled', 'mandatory')
|
|
||||||
CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']}
|
CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']}
|
||||||
|
|
||||||
RENAME_ATTIBUTES = {'description': 'doc'}
|
RENAME_ATTIBUTES = {'description': 'doc'}
|
||||||
|
|
||||||
INCOMPATIBLE_ATTRIBUTES = [['multi', 'submulti']]
|
FORCED_TEXT_ELTS_AS_NAME = ('choice', 'property', 'value', 'target')
|
||||||
|
|
||||||
#TYPE_TARGET_CONDITION = ('variable', 'family')
|
CONVERT_EXPORT = {'Leadership': 'leader',
|
||||||
|
'Variable': 'variable',
|
||||||
|
'Value': 'value',
|
||||||
|
'Property': 'property',
|
||||||
|
'Choice': 'choice',
|
||||||
|
'Param': 'param',
|
||||||
|
'Check': 'check',
|
||||||
|
}
|
||||||
|
|
||||||
# _____________________________________________________________________________
|
# _____________________________________________________________________________
|
||||||
# special types definitions for the Object Space's internal representation
|
# special types definitions for the Object Space's internal representation
|
||||||
class RootCreoleObject(object):
|
class RootCreoleObject:
|
||||||
""
|
""
|
||||||
|
|
||||||
|
|
||||||
class CreoleObjSpace(object):
|
class CreoleObjSpace:
|
||||||
"""DOM XML reflexion free internal representation of a Creole Dictionary
|
"""DOM XML reflexion free internal representation of a Creole Dictionary
|
||||||
"""
|
"""
|
||||||
choice = type('Choice', (RootCreoleObject,), OrderedDict())
|
choice = type('Choice', (RootCreoleObject,), dict())
|
||||||
property_ = type('Property', (RootCreoleObject,), OrderedDict())
|
property_ = type('Property', (RootCreoleObject,), dict())
|
||||||
# Creole ObjectSpace's Leadership variable class type
|
# Creole ObjectSpace's Leadership variable class type
|
||||||
Leadership = type('Leadership', (RootCreoleObject,), OrderedDict())
|
Leadership = type('Leadership', (RootCreoleObject,), dict())
|
||||||
"""
|
"""
|
||||||
This Atom type stands for singleton, that is
|
This Atom type stands for singleton, that is
|
||||||
an Object Space's atom object is present only once in the
|
an Object Space's atom object is present only once in the
|
||||||
object space's tree
|
object space's tree
|
||||||
"""
|
"""
|
||||||
Atom = type('Atom', (RootCreoleObject,), OrderedDict())
|
Atom = type('Atom', (RootCreoleObject,), dict())
|
||||||
"A variable that can't be redefined"
|
"A variable that can't be redefined"
|
||||||
Redefinable = type('Redefinable', (RootCreoleObject,), OrderedDict())
|
Redefinable = type('Redefinable', (RootCreoleObject,), dict())
|
||||||
"A variable can be redefined"
|
"A variable can be redefined"
|
||||||
UnRedefinable = type('UnRedefinable', (RootCreoleObject,), OrderedDict())
|
UnRedefinable = type('UnRedefinable', (RootCreoleObject,), dict())
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, dtdfilename): # pylint: disable=R0912
|
def __init__(self, dtdfilename): # pylint: disable=R0912
|
||||||
self.index = 0
|
self.index = 0
|
||||||
class ObjSpace(object): # pylint: disable=R0903
|
class ObjSpace: # pylint: disable=R0903
|
||||||
"""
|
"""
|
||||||
Base object space
|
Base object space
|
||||||
"""
|
"""
|
||||||
self.space = ObjSpace()
|
self.space = ObjSpace()
|
||||||
|
self.paths = Path()
|
||||||
self.xmlreflector = XMLReflector()
|
self.xmlreflector = XMLReflector()
|
||||||
self.xmlreflector.parse_dtd(dtdfilename)
|
self.xmlreflector.parse_dtd(dtdfilename)
|
||||||
self.redefine_variables = None
|
self.redefine_variables = None
|
||||||
self.probe_variables = []
|
self.check_removed = None
|
||||||
|
self.condition_removed = None
|
||||||
|
|
||||||
# ['variable', 'separator', 'family']
|
# ['variable', 'separator', 'family']
|
||||||
self.forced_text_elts = set()
|
self.forced_text_elts = set()
|
||||||
self.forced_text_elts_as_name = set(['choice', 'property'])
|
self.forced_text_elts_as_name = set(FORCED_TEXT_ELTS_AS_NAME)
|
||||||
self.forced_choice_option = {}
|
|
||||||
self.paths = Path()
|
|
||||||
self.list_conditions = {}
|
self.list_conditions = {}
|
||||||
|
|
||||||
self.booleans_attributs = []
|
self.booleans_attributs = []
|
||||||
|
|
||||||
for elt in self.xmlreflector.dtd.iterelements():
|
self.make_object_space_class()
|
||||||
|
|
||||||
|
def make_object_space_class(self):
|
||||||
|
"""Create Rougail ObjectSpace class types, it enables us to create objects like:
|
||||||
|
File(), Variable(), Ip(), Family(), Constraints()... and so on.
|
||||||
|
|
||||||
|
Creole ObjectSpace is an object's reflexion of the XML elements"""
|
||||||
|
|
||||||
|
for dtd_elt in self.xmlreflector.dtd.iterelements():
|
||||||
attrs = {}
|
attrs = {}
|
||||||
clstype = self.UnRedefinable
|
if dtd_elt.name in FORCE_REDEFINABLES:
|
||||||
atomic = True
|
|
||||||
forced_text_elt = False
|
|
||||||
if elt.type == 'mixed':
|
|
||||||
forced_text_elt = True
|
|
||||||
if elt.name == 'service':
|
|
||||||
self.parse_dtd_right_left_elt(elt.content)
|
|
||||||
for attr in elt.iterattributes():
|
|
||||||
atomic = False
|
|
||||||
if attr.default_value:
|
|
||||||
if attr.default_value == 'True':
|
|
||||||
default_value = True
|
|
||||||
elif attr.default_value == 'False':
|
|
||||||
default_value = False
|
|
||||||
else:
|
|
||||||
default_value = attr.default_value
|
|
||||||
attrs[attr.name] = default_value
|
|
||||||
if not attr.name.endswith('_type'):
|
|
||||||
values = list(attr.itervalues())
|
|
||||||
if values != []:
|
|
||||||
self.forced_choice_option.setdefault(elt.name, {})[attr.name] = values
|
|
||||||
|
|
||||||
if attr.name == 'redefine':
|
|
||||||
clstype = self.Redefinable
|
clstype = self.Redefinable
|
||||||
if attr.name == 'name' and forced_text_elt is True:
|
else:
|
||||||
self.forced_text_elts.add(elt.name)
|
clstype = self.UnRedefinable
|
||||||
|
atomic = dtd_elt.name not in FORCE_UNREDEFINABLES and dtd_elt.name not in FORCE_REDEFINABLES
|
||||||
|
forced_text_elt = dtd_elt.type == 'mixed'
|
||||||
|
for dtd_attr in dtd_elt.iterattributes():
|
||||||
|
atomic = False
|
||||||
|
if set(dtd_attr.itervalues()) == set(['True', 'False']):
|
||||||
|
# it's a boolean
|
||||||
|
self.booleans_attributs.append(dtd_attr.name)
|
||||||
|
if dtd_attr.default_value:
|
||||||
|
# set default value for this attribute
|
||||||
|
default_value = dtd_attr.default_value
|
||||||
|
if dtd_attr.name in self.booleans_attributs:
|
||||||
|
default_value = self.convert_boolean(dtd_attr.default_value)
|
||||||
|
attrs[dtd_attr.name] = default_value
|
||||||
|
if dtd_attr.name == 'redefine':
|
||||||
|
# has a redefine attribute, so it's a Redefinable object
|
||||||
|
clstype = self.Redefinable
|
||||||
|
if dtd_attr.name == 'name' and forced_text_elt:
|
||||||
|
# child.text should be transform has a "name" attribute
|
||||||
|
self.forced_text_elts.add(dtd_elt.name)
|
||||||
forced_text_elt = False
|
forced_text_elt = False
|
||||||
|
|
||||||
if set(attr.itervalues()) == set(['True', 'False']):
|
|
||||||
self.booleans_attributs.append(attr.name)
|
|
||||||
|
|
||||||
if forced_text_elt is True:
|
if forced_text_elt is True:
|
||||||
self.forced_text_elts_as_name.add(elt.name)
|
self.forced_text_elts_as_name.add(dtd_elt.name)
|
||||||
|
if atomic:
|
||||||
if elt.name in FORCE_REDEFINABLES:
|
# has any attribute so it's an Atomic object
|
||||||
clstype = self.Redefinable
|
|
||||||
elif elt.name in FORCE_UNREDEFINABLES:
|
|
||||||
clstype = self.UnRedefinable
|
|
||||||
elif atomic:
|
|
||||||
clstype = self.Atom
|
clstype = self.Atom
|
||||||
|
|
||||||
# Creole ObjectSpace class types, it enables us to create objects like:
|
# create ObjectSpace object
|
||||||
# Service_restriction(), Ip(), Interface(), Host(), Fstab(), Package(), Disknod(),
|
setattr(self, dtd_elt.name, type(dtd_elt.name.capitalize(), (clstype,), attrs))
|
||||||
# File(), Variables(), Family(), Variable(), Separators(), Separator(), Value(),
|
|
||||||
# Constraints()... and so on. Creole ObjectSpace is an object's reflexion of
|
|
||||||
# the XML elements
|
|
||||||
setattr(self, elt.name, type(elt.name.capitalize(), (clstype,), attrs))
|
|
||||||
|
|
||||||
def parse_dtd_right_left_elt(self, elt):
|
def create_or_populate_from_xml(self,
|
||||||
if elt.right.type == 'or':
|
namespace,
|
||||||
self.parse_dtd_right_left_elt(elt.right)
|
xmlfolders):
|
||||||
|
"""Parses a bunch of XML files
|
||||||
def _convert_boolean(self, value): # pylint: disable=R0201
|
populates the CreoleObjSpace
|
||||||
"""Boolean coercion. The Creole XML may contain srings like `True` or `False`
|
|
||||||
"""
|
"""
|
||||||
if isinstance(value, bool):
|
for xmlfile, document in self.xmlreflector.load_xml_from_folders(xmlfolders):
|
||||||
return value
|
self.redefine_variables = []
|
||||||
if value == 'True':
|
self.check_removed = []
|
||||||
return True
|
self.condition_removed = []
|
||||||
elif value == 'False':
|
self.xml_parse_document(document,
|
||||||
return False
|
self.space,
|
||||||
else:
|
namespace,
|
||||||
raise TypeError(_('{} is not True or False').format(value)) # pragma: no cover
|
)
|
||||||
|
|
||||||
def _is_already_exists(self, name, space, child, namespace):
|
def xml_parse_document(self,
|
||||||
if isinstance(space, self.family): # pylint: disable=E1101
|
document,
|
||||||
if namespace != 'creole':
|
space,
|
||||||
name = space.path + '.' + name
|
namespace,
|
||||||
return self.paths.path_is_defined(name)
|
):
|
||||||
if child.tag in ['family', 'family_action']:
|
"""Parses a Creole XML file
|
||||||
norm_name = normalize_family(name)
|
populates the CreoleObjSpace
|
||||||
else:
|
"""
|
||||||
norm_name = name
|
family_names = []
|
||||||
return norm_name in getattr(space, child.tag, {})
|
for child in document:
|
||||||
|
# this index enables us to reorder objects
|
||||||
|
self.index += 1
|
||||||
|
# doesn't proceed the XML commentaries
|
||||||
|
if not isinstance(child.tag, str):
|
||||||
|
continue
|
||||||
|
if child.tag == 'family':
|
||||||
|
if child.attrib['name'] in family_names:
|
||||||
|
raise DictConsistencyError(_('Family {} is set several times').format(child.attrib['name']))
|
||||||
|
family_names.append(child.attrib['name'])
|
||||||
|
if child.tag == 'variables':
|
||||||
|
child.attrib['name'] = namespace
|
||||||
|
if child.tag == 'value' and child.text == None:
|
||||||
|
# FIXME should not be here
|
||||||
|
continue
|
||||||
|
# variable objects creation
|
||||||
|
try:
|
||||||
|
variableobj = self.generate_variableobj(child,
|
||||||
|
space,
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
|
except SpaceObjShallNotBeUpdated:
|
||||||
|
continue
|
||||||
|
self.set_text_to_obj(child,
|
||||||
|
variableobj,
|
||||||
|
)
|
||||||
|
self.set_xml_attributes_to_obj(child,
|
||||||
|
variableobj,
|
||||||
|
)
|
||||||
|
self.variableobj_tree_visitor(child,
|
||||||
|
variableobj,
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
|
self.fill_variableobj_path_attribute(space,
|
||||||
|
child,
|
||||||
|
namespace,
|
||||||
|
document,
|
||||||
|
variableobj,
|
||||||
|
)
|
||||||
|
self.add_to_tree_structure(variableobj,
|
||||||
|
space,
|
||||||
|
child,
|
||||||
|
)
|
||||||
|
if list(child) != []:
|
||||||
|
self.xml_parse_document(child,
|
||||||
|
variableobj,
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
|
|
||||||
def _translate_in_space(self, name, family, variable, namespace):
|
def generate_variableobj(self,
|
||||||
if not isinstance(family, self.family): # pylint: disable=E1101
|
child,
|
||||||
if variable.tag in ['family', 'family_action']:
|
space,
|
||||||
norm_name = normalize_family(name)
|
namespace,
|
||||||
else:
|
):
|
||||||
norm_name = name
|
"""
|
||||||
return getattr(family, variable.tag)[norm_name]
|
instanciates or creates Creole Object Subspace objects
|
||||||
if namespace == 'creole':
|
"""
|
||||||
path = name
|
variableobj = getattr(self, child.tag)()
|
||||||
else:
|
if isinstance(variableobj, self.Redefinable):
|
||||||
path = family.path + '.' + name
|
variableobj = self.create_or_update_redefinable_object(child.attrib,
|
||||||
old_family_name = self.paths.get_variable_family_name(path)
|
space,
|
||||||
if normalize_family(family.name) == old_family_name:
|
child,
|
||||||
return getattr(family, variable.tag)[name]
|
namespace,
|
||||||
old_family = self.space.variables['creole'].family[old_family_name] # pylint: disable=E1101
|
)
|
||||||
variable_obj = old_family.variable[name]
|
elif isinstance(variableobj, self.Atom) and child.tag in vars(space):
|
||||||
del old_family.variable[name]
|
# instanciates an object from the CreoleObjSpace's builtins types
|
||||||
if 'variable' not in vars(family):
|
# example : child.tag = constraints -> a self.Constraints() object is created
|
||||||
family.variable = OrderedDict()
|
# this Atom instance has to be a singleton here
|
||||||
family.variable[name] = variable_obj
|
# we do not re-create it, we reuse it
|
||||||
self.paths.append('variable', name, namespace, family.name, variable_obj)
|
variableobj = getattr(space, child.tag)
|
||||||
return variable_obj
|
self.create_tree_structure(space,
|
||||||
|
child,
|
||||||
|
variableobj,
|
||||||
|
)
|
||||||
|
return variableobj
|
||||||
|
|
||||||
def remove_check(self, name): # pylint: disable=C0111
|
def create_or_update_redefinable_object(self,
|
||||||
if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'check'):
|
subspace,
|
||||||
remove_checks = []
|
space,
|
||||||
for idx, check in enumerate(self.space.constraints.check): # pylint: disable=E1101
|
child,
|
||||||
if hasattr(check, 'target') and check.target == name:
|
namespace,
|
||||||
remove_checks.append(idx)
|
):
|
||||||
|
|
||||||
remove_checks = list(set(remove_checks))
|
|
||||||
remove_checks.sort(reverse=True)
|
|
||||||
for idx in remove_checks:
|
|
||||||
self.space.constraints.check.pop(idx) # pylint: disable=E1101
|
|
||||||
def remove_condition(self, name): # pylint: disable=C0111
|
|
||||||
for idx, condition in enumerate(self.space.constraints.condition): # pylint: disable=E1101
|
|
||||||
remove_targets = []
|
|
||||||
if hasattr(condition, 'target'):
|
|
||||||
for target_idx, target in enumerate(condition.target):
|
|
||||||
if target.name == name:
|
|
||||||
remove_targets.append(target_idx)
|
|
||||||
remove_targets = list(set(remove_targets))
|
|
||||||
remove_targets.sort(reverse=True)
|
|
||||||
for idx in remove_targets:
|
|
||||||
del condition.target[idx]
|
|
||||||
|
|
||||||
def create_or_update_space_object(self, subspace, space, child, namespace):
|
|
||||||
"""Creates or retrieves the space object that corresponds
|
"""Creates or retrieves the space object that corresponds
|
||||||
to the `child` XML object
|
to the `child` XML object
|
||||||
|
|
||||||
|
@ -249,448 +279,251 @@ class CreoleObjSpace(object):
|
||||||
name = child.text
|
name = child.text
|
||||||
else:
|
else:
|
||||||
name = subspace['name']
|
name = subspace['name']
|
||||||
if self._is_already_exists(name, space, child, namespace):
|
if self.is_already_exists(name,
|
||||||
if child.tag in FORCE_REDEFINABLES:
|
space,
|
||||||
redefine = self._convert_boolean(subspace.get('redefine', True))
|
child,
|
||||||
else:
|
namespace,
|
||||||
redefine = self._convert_boolean(subspace.get('redefine', False))
|
):
|
||||||
exists = self._convert_boolean(subspace.get('exists', True))
|
default_redefine = child.tag in FORCE_REDEFINABLES
|
||||||
|
redefine = self.convert_boolean(subspace.get('redefine', default_redefine))
|
||||||
|
exists = self.convert_boolean(subspace.get('exists', True))
|
||||||
if redefine is True:
|
if redefine is True:
|
||||||
return self._translate_in_space(name, space, child, namespace)
|
return self.translate_in_space(name,
|
||||||
|
space,
|
||||||
|
child,
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
elif exists is False:
|
elif exists is False:
|
||||||
raise SpaceObjShallNotBeUpdated()
|
raise SpaceObjShallNotBeUpdated()
|
||||||
else:
|
raise DictConsistencyError(_(f'Already present in another XML file, {name} cannot be re-created'))
|
||||||
raise CreoleDictConsistencyError(_('Already present in another XML file, {} '
|
redefine = self.convert_boolean(subspace.get('redefine', False))
|
||||||
'cannot be re-created').format(name))
|
exists = self.convert_boolean(subspace.get('exists', False))
|
||||||
else:
|
|
||||||
redefine = self._convert_boolean(subspace.get('redefine', False))
|
|
||||||
exists = self._convert_boolean(subspace.get('exists', False))
|
|
||||||
if redefine is False or exists is True:
|
if redefine is False or exists is True:
|
||||||
return getattr(self, child.tag)()
|
return getattr(self, child.tag)()
|
||||||
else:
|
raise DictConsistencyError(_(f'Redefined object: {name} does not exist yet'))
|
||||||
raise CreoleDictConsistencyError(_('Redefined object: '
|
|
||||||
'{} does not exist yet').format(name))
|
|
||||||
|
|
||||||
def generate_creoleobj(self, child, space, namespace):
|
def create_tree_structure(self,
|
||||||
"""
|
space,
|
||||||
instanciates or creates Creole Object Subspace objects
|
child,
|
||||||
"""
|
variableobj,
|
||||||
if issubclass(getattr(self, child.tag), self.Redefinable):
|
): # pylint: disable=R0201
|
||||||
creoleobj = self.create_or_update_space_object(child.attrib, space, child, namespace)
|
|
||||||
else:
|
|
||||||
# instanciates an object from the CreoleObjSpace's builtins types
|
|
||||||
# example : child.tag = constraints -> a self.Constraints() object is created
|
|
||||||
creoleobj = getattr(self, child.tag)()
|
|
||||||
# this Atom instance has to be a singleton here
|
|
||||||
# we do not re-create it, we reuse it
|
|
||||||
if isinstance(creoleobj, self.Atom) and child.tag in vars(space):
|
|
||||||
creoleobj = getattr(space, child.tag)
|
|
||||||
self.create_tree_structure(space, child, creoleobj)
|
|
||||||
return creoleobj
|
|
||||||
|
|
||||||
def create_tree_structure(self, space, child, creoleobj): # pylint: disable=R0201
|
|
||||||
"""
|
"""
|
||||||
Builds the tree structure of the object space here
|
Builds the tree structure of the object space here
|
||||||
we set services attributes in order to be populated later on
|
we set services attributes in order to be populated later on
|
||||||
for example::
|
for example::
|
||||||
|
|
||||||
space = Family()
|
space = Family()
|
||||||
space.variable = OrderedDict()
|
space.variable = dict()
|
||||||
another example:
|
another example:
|
||||||
space = Variable()
|
space = Variable()
|
||||||
space.value = list()
|
space.value = list()
|
||||||
"""
|
"""
|
||||||
if child.tag not in vars(space):
|
if child.tag not in vars(space):
|
||||||
if isinstance(creoleobj, self.Redefinable):
|
if isinstance(variableobj, self.Redefinable):
|
||||||
setattr(space, child.tag, OrderedDict())
|
setattr(space, child.tag, dict())
|
||||||
elif isinstance(creoleobj, self.UnRedefinable):
|
elif isinstance(variableobj, self.UnRedefinable):
|
||||||
setattr(space, child.tag, [])
|
setattr(space, child.tag, [])
|
||||||
elif isinstance(creoleobj, self.Atom):
|
elif not isinstance(variableobj, self.Atom): # pragma: no cover
|
||||||
pass
|
raise OperationError(_("Creole object {} "
|
||||||
else: # pragma: no cover
|
"has a wrong type").format(type(variableobj)))
|
||||||
raise CreoleOperationError(_("Creole object {} "
|
|
||||||
"has a wrong type").format(type(creoleobj)))
|
|
||||||
|
|
||||||
def _add_to_tree_structure(self, creoleobj, space, child): # pylint: disable=R0201
|
def is_already_exists(self, name, space, child, namespace):
|
||||||
if isinstance(creoleobj, self.Redefinable):
|
if isinstance(space, self.family): # pylint: disable=E1101
|
||||||
name = creoleobj.name
|
if namespace != variable_namespace:
|
||||||
if child.tag == 'family' or child.tag == 'family_action':
|
name = space.path + '.' + name
|
||||||
name = normalize_family(name)
|
return self.paths.path_is_defined(name)
|
||||||
getattr(space, child.tag)[name] = creoleobj
|
if child.tag == 'family':
|
||||||
elif isinstance(creoleobj, self.UnRedefinable):
|
norm_name = normalize_family(name)
|
||||||
getattr(space, child.tag).append(creoleobj)
|
|
||||||
else:
|
else:
|
||||||
setattr(space, child.tag, creoleobj)
|
norm_name = name
|
||||||
|
return norm_name in getattr(space, child.tag, {})
|
||||||
|
|
||||||
def _set_text_to_obj(self, child, creoleobj):
|
def convert_boolean(self, value): # pylint: disable=R0201
|
||||||
|
"""Boolean coercion. The Creole XML may contain srings like `True` or `False`
|
||||||
|
"""
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
if value == 'True':
|
||||||
|
return True
|
||||||
|
elif value == 'False':
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise TypeError(_('{} is not True or False').format(value)) # pragma: no cover
|
||||||
|
|
||||||
|
def translate_in_space(self,
|
||||||
|
name,
|
||||||
|
family,
|
||||||
|
variable,
|
||||||
|
namespace,
|
||||||
|
):
|
||||||
|
if not isinstance(family, self.family): # pylint: disable=E1101
|
||||||
|
if variable.tag == 'family':
|
||||||
|
norm_name = normalize_family(name)
|
||||||
|
else:
|
||||||
|
norm_name = name
|
||||||
|
return getattr(family, variable.tag)[norm_name]
|
||||||
|
if namespace == variable_namespace:
|
||||||
|
path = name
|
||||||
|
else:
|
||||||
|
path = family.path + '.' + name
|
||||||
|
old_family_name = self.paths.get_variable_family_name(path)
|
||||||
|
if normalize_family(family.name) == old_family_name:
|
||||||
|
return getattr(family, variable.tag)[name]
|
||||||
|
old_family = self.space.variables[variable_namespace].family[old_family_name] # pylint: disable=E1101
|
||||||
|
variable_obj = old_family.variable[name]
|
||||||
|
del old_family.variable[name]
|
||||||
|
if 'variable' not in vars(family):
|
||||||
|
family.variable = dict()
|
||||||
|
family.variable[name] = variable_obj
|
||||||
|
self.paths.add_variable(namespace,
|
||||||
|
name,
|
||||||
|
family.name,
|
||||||
|
False,
|
||||||
|
variable_obj,
|
||||||
|
)
|
||||||
|
return variable_obj
|
||||||
|
|
||||||
|
def remove_check(self, name): # pylint: disable=C0111
|
||||||
|
if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'check'):
|
||||||
|
remove_checks = []
|
||||||
|
for idx, check in enumerate(self.space.constraints.check): # pylint: disable=E1101
|
||||||
|
if hasattr(check, 'target') and check.target == name:
|
||||||
|
remove_checks.append(idx)
|
||||||
|
|
||||||
|
remove_checks = list(set(remove_checks))
|
||||||
|
remove_checks.sort(reverse=True)
|
||||||
|
for idx in remove_checks:
|
||||||
|
self.space.constraints.check.pop(idx) # pylint: disable=E1101
|
||||||
|
|
||||||
|
def remove_condition(self, name): # pylint: disable=C0111
|
||||||
|
for idx, condition in enumerate(self.space.constraints.condition): # pylint: disable=E1101
|
||||||
|
remove_targets = []
|
||||||
|
if hasattr(condition, 'target'):
|
||||||
|
for target_idx, target in enumerate(condition.target):
|
||||||
|
if target.name == name:
|
||||||
|
remove_targets.append(target_idx)
|
||||||
|
remove_targets = list(set(remove_targets))
|
||||||
|
remove_targets.sort(reverse=True)
|
||||||
|
for idx in remove_targets:
|
||||||
|
del condition.target[idx]
|
||||||
|
|
||||||
|
def add_to_tree_structure(self,
|
||||||
|
variableobj,
|
||||||
|
space,
|
||||||
|
child,
|
||||||
|
): # pylint: disable=R0201
|
||||||
|
if isinstance(variableobj, self.Redefinable):
|
||||||
|
name = variableobj.name
|
||||||
|
if child.tag == 'family':
|
||||||
|
name = normalize_family(name)
|
||||||
|
getattr(space, child.tag)[name] = variableobj
|
||||||
|
elif isinstance(variableobj, self.UnRedefinable):
|
||||||
|
getattr(space, child.tag).append(variableobj)
|
||||||
|
else:
|
||||||
|
setattr(space, child.tag, variableobj)
|
||||||
|
|
||||||
|
def set_text_to_obj(self,
|
||||||
|
child,
|
||||||
|
variableobj,
|
||||||
|
):
|
||||||
if child.text is None:
|
if child.text is None:
|
||||||
text = None
|
text = None
|
||||||
else:
|
else:
|
||||||
text = child.text.strip()
|
text = child.text.strip()
|
||||||
if text:
|
if text:
|
||||||
if child.tag in self.forced_text_elts_as_name:
|
if child.tag in self.forced_text_elts_as_name:
|
||||||
creoleobj.name = text
|
variableobj.name = text
|
||||||
else:
|
else:
|
||||||
creoleobj.text = text
|
variableobj.text = text
|
||||||
|
|
||||||
def _set_xml_attributes_to_obj(self, child, creoleobj):
|
def set_xml_attributes_to_obj(self,
|
||||||
redefine = self._convert_boolean(child.attrib.get('redefine', False))
|
child,
|
||||||
has_value = hasattr(creoleobj, 'value')
|
variableobj,
|
||||||
if HIGH_COMPATIBILITY and has_value:
|
):
|
||||||
has_value = len(child) != 1 or child[0].text != None
|
redefine = self.convert_boolean(child.attrib.get('redefine', False))
|
||||||
if (redefine is True and child.tag == 'variable' and has_value
|
has_value = hasattr(variableobj, 'value')
|
||||||
and len(child) != 0):
|
if redefine is True and child.tag == 'variable' and has_value and len(child) != 0:
|
||||||
del creoleobj.value
|
del variableobj.value
|
||||||
for attr, val in child.attrib.items():
|
for attr, val in child.attrib.items():
|
||||||
if redefine and attr in UNREDEFINABLE:
|
if redefine and attr in UNREDEFINABLE:
|
||||||
# UNREDEFINABLE concerns only 'variable' node so we can fix name
|
# UNREDEFINABLE concerns only 'variable' node so we can fix name
|
||||||
# to child.attrib['name']
|
# to child.attrib['name']
|
||||||
name = child.attrib['name']
|
name = child.attrib['name']
|
||||||
raise CreoleDictConsistencyError(_("cannot redefine attribute {} for variable {}").format(attr, name))
|
raise DictConsistencyError(_(f'cannot redefine attribute {attr} for variable {name}'))
|
||||||
if isinstance(getattr(creoleobj, attr, None), bool):
|
if attr in self.booleans_attributs:
|
||||||
if val == 'False':
|
val = self.convert_boolean(val)
|
||||||
val = False
|
if not (attr == 'name' and getattr(variableobj, 'name', None) != None):
|
||||||
elif val == 'True':
|
setattr(variableobj, attr, val)
|
||||||
val = True
|
keys = list(vars(variableobj).keys())
|
||||||
else: # pragma: no cover
|
|
||||||
raise CreoleOperationError(_('value for {} must be True or False, '
|
|
||||||
'not {}').format(attr, val))
|
|
||||||
if not (attr == 'name' and getattr(creoleobj, 'name', None) != None):
|
|
||||||
setattr(creoleobj, attr, val)
|
|
||||||
keys = list(vars(creoleobj).keys())
|
|
||||||
for incompatible in INCOMPATIBLE_ATTRIBUTES:
|
|
||||||
found = False
|
|
||||||
for inc in incompatible:
|
|
||||||
if inc in keys:
|
|
||||||
if found:
|
|
||||||
raise CreoleDictConsistencyError(_('those attributes are incompatible {}').format(incompatible))
|
|
||||||
found = True
|
|
||||||
|
|
||||||
|
def variableobj_tree_visitor(self,
|
||||||
def _creoleobj_tree_visitor(self, child, creoleobj, namespace):
|
child,
|
||||||
|
variableobj,
|
||||||
|
namespace,
|
||||||
|
):
|
||||||
"""Creole object tree manipulations
|
"""Creole object tree manipulations
|
||||||
"""
|
"""
|
||||||
if child.tag == 'variable' and child.attrib.get('remove_check', False):
|
if child.tag == 'variable':
|
||||||
self.remove_check(creoleobj.name)
|
if child.attrib.get('remove_check', False):
|
||||||
if child.tag == 'variable' and child.attrib.get('remove_condition', False):
|
self.remove_check(variableobj.name)
|
||||||
self.remove_condition(creoleobj.name)
|
if child.attrib.get('remove_condition', False):
|
||||||
if child.tag in ['auto', 'fill', 'check']:
|
self.remove_condition(variableobj.name)
|
||||||
variable_name = child.attrib['target']
|
if child.tag == 'fill':
|
||||||
# XXX not working with variable not in creole and in leader/followers
|
# if variable is a redefine in current dictionary
|
||||||
if variable_name in self.redefine_variables:
|
# XXX not working with variable not in variable and in leader/followers
|
||||||
creoleobj.redefine = True
|
variableobj.redefine = child.attrib['target'] in self.redefine_variables
|
||||||
else:
|
if not hasattr(variableobj, 'index'):
|
||||||
creoleobj.redefine = False
|
variableobj.index = self.index
|
||||||
if not hasattr(creoleobj, 'index'):
|
if child.tag == 'check' and child.attrib['target'] in self.redefine_variables and child.attrib['target'] not in self.check_removed:
|
||||||
creoleobj.index = self.index
|
self.remove_check(child.attrib['target'])
|
||||||
if child.tag in ['auto', 'fill', 'condition', 'check', 'action']:
|
self.check_removed.append(child.attrib['target'])
|
||||||
creoleobj.namespace = namespace
|
if child.tag == 'condition' and child.attrib['source'] in self.redefine_variables and child.attrib['source'] not in self.check_removed:
|
||||||
|
self.remove_condition(child.attrib['source'])
|
||||||
|
self.condition_removed.append(child.attrib['source'])
|
||||||
|
variableobj.namespace = namespace
|
||||||
|
|
||||||
def xml_parse_document(self, document, space, namespace, is_in_family=False):
|
def fill_variableobj_path_attribute(self,
|
||||||
"""Parses a Creole XML file
|
space,
|
||||||
populates the CreoleObjSpace
|
child,
|
||||||
"""
|
namespace,
|
||||||
family_names = []
|
document,
|
||||||
for child in document:
|
variableobj,
|
||||||
# this index enables us to reorder the 'fill' and 'auto' objects
|
): # pylint: disable=R0913
|
||||||
self.index += 1
|
|
||||||
# doesn't proceed the XML commentaries
|
|
||||||
if not isinstance(child.tag, str):
|
|
||||||
continue
|
|
||||||
if child.tag == 'family':
|
|
||||||
is_in_family = True
|
|
||||||
if child.attrib['name'] in family_names:
|
|
||||||
raise CreoleDictConsistencyError(_('Family {} is set several times').format(child.attrib['name']))
|
|
||||||
family_names.append(child.attrib['name'])
|
|
||||||
if child.tag == 'variables':
|
|
||||||
child.attrib['name'] = namespace
|
|
||||||
if HIGH_COMPATIBILITY and child.tag == 'value' and child.text == None:
|
|
||||||
continue
|
|
||||||
# creole objects creation
|
|
||||||
try:
|
|
||||||
creoleobj = self.generate_creoleobj(child, space, namespace)
|
|
||||||
except SpaceObjShallNotBeUpdated:
|
|
||||||
continue
|
|
||||||
self._set_text_to_obj(child, creoleobj)
|
|
||||||
self._set_xml_attributes_to_obj(child, creoleobj)
|
|
||||||
self._creoleobj_tree_visitor(child, creoleobj, namespace)
|
|
||||||
self._fill_creoleobj_path_attribute(space, child, namespace, document, creoleobj)
|
|
||||||
self._add_to_tree_structure(creoleobj, space, child)
|
|
||||||
if list(child) != []:
|
|
||||||
self.xml_parse_document(child, creoleobj, namespace, is_in_family)
|
|
||||||
|
|
||||||
def _fill_creoleobj_path_attribute(self, space, child, namespace, document, creoleobj): # pylint: disable=R0913
|
|
||||||
"""Fill self.paths attributes
|
"""Fill self.paths attributes
|
||||||
"""
|
"""
|
||||||
if not isinstance(space, self.help): # pylint: disable=E1101
|
if isinstance(space, self.help): # pylint: disable=E1101
|
||||||
|
return
|
||||||
if child.tag == 'variable':
|
if child.tag == 'variable':
|
||||||
family_name = normalize_family(document.attrib['name'])
|
family_name = normalize_family(document.attrib['name'])
|
||||||
self.paths.append('variable', child.attrib['name'], namespace, family_name,
|
self.paths.add_variable(namespace,
|
||||||
creoleobj)
|
child.attrib['name'],
|
||||||
|
family_name,
|
||||||
|
document.attrib.get('dynamic') != None,
|
||||||
|
variableobj)
|
||||||
if child.attrib.get('redefine', 'False') == 'True':
|
if child.attrib.get('redefine', 'False') == 'True':
|
||||||
if namespace == 'creole':
|
if namespace == variable_namespace:
|
||||||
self.redefine_variables.append(child.attrib['name'])
|
self.redefine_variables.append(child.attrib['name'])
|
||||||
else:
|
else:
|
||||||
self.redefine_variables.append(namespace + '.' + family_name + '.' +
|
self.redefine_variables.append(namespace + '.' + family_name + '.' +
|
||||||
child.attrib['name'])
|
child.attrib['name'])
|
||||||
|
|
||||||
if child.tag == 'family':
|
elif child.tag == 'family':
|
||||||
family_name = normalize_family(child.attrib['name'])
|
family_name = normalize_family(child.attrib['name'])
|
||||||
if namespace != 'creole':
|
if namespace != variable_namespace:
|
||||||
family_name = namespace + '.' + family_name
|
family_name = namespace + '.' + family_name
|
||||||
self.paths.append('family', family_name, namespace, creoleobj=creoleobj)
|
self.paths.add_family(namespace,
|
||||||
creoleobj.path = self.paths.get_family_path(family_name, namespace)
|
family_name,
|
||||||
|
variableobj,
|
||||||
def create_or_populate_from_xml(self, namespace, xmlfolders, from_zephir=None):
|
)
|
||||||
"""Parses a bunch of XML files
|
variableobj.path = self.paths.get_family_path(family_name, namespace)
|
||||||
populates the CreoleObjSpace
|
|
||||||
"""
|
|
||||||
documents = self.xmlreflector.load_xml_from_folders(xmlfolders, from_zephir)
|
|
||||||
for xmlfile, document in documents:
|
|
||||||
try:
|
|
||||||
self.redefine_variables = []
|
|
||||||
self.xml_parse_document(document, self.space, namespace)
|
|
||||||
except Exception as err:
|
|
||||||
#print(_('error in XML file {}').format(xmlfile))
|
|
||||||
raise err
|
|
||||||
|
|
||||||
def populate_from_zephir(self, namespace, xmlfile):
|
|
||||||
self.redefine_variables = []
|
|
||||||
document = self.xmlreflector.parse_xmlfile(xmlfile, from_zephir=True, zephir2=True)
|
|
||||||
self.xml_parse_document(document, self.space, namespace)
|
|
||||||
|
|
||||||
def space_visitor(self, eosfunc_file): # pylint: disable=C0111
|
def space_visitor(self, eosfunc_file): # pylint: disable=C0111
|
||||||
ActionAnnotator(self)
|
self.funcs_path = eosfunc_file
|
||||||
ServiceAnnotator(self)
|
|
||||||
SpaceAnnotator(self, eosfunc_file)
|
SpaceAnnotator(self, eosfunc_file)
|
||||||
|
|
||||||
def save(self, filename, force_no_save=False):
|
def save(self,
|
||||||
"""Save an XML output on disk
|
):
|
||||||
|
tiramisu_objects = TiramisuReflector(self.space,
|
||||||
:param filename: the full XML filename
|
self.funcs_path,
|
||||||
"""
|
)
|
||||||
xml = Element('creole')
|
return tiramisu_objects.get_text() + '\n'
|
||||||
self._xml_export(xml, self.space)
|
|
||||||
if not force_no_save:
|
|
||||||
self.xmlreflector.save_xmlfile(filename, xml)
|
|
||||||
return xml
|
|
||||||
|
|
||||||
def save_probes(self, filename, force_no_save=False):
|
|
||||||
"""Save an XML output on disk
|
|
||||||
|
|
||||||
:param filename: the full XML filename
|
|
||||||
"""
|
|
||||||
ret = {}
|
|
||||||
for variable in self.probe_variables:
|
|
||||||
args = []
|
|
||||||
kwargs = {}
|
|
||||||
if hasattr(variable, 'param'):
|
|
||||||
for param in variable.param:
|
|
||||||
list_param = list(vars(param).keys())
|
|
||||||
if 'index' in list_param:
|
|
||||||
list_param.remove('index')
|
|
||||||
if list_param == ['text']:
|
|
||||||
args.append(param.text)
|
|
||||||
elif list_param == ['text', 'name']:
|
|
||||||
kwargs[param.name] = param.text
|
|
||||||
else:
|
|
||||||
print(vars(param))
|
|
||||||
raise Exception('hu?')
|
|
||||||
ret[variable.target] = {'function': variable.name,
|
|
||||||
'args': args,
|
|
||||||
'kwargs': kwargs}
|
|
||||||
if not force_no_save:
|
|
||||||
with open(filename, 'w') as fhj:
|
|
||||||
dump(ret, fhj)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def _get_attributes(self, space): # pylint: disable=R0201
|
|
||||||
for attr in dir(space):
|
|
||||||
if not attr.startswith('_'):
|
|
||||||
yield attr
|
|
||||||
|
|
||||||
def _sub_xml_export(self, name, node, node_name, space, current_space):
|
|
||||||
if isinstance(space, dict):
|
|
||||||
space = list(space.values())
|
|
||||||
if isinstance(space, list):
|
|
||||||
for subspace in space:
|
|
||||||
if isinstance(subspace, self.Leadership):
|
|
||||||
_name = 'leader'
|
|
||||||
else:
|
|
||||||
_name = name
|
|
||||||
if name in ['services', 'variables', 'actions']:
|
|
||||||
_name = 'family'
|
|
||||||
if HIGH_COMPATIBILITY and not hasattr(subspace, 'doc'):
|
|
||||||
subspace.doc = ''
|
|
||||||
if _name == 'value' and (not hasattr(subspace, 'name') or subspace.name is None):
|
|
||||||
continue
|
|
||||||
child_node = SubElement(node, _name)
|
|
||||||
self._xml_export(child_node, subspace, _name)
|
|
||||||
elif isinstance(space, self.Atom):
|
|
||||||
if name == 'services':
|
|
||||||
child_node = SubElement(node, 'family')
|
|
||||||
child_node.attrib['name'] = name
|
|
||||||
else:
|
|
||||||
child_node = SubElement(node, name)
|
|
||||||
for subname in self._get_attributes(space):
|
|
||||||
subspace = getattr(space, subname)
|
|
||||||
self._sub_xml_export(subname, child_node, name, subspace, space)
|
|
||||||
elif isinstance(space, self.Redefinable):
|
|
||||||
child_node = SubElement(node, 'family')
|
|
||||||
child_node.attrib['name'] = name
|
|
||||||
for subname in self._get_attributes(space):
|
|
||||||
subspace = getattr(space, subname)
|
|
||||||
self._sub_xml_export(subname, child_node, name, subspace, space)
|
|
||||||
else:
|
|
||||||
# FIXME plutot dans annotator ...
|
|
||||||
if name in PROPERTIES and node.tag in ['variable', 'family', 'leader']:
|
|
||||||
if space is True:
|
|
||||||
for prop in CONVERT_PROPERTIES.get(name, [name]):
|
|
||||||
SubElement(node, 'property').text = prop
|
|
||||||
|
|
||||||
elif name not in ERASED_ATTRIBUTES:
|
|
||||||
if name == 'name' and node_name in self.forced_text_elts_as_name and not hasattr(current_space, 'param'):
|
|
||||||
if isinstance(space, str):
|
|
||||||
node.text = space
|
|
||||||
else:
|
|
||||||
node.text = str(space)
|
|
||||||
elif name == 'text' and node_name in self.forced_text_elts:
|
|
||||||
node.text = space
|
|
||||||
elif node.tag == 'family' and name == 'name':
|
|
||||||
if 'doc' not in node.attrib.keys():
|
|
||||||
node.attrib['doc'] = space
|
|
||||||
node.attrib['name'] = normalize_family(space, check_name=False)
|
|
||||||
elif node.tag in ['variable', 'family', 'leader'] and name == 'mode':
|
|
||||||
if space is not None:
|
|
||||||
SubElement(node, 'property').text = space
|
|
||||||
else:
|
|
||||||
if name in RENAME_ATTIBUTES:
|
|
||||||
name = RENAME_ATTIBUTES[name]
|
|
||||||
if space is not None:
|
|
||||||
node.attrib[name] = str(space)
|
|
||||||
|
|
||||||
def _xml_export(self, node, space, node_name='creole'):
|
|
||||||
for name in self._get_attributes(space):
|
|
||||||
subspace = getattr(space, name)
|
|
||||||
self._sub_xml_export(name, node, node_name, subspace, space)
|
|
||||||
|
|
||||||
|
|
||||||
class Path(object):
|
|
||||||
"""Helper class to handle the `path` attribute of a CreoleObjSpace
|
|
||||||
instance.
|
|
||||||
|
|
||||||
sample: path="creole.general.condition"
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.variables = {}
|
|
||||||
self.families = {}
|
|
||||||
|
|
||||||
def append(self, pathtype, name, namespace, family=None, creoleobj=None): # pylint: disable=C0111
|
|
||||||
if pathtype == 'family':
|
|
||||||
self.families[name] = dict(name=name, namespace=namespace, creoleobj=creoleobj)
|
|
||||||
elif pathtype == 'variable':
|
|
||||||
if namespace == 'creole':
|
|
||||||
varname = name
|
|
||||||
else:
|
|
||||||
if '.' in name:
|
|
||||||
varname = name
|
|
||||||
else:
|
|
||||||
varname = '.'.join([namespace, family, name])
|
|
||||||
self.variables[varname] = dict(name=name, family=family, namespace=namespace,
|
|
||||||
leader=None, creoleobj=creoleobj)
|
|
||||||
else: # pragma: no cover
|
|
||||||
raise Exception('unknown pathtype {}'.format(pathtype))
|
|
||||||
|
|
||||||
def get_family_path(self, name, current_namespace): # pylint: disable=C0111
|
|
||||||
if current_namespace is None: # pragma: no cover
|
|
||||||
raise CreoleOperationError('current_namespace must not be None')
|
|
||||||
dico = self.families[normalize_family(name,
|
|
||||||
check_name=False,
|
|
||||||
allow_dot=True)]
|
|
||||||
if dico['namespace'] != 'creole' and current_namespace != dico['namespace']:
|
|
||||||
raise CreoleDictConsistencyError(_('A family located in the {} namespace '
|
|
||||||
'shall not be used in the {} namespace').format(
|
|
||||||
dico['namespace'], current_namespace))
|
|
||||||
path = dico['name']
|
|
||||||
if dico['namespace'] is not None and '.' not in dico['name']:
|
|
||||||
path = '.'.join([dico['namespace'], path])
|
|
||||||
return path
|
|
||||||
|
|
||||||
def get_family_namespace(self, name): # pylint: disable=C0111
|
|
||||||
dico = self.families[name]
|
|
||||||
if dico['namespace'] is None:
|
|
||||||
return dico['name']
|
|
||||||
return dico['namespace']
|
|
||||||
|
|
||||||
def get_family_obj(self, name): # pylint: disable=C0111
|
|
||||||
if name not in self.families:
|
|
||||||
raise CreoleDictConsistencyError(_('unknown family {}').format(name))
|
|
||||||
dico = self.families[name]
|
|
||||||
return dico['creoleobj']
|
|
||||||
|
|
||||||
def get_variable_name(self, name): # pylint: disable=C0111
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
return dico['name']
|
|
||||||
|
|
||||||
def get_variable_obj(self, name): # pylint: disable=C0111
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
return dico['creoleobj']
|
|
||||||
|
|
||||||
def get_variable_family_name(self, name): # pylint: disable=C0111
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
return dico['family']
|
|
||||||
|
|
||||||
def get_variable_family_path(self, name): # pylint: disable=C0111
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
list_path = [dico['namespace'], dico['family']]
|
|
||||||
if dico['leader'] is not None:
|
|
||||||
list_path.append(dico['leader'])
|
|
||||||
return '.'.join(list_path)
|
|
||||||
|
|
||||||
def get_variable_namespace(self, name): # pylint: disable=C0111
|
|
||||||
return self._get_variable(name)['namespace']
|
|
||||||
|
|
||||||
def get_variable_path(self, name, current_namespace, allow_source=False): # pylint: disable=C0111
|
|
||||||
if current_namespace is None: # pragma: no cover
|
|
||||||
raise CreoleOperationError('current_namespace must not be None')
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
if not allow_source:
|
|
||||||
if dico['namespace'] not in ['creole', 'services'] and current_namespace != dico['namespace']:
|
|
||||||
raise CreoleDictConsistencyError(_('A variable located in the {} namespace '
|
|
||||||
'shall not be used in the {} namespace').format(
|
|
||||||
dico['namespace'], current_namespace))
|
|
||||||
if '.' in dico['name']:
|
|
||||||
return dico['name']
|
|
||||||
list_path = [dico['namespace'], dico['family']]
|
|
||||||
if dico['leader'] is not None:
|
|
||||||
list_path.append(dico['leader'])
|
|
||||||
list_path.append(dico['name'])
|
|
||||||
return '.'.join(list_path)
|
|
||||||
|
|
||||||
def path_is_defined(self, name): # pylint: disable=C0111
|
|
||||||
return name in self.variables
|
|
||||||
|
|
||||||
def set_leader(self, name, leader): # pylint: disable=C0111
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
namespace = dico['namespace']
|
|
||||||
if dico['leader'] != None:
|
|
||||||
raise CreoleDictConsistencyError(_('Already defined leader {} for variable'
|
|
||||||
' {}'.format(dico['leader'], name)))
|
|
||||||
dico['leader'] = leader
|
|
||||||
if namespace != 'creole':
|
|
||||||
new_path = self.get_variable_path(name, namespace)
|
|
||||||
self.append('variable', new_path, namespace, family=dico['family'], creoleobj=dico['creoleobj'])
|
|
||||||
self.variables[new_path]['leader'] = leader
|
|
||||||
del self.variables[name]
|
|
||||||
|
|
||||||
def _get_variable(self, name):
|
|
||||||
if name not in self.variables:
|
|
||||||
if name.startswith('creole.'):
|
|
||||||
name = name.split('.')[-1]
|
|
||||||
if name not in self.variables:
|
|
||||||
raise CreoleDictConsistencyError(_('unknown option {}').format(name))
|
|
||||||
return self.variables[name]
|
|
||||||
|
|
||||||
def get_leader(self, name): # pylint: disable=C0111
|
|
||||||
dico = self._get_variable(name)
|
|
||||||
return dico['leader']
|
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
from .i18n import _
|
||||||
|
from .utils import normalize_family
|
||||||
|
from .error import OperationError, DictConsistencyError
|
||||||
|
from .config import variable_namespace
|
||||||
|
|
||||||
|
|
||||||
|
class Path:
|
||||||
|
"""Helper class to handle the `path` attribute of a CreoleObjSpace
|
||||||
|
instance.
|
||||||
|
|
||||||
|
sample: path="creole.general.condition"
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.variables = {}
|
||||||
|
self.families = {}
|
||||||
|
self.full_paths = {}
|
||||||
|
|
||||||
|
# Family
|
||||||
|
def add_family(self,
|
||||||
|
namespace: str,
|
||||||
|
name: str,
|
||||||
|
variableobj: str,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
if '.' not in name and namespace == variable_namespace:
|
||||||
|
full_name = '.'.join([namespace, name])
|
||||||
|
self.full_paths[name] = full_name
|
||||||
|
else:
|
||||||
|
full_name = name
|
||||||
|
if full_name in self.families and self.families[full_name]['variableobj'] != variableobj:
|
||||||
|
raise DictConsistencyError(_(f'Duplicate family name {name}'))
|
||||||
|
self.families[full_name] = dict(name=name,
|
||||||
|
namespace=namespace,
|
||||||
|
variableobj=variableobj,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_family_path(self,
|
||||||
|
name: str,
|
||||||
|
current_namespace: str,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
name = normalize_family(name,
|
||||||
|
check_name=False,
|
||||||
|
allow_dot=True,
|
||||||
|
)
|
||||||
|
if '.' not in name and current_namespace == variable_namespace and name in self.full_paths:
|
||||||
|
name = self.full_paths[name]
|
||||||
|
if current_namespace is None: # pragma: no cover
|
||||||
|
raise OperationError('current_namespace must not be None')
|
||||||
|
dico = self.families[name]
|
||||||
|
if dico['namespace'] != variable_namespace and current_namespace != dico['namespace']:
|
||||||
|
raise DictConsistencyError(_('A family located in the {} namespace '
|
||||||
|
'shall not be used in the {} namespace').format(
|
||||||
|
dico['namespace'], current_namespace))
|
||||||
|
return dico['name']
|
||||||
|
|
||||||
|
def get_family_obj(self,
|
||||||
|
name: str,
|
||||||
|
) -> 'Family': # pylint: disable=C0111
|
||||||
|
if '.' not in name and name in self.full_paths:
|
||||||
|
name = self.full_paths[name]
|
||||||
|
if name not in self.families:
|
||||||
|
raise DictConsistencyError(_('unknown family {}').format(name))
|
||||||
|
dico = self.families[name]
|
||||||
|
return dico['variableobj']
|
||||||
|
|
||||||
|
def family_is_defined(self,
|
||||||
|
name: str,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
if '.' not in name and name not in self.families and name in self.full_paths:
|
||||||
|
return True
|
||||||
|
return name in self.families
|
||||||
|
|
||||||
|
# Leadership
|
||||||
|
def set_leader(self,
|
||||||
|
namespace: str,
|
||||||
|
leader_family_name: str,
|
||||||
|
name: str,
|
||||||
|
leader_name: str,
|
||||||
|
) -> None: # pylint: disable=C0111
|
||||||
|
# need rebuild path and move object in new path
|
||||||
|
old_path = namespace + '.' + leader_family_name + '.' + name
|
||||||
|
dico = self._get_variable(old_path)
|
||||||
|
del self.variables[old_path]
|
||||||
|
new_path = namespace + '.' + leader_family_name + '.' + leader_name + '.' + name
|
||||||
|
self.add_variable(namespace,
|
||||||
|
new_path,
|
||||||
|
dico['family'],
|
||||||
|
False,
|
||||||
|
dico['variableobj'],
|
||||||
|
)
|
||||||
|
if namespace == variable_namespace:
|
||||||
|
self.full_paths[name] = new_path
|
||||||
|
else:
|
||||||
|
name = new_path
|
||||||
|
dico = self._get_variable(name)
|
||||||
|
if dico['leader'] != None:
|
||||||
|
raise DictConsistencyError(_('Already defined leader {} for variable'
|
||||||
|
' {}'.format(dico['leader'], name)))
|
||||||
|
dico['leader'] = leader_name
|
||||||
|
|
||||||
|
def get_leader(self, name): # pylint: disable=C0111
|
||||||
|
return self._get_variable(name)['leader']
|
||||||
|
|
||||||
|
# Variable
|
||||||
|
def add_variable(self,
|
||||||
|
namespace: str,
|
||||||
|
name: str,
|
||||||
|
family: str,
|
||||||
|
is_dynamic: bool,
|
||||||
|
variableobj,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
if '.' not in name:
|
||||||
|
full_name = '.'.join([namespace, family, name])
|
||||||
|
self.full_paths[name] = full_name
|
||||||
|
else:
|
||||||
|
full_name = name
|
||||||
|
if namespace == variable_namespace:
|
||||||
|
name = name.rsplit('.', 1)[1]
|
||||||
|
self.variables[full_name] = dict(name=name,
|
||||||
|
family=family,
|
||||||
|
namespace=namespace,
|
||||||
|
leader=None,
|
||||||
|
is_dynamic=is_dynamic,
|
||||||
|
variableobj=variableobj)
|
||||||
|
|
||||||
|
def get_variable_name(self,
|
||||||
|
name,
|
||||||
|
): # pylint: disable=C0111
|
||||||
|
return self._get_variable(name)['name']
|
||||||
|
|
||||||
|
def get_variable_obj(self,
|
||||||
|
name:str,
|
||||||
|
) -> 'Variable': # pylint: disable=C0111
|
||||||
|
return self._get_variable(name)['variableobj']
|
||||||
|
|
||||||
|
def get_variable_family_name(self,
|
||||||
|
name: str,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
return self._get_variable(name)['family']
|
||||||
|
|
||||||
|
def get_variable_namespace(self,
|
||||||
|
name: str,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
return self._get_variable(name)['namespace']
|
||||||
|
|
||||||
|
def get_variable_path(self,
|
||||||
|
name: str,
|
||||||
|
current_namespace: str,
|
||||||
|
allow_source: str=False,
|
||||||
|
with_suffix: bool=False,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
if current_namespace is None: # pragma: no cover
|
||||||
|
raise OperationError('current_namespace must not be None')
|
||||||
|
if with_suffix:
|
||||||
|
dico, suffix = self._get_variable(name,
|
||||||
|
with_suffix=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
dico = self._get_variable(name)
|
||||||
|
if not allow_source:
|
||||||
|
if dico['namespace'] not in [variable_namespace, 'services'] and current_namespace != dico['namespace']:
|
||||||
|
raise DictConsistencyError(_('A variable located in the {} namespace '
|
||||||
|
'shall not be used in the {} namespace').format(
|
||||||
|
dico['namespace'], current_namespace))
|
||||||
|
if '.' in dico['name']:
|
||||||
|
value = dico['name']
|
||||||
|
else:
|
||||||
|
list_path = [dico['namespace'], dico['family']]
|
||||||
|
if dico['leader'] is not None:
|
||||||
|
list_path.append(dico['leader'])
|
||||||
|
list_path.append(dico['name'])
|
||||||
|
value = '.'.join(list_path)
|
||||||
|
if with_suffix:
|
||||||
|
return value, suffix
|
||||||
|
return value
|
||||||
|
|
||||||
|
def path_is_defined(self,
|
||||||
|
name: str,
|
||||||
|
) -> str: # pylint: disable=C0111
|
||||||
|
if '.' not in name and name not in self.variables and name in self.full_paths:
|
||||||
|
return True
|
||||||
|
return name in self.variables
|
||||||
|
|
||||||
|
def _get_variable(self,
|
||||||
|
name: str,
|
||||||
|
with_suffix: bool=False,
|
||||||
|
) -> str:
|
||||||
|
if name not in self.variables:
|
||||||
|
if name not in self.variables:
|
||||||
|
if '.' not in name and name in self.full_paths:
|
||||||
|
name = self.full_paths[name]
|
||||||
|
if name not in self.variables:
|
||||||
|
for var_name, variable in self.variables.items():
|
||||||
|
if variable['is_dynamic'] and name.startswith(var_name):
|
||||||
|
return variable, name[len(var_name):]
|
||||||
|
if '.' not in name:
|
||||||
|
for var_name, path in self.full_paths.items():
|
||||||
|
if name.startswith(var_name):
|
||||||
|
variable = self.variables[self.full_paths[var_name]]
|
||||||
|
if variable['is_dynamic']:
|
||||||
|
return variable, name[len(var_name):]
|
||||||
|
raise DictConsistencyError(_('unknown option {}').format(name))
|
||||||
|
if with_suffix:
|
||||||
|
return self.variables[name], None
|
||||||
|
return self.variables[name]
|
|
@ -5,32 +5,12 @@ On travaille sur les fichiers cibles
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import imp
|
import imp
|
||||||
import sys
|
|
||||||
from shutil import copy
|
from shutil import copy
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
from os import listdir, unlink, makedirs
|
from os import listdir, makedirs
|
||||||
from os.path import dirname, basename, join, split, isfile, isdir
|
from os.path import dirname, join, isfile
|
||||||
|
|
||||||
from tempfile import mktemp
|
|
||||||
|
|
||||||
from Cheetah import Parser
|
|
||||||
|
|
||||||
|
|
||||||
# l'encoding du template est déterminé par une regexp (encodingDirectiveRE dans Parser.py)
|
|
||||||
# il cherche un ligne qui ressemble à '#encoding: utf-8
|
|
||||||
# cette classe simule le module 're' et retourne toujours l'encoding utf-8
|
|
||||||
# 6224
|
|
||||||
class FakeEncoding:
|
|
||||||
def groups(self):
|
|
||||||
return ('utf-8',)
|
|
||||||
|
|
||||||
def search(self, *args):
|
|
||||||
return self
|
|
||||||
Parser.encodingDirectiveRE = FakeEncoding()
|
|
||||||
|
|
||||||
|
|
||||||
from Cheetah.Template import Template as ChtTemplate
|
from Cheetah.Template import Template as ChtTemplate
|
||||||
from Cheetah.NameMapper import NotFound as CheetahNotFound
|
from Cheetah.NameMapper import NotFound as CheetahNotFound
|
||||||
|
@ -38,8 +18,8 @@ from Cheetah.NameMapper import NotFound as CheetahNotFound
|
||||||
from tiramisu import Config
|
from tiramisu import Config
|
||||||
from tiramisu.error import PropertiesOptionError
|
from tiramisu.error import PropertiesOptionError
|
||||||
|
|
||||||
from .config import patch_dir
|
from .config import patch_dir, variable_namespace
|
||||||
from .error import FileNotFound, TemplateError, TemplateDisabled
|
from .error import FileNotFound, TemplateError
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
|
|
||||||
|
@ -47,6 +27,7 @@ from .utils import normalize_family
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
log.addHandler(logging.NullHandler())
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class IsDefined:
|
class IsDefined:
|
||||||
"""
|
"""
|
||||||
filtre permettant de ne pas lever d'exception au cas où
|
filtre permettant de ne pas lever d'exception au cas où
|
||||||
|
@ -59,34 +40,16 @@ class IsDefined:
|
||||||
if '.' in varname:
|
if '.' in varname:
|
||||||
splitted_var = varname.split('.')
|
splitted_var = varname.split('.')
|
||||||
if len(splitted_var) != 2:
|
if len(splitted_var) != 2:
|
||||||
msg = _("Group variables must be of type master.slave")
|
msg = _("Group variables must be of type leader.follower")
|
||||||
raise KeyError(msg)
|
raise KeyError(msg)
|
||||||
master, slave = splitted_var
|
leader, follower = splitted_var
|
||||||
if master in self.context:
|
if leader in self.context:
|
||||||
return slave in self.context[master].slave.keys()
|
return follower in self.context[leader].follower.keys()
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return varname in self.context
|
return varname in self.context
|
||||||
|
|
||||||
|
|
||||||
class CreoleGet:
|
|
||||||
def __init__(self, context):
|
|
||||||
self.context = context
|
|
||||||
|
|
||||||
def __call__(self, varname):
|
|
||||||
return self.context[varname]
|
|
||||||
|
|
||||||
def __getitem__(self, varname):
|
|
||||||
"""For bracket and dotted notation
|
|
||||||
"""
|
|
||||||
return self.context[varname]
|
|
||||||
|
|
||||||
def __contains__(self, varname):
|
|
||||||
"""Check variable existence in context
|
|
||||||
"""
|
|
||||||
return varname in self.context
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def cl_compile(kls, *args, **kwargs):
|
def cl_compile(kls, *args, **kwargs):
|
||||||
kwargs['compilerSettings'] = {'directiveStartToken' : '%',
|
kwargs['compilerSettings'] = {'directiveStartToken' : '%',
|
||||||
|
@ -103,12 +66,6 @@ ChtTemplate.old_compile = ChtTemplate.compile
|
||||||
ChtTemplate.compile = cl_compile
|
ChtTemplate.compile = cl_compile
|
||||||
|
|
||||||
|
|
||||||
class CreoleClient:
|
|
||||||
def __init__(self,
|
|
||||||
config: Config):
|
|
||||||
self.config = config
|
|
||||||
|
|
||||||
|
|
||||||
class CheetahTemplate(ChtTemplate):
|
class CheetahTemplate(ChtTemplate):
|
||||||
"""classe pour personnaliser et faciliter la construction
|
"""classe pour personnaliser et faciliter la construction
|
||||||
du template Cheetah
|
du template Cheetah
|
||||||
|
@ -133,7 +90,7 @@ class CheetahTemplate(ChtTemplate):
|
||||||
|
|
||||||
|
|
||||||
class CreoleLeader:
|
class CreoleLeader:
|
||||||
def __init__(self, value, slave=None, index=None):
|
def __init__(self, value, follower=None, index=None):
|
||||||
"""
|
"""
|
||||||
On rend la variable itérable pour pouvoir faire:
|
On rend la variable itérable pour pouvoir faire:
|
||||||
for ip in iplist:
|
for ip in iplist:
|
||||||
|
@ -143,20 +100,20 @@ class CreoleLeader:
|
||||||
index is used for CreoleLint
|
index is used for CreoleLint
|
||||||
"""
|
"""
|
||||||
self._value = value
|
self._value = value
|
||||||
if slave is not None:
|
if follower is not None:
|
||||||
self.slave = slave
|
self.follower = follower
|
||||||
else:
|
else:
|
||||||
self.slave = {}
|
self.follower = {}
|
||||||
self._index = index
|
self._index = index
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
"""Get slave variable or attribute of master value.
|
"""Get follower variable or attribute of leader value.
|
||||||
|
|
||||||
If the attribute is a name of a slave variable, return its value.
|
If the attribute is a name of a follower variable, return its value.
|
||||||
Otherwise, returns the requested attribute of master value.
|
Otherwise, returns the requested attribute of leader value.
|
||||||
"""
|
"""
|
||||||
if name in self.slave:
|
if name in self.follower:
|
||||||
value = self.slave[name]
|
value = self.follower[name]
|
||||||
if isinstance(value, PropertiesOptionError):
|
if isinstance(value, PropertiesOptionError):
|
||||||
raise AttributeError()
|
raise AttributeError()
|
||||||
return value
|
return value
|
||||||
|
@ -164,36 +121,36 @@ class CreoleLeader:
|
||||||
return getattr(self._value, name)
|
return getattr(self._value, name)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"""Get a master.slave at requested index.
|
"""Get a leader.follower at requested index.
|
||||||
"""
|
"""
|
||||||
ret = {}
|
ret = {}
|
||||||
for key, values in self.slave.items():
|
for key, values in self.follower.items():
|
||||||
ret[key] = values[index]
|
ret[key] = values[index]
|
||||||
return CreoleLeader(self._value[index], ret, index)
|
return CreoleLeader(self._value[index], ret, index)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""Iterate over master.slave.
|
"""Iterate over leader.follower.
|
||||||
|
|
||||||
Return synchronised value of master.slave.
|
Return synchronised value of leader.follower.
|
||||||
"""
|
"""
|
||||||
for i in range(len(self._value)):
|
for i in range(len(self._value)):
|
||||||
ret = {}
|
ret = {}
|
||||||
for key, values in self.slave.items():
|
for key, values in self.follower.items():
|
||||||
ret[key] = values[i]
|
ret[key] = values[i]
|
||||||
yield CreoleLeader(self._value[i], ret, i)
|
yield CreoleLeader(self._value[i], ret, i)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""Delegate to master value
|
"""Delegate to leader value
|
||||||
"""
|
"""
|
||||||
return len(self._value)
|
return len(self._value)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Show CreoleLeader as dictionary.
|
"""Show CreoleLeader as dictionary.
|
||||||
|
|
||||||
The master value is stored under 'value' key.
|
The leader value is stored under 'value' key.
|
||||||
The slaves are stored under 'slave' key.
|
The followers are stored under 'follower' key.
|
||||||
"""
|
"""
|
||||||
return repr({'value': self._value, 'slave': self.slave})
|
return repr({'value': self._value, 'follower': self.follower})
|
||||||
|
|
||||||
def __eq__(self, value):
|
def __eq__(self, value):
|
||||||
return value == self._value
|
return value == self._value
|
||||||
|
@ -214,7 +171,7 @@ class CreoleLeader:
|
||||||
return self._value >= value
|
return self._value >= value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Delegate to master value
|
"""Delegate to leader value
|
||||||
"""
|
"""
|
||||||
return str(self._value)
|
return str(self._value)
|
||||||
|
|
||||||
|
@ -227,7 +184,7 @@ class CreoleLeader:
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
return item in self._value
|
return item in self._value
|
||||||
|
|
||||||
async def add_slave(self, config, name, path):
|
async def add_follower(self, config, name, path):
|
||||||
if isinstance(self._value, list):
|
if isinstance(self._value, list):
|
||||||
values = []
|
values = []
|
||||||
for idx in range(len(self._value)):
|
for idx in range(len(self._value)):
|
||||||
|
@ -237,7 +194,7 @@ class CreoleLeader:
|
||||||
values.append(err)
|
values.append(err)
|
||||||
else:
|
else:
|
||||||
raise Exception('hu?')
|
raise Exception('hu?')
|
||||||
self.slave[name] = values
|
self.follower[name] = values
|
||||||
|
|
||||||
|
|
||||||
class CreoleExtra:
|
class CreoleExtra:
|
||||||
|
@ -252,6 +209,9 @@ class CreoleExtra:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.suboption.__str__()
|
return self.suboption.__str__()
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.suboption.values())
|
||||||
|
|
||||||
|
|
||||||
class CreoleTemplateEngine:
|
class CreoleTemplateEngine:
|
||||||
"""Engine to process Creole cheetah template
|
"""Engine to process Creole cheetah template
|
||||||
|
@ -261,7 +221,8 @@ class CreoleTemplateEngine:
|
||||||
eosfunc_file: str,
|
eosfunc_file: str,
|
||||||
distrib_dir: str,
|
distrib_dir: str,
|
||||||
tmp_dir: str,
|
tmp_dir: str,
|
||||||
dest_dir:str) -> None:
|
dest_dir: str,
|
||||||
|
) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
self.dest_dir = dest_dir
|
self.dest_dir = dest_dir
|
||||||
self.tmp_dir = tmp_dir
|
self.tmp_dir = tmp_dir
|
||||||
|
@ -273,9 +234,9 @@ class CreoleTemplateEngine:
|
||||||
if not func.startswith('_'):
|
if not func.startswith('_'):
|
||||||
eos[func] = getattr(eosfunc, func)
|
eos[func] = getattr(eosfunc, func)
|
||||||
self.eosfunc = eos
|
self.eosfunc = eos
|
||||||
self.creole_variables_dict = {}
|
self.rougail_variables_dict = {}
|
||||||
|
|
||||||
async def load_eole_variables_creole(self,
|
async def load_eole_variables_rougail(self,
|
||||||
optiondescription):
|
optiondescription):
|
||||||
for option in await optiondescription.list('all'):
|
for option in await optiondescription.list('all'):
|
||||||
if await option.option.isoptiondescription():
|
if await option.option.isoptiondescription():
|
||||||
|
@ -283,15 +244,15 @@ class CreoleTemplateEngine:
|
||||||
for idx, suboption in enumerate(await option.list('all')):
|
for idx, suboption in enumerate(await option.list('all')):
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
leader = CreoleLeader(await suboption.value.get())
|
leader = CreoleLeader(await suboption.value.get())
|
||||||
self.creole_variables_dict[await suboption.option.name()] = leader
|
self.rougail_variables_dict[await suboption.option.name()] = leader
|
||||||
else:
|
else:
|
||||||
await leader.add_slave(self.config,
|
await leader.add_follower(self.config,
|
||||||
await suboption.option.name(),
|
await suboption.option.name(),
|
||||||
await suboption.option.path())
|
await suboption.option.path())
|
||||||
else:
|
else:
|
||||||
await self.load_eole_variables_creole(option)
|
await self.load_eole_variables_rougail(option)
|
||||||
else:
|
else:
|
||||||
self.creole_variables_dict[await option.option.name()] = await option.value.get()
|
self.rougail_variables_dict[await option.option.name()] = await option.value.get()
|
||||||
|
|
||||||
async def load_eole_variables(self,
|
async def load_eole_variables(self,
|
||||||
namespace,
|
namespace,
|
||||||
|
@ -300,20 +261,26 @@ class CreoleTemplateEngine:
|
||||||
for family in await optiondescription.list('all'):
|
for family in await optiondescription.list('all'):
|
||||||
variables = {}
|
variables = {}
|
||||||
for variable in await family.list('all'):
|
for variable in await family.list('all'):
|
||||||
if await variable.option.isoptiondescription() and await variable.option.isleadership():
|
if await variable.option.isoptiondescription():
|
||||||
|
if await variable.option.isleadership():
|
||||||
for idx, suboption in enumerate(await variable.list('all')):
|
for idx, suboption in enumerate(await variable.list('all')):
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
leader = CreoleLeader(await suboption.value.get())
|
leader = CreoleLeader(await suboption.value.get())
|
||||||
leader_name = await suboption.option.name()
|
leader_name = await suboption.option.name()
|
||||||
else:
|
else:
|
||||||
await leader.add_slave(self.config,
|
await leader.add_follower(self.config,
|
||||||
await suboption.option.name(),
|
await suboption.option.name(),
|
||||||
await suboption.option.path())
|
await suboption.option.path())
|
||||||
variables[leader_name] = leader
|
variables[leader_name] = leader
|
||||||
|
else:
|
||||||
|
subfamilies = await self.load_eole_variables(await variable.option.name(),
|
||||||
|
variable,
|
||||||
|
)
|
||||||
|
variables[await variable.option.name()] = subfamilies
|
||||||
else:
|
else:
|
||||||
variables[await variable.option.name()] = await variable.value.get()
|
variables[await variable.option.name()] = await variable.value.get()
|
||||||
families[await family.option.name()] = CreoleExtra(variables)
|
families[await family.option.name()] = CreoleExtra(variables)
|
||||||
self.creole_variables_dict[namespace] = CreoleExtra(families)
|
return CreoleExtra(families)
|
||||||
|
|
||||||
def patch_template(self,
|
def patch_template(self,
|
||||||
filename: str):
|
filename: str):
|
||||||
|
@ -342,6 +309,8 @@ class CreoleTemplateEngine:
|
||||||
self.patch_template(filename)
|
self.patch_template(filename)
|
||||||
|
|
||||||
def process(self,
|
def process(self,
|
||||||
|
source: str,
|
||||||
|
true_destfilename: str,
|
||||||
destfilename: str,
|
destfilename: str,
|
||||||
filevar: Dict,
|
filevar: Dict,
|
||||||
variable: Any):
|
variable: Any):
|
||||||
|
@ -350,12 +319,12 @@ class CreoleTemplateEngine:
|
||||||
# full path of the destination file
|
# full path of the destination file
|
||||||
log.info(_(f"Cheetah processing: '{destfilename}'"))
|
log.info(_(f"Cheetah processing: '{destfilename}'"))
|
||||||
try:
|
try:
|
||||||
cheetah_template = CheetahTemplate(join(self.tmp_dir,
|
cheetah_template = CheetahTemplate(source,
|
||||||
filevar['source']),
|
self.rougail_variables_dict,
|
||||||
self.creole_variables_dict,
|
|
||||||
self.eosfunc,
|
self.eosfunc,
|
||||||
destfilename,
|
true_destfilename,
|
||||||
variable)
|
variable,
|
||||||
|
)
|
||||||
data = str(cheetah_template)
|
data = str(cheetah_template)
|
||||||
except CheetahNotFound as err:
|
except CheetahNotFound as err:
|
||||||
varname = err.args[0][13:-1]
|
varname = err.args[0][13:-1]
|
||||||
|
@ -368,51 +337,53 @@ class CreoleTemplateEngine:
|
||||||
|
|
||||||
def instance_file(self,
|
def instance_file(self,
|
||||||
filevar: Dict,
|
filevar: Dict,
|
||||||
systemd_rights: list) -> None:
|
service_name: str) -> None:
|
||||||
"""Run templatisation on one file
|
"""Run templatisation on one file
|
||||||
"""
|
"""
|
||||||
log.info(_("Instantiating file '{filename}'"))
|
log.info(_("Instantiating file '{filename}'"))
|
||||||
filenames = filevar['name']
|
|
||||||
if 'variable' in filevar:
|
if 'variable' in filevar:
|
||||||
variable = filevar['variable']
|
variable = filevar['variable']
|
||||||
else:
|
else:
|
||||||
variable = None
|
variable = None
|
||||||
|
filenames = filevar['name']
|
||||||
if not isinstance(filenames, list):
|
if not isinstance(filenames, list):
|
||||||
filenames = [filenames]
|
filenames = [filenames]
|
||||||
if variable:
|
if variable:
|
||||||
variable = [variable]
|
variable = [variable]
|
||||||
for idx, filename in enumerate(filenames):
|
for idx, filename in enumerate(filenames):
|
||||||
destfilename = join(self.dest_dir,
|
destfilename = join(self.dest_dir, filename[1:])
|
||||||
filename[1:])
|
|
||||||
makedirs(dirname(destfilename), exist_ok=True)
|
makedirs(dirname(destfilename), exist_ok=True)
|
||||||
if variable:
|
if variable:
|
||||||
var = variable[idx]
|
var = variable[idx]
|
||||||
else:
|
else:
|
||||||
var = None
|
var = None
|
||||||
self.process(destfilename,
|
source = join(self.tmp_dir, filevar['source'])
|
||||||
|
if filevar['templating']:
|
||||||
|
self.process(source,
|
||||||
|
filename,
|
||||||
|
destfilename,
|
||||||
filevar,
|
filevar,
|
||||||
var)
|
var)
|
||||||
systemd_rights.append(f'C {filename} {filevar["mode"]} {filevar["owner"]} {filevar["group"]} - -')
|
else:
|
||||||
systemd_rights.append(f'z {filename} - - - - -')
|
copy(source, destfilename)
|
||||||
|
|
||||||
async def instance_files(self) -> None:
|
async def instance_files(self) -> None:
|
||||||
"""Run templatisation on all files
|
"""Run templatisation on all files
|
||||||
"""
|
"""
|
||||||
for option in await self.config.option.list(type='all'):
|
for option in await self.config.option.list(type='all'):
|
||||||
namespace = await option.option.name()
|
namespace = await option.option.name()
|
||||||
if namespace in ['services', 'actions']:
|
if namespace == variable_namespace:
|
||||||
continue
|
await self.load_eole_variables_rougail(option)
|
||||||
elif namespace == 'creole':
|
|
||||||
await self.load_eole_variables_creole(option)
|
|
||||||
else:
|
else:
|
||||||
await self.load_eole_variables(namespace,
|
families = await self.load_eole_variables(namespace,
|
||||||
option)
|
option)
|
||||||
|
self.rougail_variables_dict[namespace] = families
|
||||||
for template in listdir(self.distrib_dir):
|
for template in listdir(self.distrib_dir):
|
||||||
self.prepare_template(join(self.distrib_dir, template))
|
self.prepare_template(join(self.distrib_dir, template))
|
||||||
systemd_rights = []
|
|
||||||
for service_obj in await self.config.option('services').list('all'):
|
for service_obj in await self.config.option('services').list('all'):
|
||||||
|
service_name = await service_obj.option.doc()
|
||||||
for fills in await service_obj.list('all'):
|
for fills in await service_obj.list('all'):
|
||||||
if await fills.option.name() == 'files':
|
if await fills.option.name() in ['files', 'overrides']:
|
||||||
for fill_obj in await fills.list('all'):
|
for fill_obj in await fills.list('all'):
|
||||||
fill = await fill_obj.value.dict()
|
fill = await fill_obj.value.dict()
|
||||||
filename = fill['source']
|
filename = fill['source']
|
||||||
|
@ -421,23 +392,22 @@ class CreoleTemplateEngine:
|
||||||
raise FileNotFound(_(f"File {distib_file} does not exist."))
|
raise FileNotFound(_(f"File {distib_file} does not exist."))
|
||||||
if fill.get('activate', False):
|
if fill.get('activate', False):
|
||||||
self.instance_file(fill,
|
self.instance_file(fill,
|
||||||
systemd_rights)
|
service_name,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
log.debug(_("Instantiation of file '{filename}' disabled"))
|
log.debug(_("Instantiation of file '{filename}' disabled"))
|
||||||
|
|
||||||
with open(join(self.dest_dir, 'rougail.conf'), 'w') as fh:
|
|
||||||
fh.write('\n'.join(systemd_rights))
|
|
||||||
fh.write('\n')
|
|
||||||
|
|
||||||
|
|
||||||
async def generate(config: Config,
|
async def generate(config: Config,
|
||||||
eosfunc_file: str,
|
eosfunc_file: str,
|
||||||
distrib_dir: str,
|
distrib_dir: str,
|
||||||
tmp_dir: str,
|
tmp_dir: str,
|
||||||
dest_dir: str) -> None:
|
dest_dir: str,
|
||||||
|
) -> None:
|
||||||
engine = CreoleTemplateEngine(config,
|
engine = CreoleTemplateEngine(config,
|
||||||
eosfunc_file,
|
eosfunc_file,
|
||||||
distrib_dir,
|
distrib_dir,
|
||||||
tmp_dir,
|
tmp_dir,
|
||||||
dest_dir)
|
dest_dir,
|
||||||
|
)
|
||||||
await engine.instance_files()
|
await engine.instance_files()
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
from tiramisu import DynOptionDescription
|
||||||
|
from .utils import normalize_family
|
||||||
|
|
||||||
|
|
||||||
|
class ConvertDynOptionDescription(DynOptionDescription):
|
||||||
|
def convert_suffix_to_path(self, suffix):
|
||||||
|
if not isinstance(suffix, str):
|
||||||
|
suffix = str(suffix)
|
||||||
|
return normalize_family(suffix,
|
||||||
|
check_name=False)
|
|
@ -0,0 +1,503 @@
|
||||||
|
"""loader
|
||||||
|
flattened XML specific
|
||||||
|
"""
|
||||||
|
from os.path import isfile
|
||||||
|
from lxml.etree import DTD
|
||||||
|
|
||||||
|
from .config import dtdfilename, variable_namespace
|
||||||
|
from .i18n import _
|
||||||
|
from .error import LoaderError
|
||||||
|
from .annotator import ERASED_ATTRIBUTES
|
||||||
|
|
||||||
|
|
||||||
|
FUNC_TO_DICT = ['valid_not_equal']
|
||||||
|
FORCE_INFORMATIONS = ['help', 'test', 'separator', 'manage']
|
||||||
|
ATTRIBUTES_ORDER = ('name', 'doc', 'default', 'multi')
|
||||||
|
|
||||||
|
|
||||||
|
CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
|
||||||
|
'choice': dict(opttype="ChoiceOption"),
|
||||||
|
'string': dict(opttype="StrOption"),
|
||||||
|
'password': dict(opttype="PasswordOption"),
|
||||||
|
'mail': dict(opttype="EmailOption"),
|
||||||
|
'boolean': dict(opttype="BoolOption"),
|
||||||
|
'symlink': dict(opttype="SymLinkOption"),
|
||||||
|
'filename': dict(opttype="FilenameOption"),
|
||||||
|
'date': dict(opttype="DateOption"),
|
||||||
|
'unix_user': dict(opttype="UsernameOption"),
|
||||||
|
'ip': dict(opttype="IPOption", initkwargs={'allow_reserved': True}),
|
||||||
|
'local_ip': dict(opttype="IPOption", initkwargs={'private_only': True, 'warnings_only': True}),
|
||||||
|
'netmask': dict(opttype="NetmaskOption"),
|
||||||
|
'network': dict(opttype="NetworkOption"),
|
||||||
|
'broadcast': dict(opttype="BroadcastOption"),
|
||||||
|
'netbios': dict(opttype="DomainnameOption", initkwargs={'type': 'netbios', 'warnings_only': True}),
|
||||||
|
'domain': dict(opttype="DomainnameOption", initkwargs={'type': 'domainname', 'allow_ip': False}),
|
||||||
|
'hostname': dict(opttype="DomainnameOption", initkwargs={'type': 'hostname', 'allow_ip': False}),
|
||||||
|
'web_address': dict(opttype="URLOption", initkwargs={'allow_ip': True, 'allow_without_dot': True}),
|
||||||
|
'port': dict(opttype="PortOption", initkwargs={'allow_private': True}),
|
||||||
|
'mac': dict(opttype="MACOption"),
|
||||||
|
'cidr': dict(opttype="IPOption", initkwargs={'cidr': True}),
|
||||||
|
'network_cidr': dict(opttype="NetworkOption", initkwargs={'cidr': True}),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TiramisuReflector:
|
||||||
|
def __init__(self,
|
||||||
|
xmlroot,
|
||||||
|
funcs_path,
|
||||||
|
):
|
||||||
|
self.storage = ElementStorage()
|
||||||
|
self.storage.text = ["from tiramisu import *",
|
||||||
|
"from rougail.tiramisu import ConvertDynOptionDescription",
|
||||||
|
"import imp",
|
||||||
|
f"func = imp.load_source('func', '{funcs_path}')",
|
||||||
|
]
|
||||||
|
self.make_tiramisu_objects(xmlroot)
|
||||||
|
# parse object
|
||||||
|
self.storage.get('.').get()
|
||||||
|
|
||||||
|
def make_tiramisu_objects(self,
|
||||||
|
xmlroot,
|
||||||
|
):
|
||||||
|
family = self.get_root_family()
|
||||||
|
for xmlelt in self.reorder_family(xmlroot):
|
||||||
|
self.iter_family(xmlelt,
|
||||||
|
family,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_root_family(self):
|
||||||
|
family = Family(BaseElt('baseoption',
|
||||||
|
'baseoption',
|
||||||
|
),
|
||||||
|
self.storage,
|
||||||
|
False,
|
||||||
|
'.',
|
||||||
|
)
|
||||||
|
return family
|
||||||
|
|
||||||
|
def reorder_family(self, xmlroot):
|
||||||
|
# variable_namespace family has to be loaded before any other family
|
||||||
|
# because `extra` family could use `variable_namespace` variables.
|
||||||
|
if hasattr(xmlroot, 'variables'):
|
||||||
|
if variable_namespace in xmlroot.variables:
|
||||||
|
yield xmlroot.variables[variable_namespace]
|
||||||
|
for xmlelt, value in xmlroot.variables.items():
|
||||||
|
if xmlelt != variable_namespace:
|
||||||
|
yield value
|
||||||
|
if hasattr(xmlroot, 'services'):
|
||||||
|
yield xmlroot.services
|
||||||
|
|
||||||
|
def get_attributes(self, space): # pylint: disable=R0201
|
||||||
|
for attr in dir(space):
|
||||||
|
if not attr.startswith('_') and attr not in ERASED_ATTRIBUTES:
|
||||||
|
yield attr
|
||||||
|
|
||||||
|
def get_children(self,
|
||||||
|
space,
|
||||||
|
):
|
||||||
|
for tag in self.get_attributes(space):
|
||||||
|
children = getattr(space, tag)
|
||||||
|
if children.__class__.__name__ == 'Family':
|
||||||
|
children = [children]
|
||||||
|
if isinstance(children, dict):
|
||||||
|
children = list(children.values())
|
||||||
|
if isinstance(children, list):
|
||||||
|
yield tag, children
|
||||||
|
|
||||||
|
def iter_family(self,
|
||||||
|
child,
|
||||||
|
family,
|
||||||
|
subpath,
|
||||||
|
):
|
||||||
|
tag = child.__class__.__name__
|
||||||
|
if tag == 'Variable':
|
||||||
|
function = self.populate_variable
|
||||||
|
elif tag == 'Property':
|
||||||
|
# property already imported with family
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
function = self.populate_family
|
||||||
|
#else:
|
||||||
|
# raise Exception('unknown tag {}'.format(child.tag))
|
||||||
|
function(family,
|
||||||
|
child,
|
||||||
|
subpath,
|
||||||
|
)
|
||||||
|
|
||||||
|
def populate_family(self,
|
||||||
|
parent_family,
|
||||||
|
elt,
|
||||||
|
subpath,
|
||||||
|
):
|
||||||
|
path = self.build_path(subpath,
|
||||||
|
elt,
|
||||||
|
)
|
||||||
|
tag = elt.__class__.__name__
|
||||||
|
family = Family(elt,
|
||||||
|
self.storage,
|
||||||
|
tag == 'Leadership',
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
parent_family.add(family)
|
||||||
|
for tag, children in self.get_children(elt):
|
||||||
|
for child in children:
|
||||||
|
self.iter_family(child,
|
||||||
|
family,
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
|
||||||
|
def populate_variable(self,
|
||||||
|
family,
|
||||||
|
elt,
|
||||||
|
subpath,
|
||||||
|
):
|
||||||
|
is_follower = False
|
||||||
|
is_leader = False
|
||||||
|
if family.is_leader:
|
||||||
|
if elt.name != family.elt.name:
|
||||||
|
is_follower = True
|
||||||
|
else:
|
||||||
|
is_leader = True
|
||||||
|
family.add(Variable(elt,
|
||||||
|
self.storage,
|
||||||
|
is_follower,
|
||||||
|
is_leader,
|
||||||
|
self.build_path(subpath,
|
||||||
|
elt,
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
def build_path(self,
|
||||||
|
subpath,
|
||||||
|
elt,
|
||||||
|
):
|
||||||
|
if subpath is None:
|
||||||
|
return elt.name
|
||||||
|
return subpath + '.' + elt.name
|
||||||
|
|
||||||
|
def get_text(self):
|
||||||
|
return '\n'.join(self.storage.get('.').get_text())
|
||||||
|
|
||||||
|
|
||||||
|
class BaseElt:
|
||||||
|
def __init__(self,
|
||||||
|
name,
|
||||||
|
doc,
|
||||||
|
):
|
||||||
|
self.name = name
|
||||||
|
self.doc = doc
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter([])
|
||||||
|
|
||||||
|
|
||||||
|
class ElementStorage:
|
||||||
|
def __init__(self,
|
||||||
|
):
|
||||||
|
self.paths = {}
|
||||||
|
self.text = []
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def add(self, path, elt):
|
||||||
|
self.paths[path] = (elt, self.index)
|
||||||
|
self.index += 1
|
||||||
|
|
||||||
|
def get(self, path):
|
||||||
|
if path not in self.paths or self.paths[path][0] is None:
|
||||||
|
raise LoaderError(_('there is no element for path {}').format(path))
|
||||||
|
return self.paths[path][0]
|
||||||
|
|
||||||
|
def get_name(self, path):
|
||||||
|
if path not in self.paths:
|
||||||
|
raise LoaderError(_('there is no element for index {}').format(path))
|
||||||
|
return f'option_{self.paths[path][1]}'
|
||||||
|
|
||||||
|
|
||||||
|
class Common:
|
||||||
|
def __init__(self,
|
||||||
|
elt,
|
||||||
|
storage,
|
||||||
|
is_leader,
|
||||||
|
path,
|
||||||
|
):
|
||||||
|
self.option_name = None
|
||||||
|
self.path = path
|
||||||
|
self.attrib = {}
|
||||||
|
self.informations = {}
|
||||||
|
self.storage = storage
|
||||||
|
self.is_leader = is_leader
|
||||||
|
self.storage.add(self.path, self)
|
||||||
|
|
||||||
|
def populate_properties(self, child):
|
||||||
|
if child.type == 'calculation':
|
||||||
|
action = f"ParamValue('{child.name}')"
|
||||||
|
option_name = self.storage.get(child.source).get()
|
||||||
|
kwargs = f"'condition': ParamOption({option_name}, todict=True), 'expected': ParamValue('{child.expected}')"
|
||||||
|
if child.inverse:
|
||||||
|
kwargs += ", 'reverse_condition': ParamValue(True)"
|
||||||
|
prop = 'Calculation(calc_value, Params(' + action + ', kwargs={' + kwargs + '}))'
|
||||||
|
else:
|
||||||
|
prop = "'" + child.text + "'"
|
||||||
|
if self.attrib['properties']:
|
||||||
|
self.attrib['properties'] += ', '
|
||||||
|
self.attrib['properties'] += prop
|
||||||
|
|
||||||
|
def get_attrib(self, attrib):
|
||||||
|
ret_list = []
|
||||||
|
for key, value in self.attrib.items():
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
if key == 'properties':
|
||||||
|
if not self.attrib[key]:
|
||||||
|
continue
|
||||||
|
value = "frozenset({" + self.attrib[key] + "})"
|
||||||
|
elif key in ['default', 'multi', 'suffixes', 'validators']:
|
||||||
|
value = self.attrib[key]
|
||||||
|
elif isinstance(value, str) and key != 'opt' and not value.startswith('['):
|
||||||
|
value = "'" + value.replace("'", "\\\'") + "'"
|
||||||
|
ret_list.append(f'{key}={value}')
|
||||||
|
return ', '.join(ret_list)
|
||||||
|
|
||||||
|
def populate_informations(self):
|
||||||
|
for key, value in self.informations.items():
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = '"' + value.replace('"', '\"') + '"'
|
||||||
|
self.storage.text.append(f'{self.option_name}.impl_set_information("{key}", {value})')
|
||||||
|
|
||||||
|
def get_text(self,
|
||||||
|
):
|
||||||
|
return self.storage.text
|
||||||
|
|
||||||
|
def get_attributes(self, space): # pylint: disable=R0201
|
||||||
|
attributes = dir(space)
|
||||||
|
for attr in ATTRIBUTES_ORDER:
|
||||||
|
if attr in attributes:
|
||||||
|
yield attr
|
||||||
|
for attr in dir(space):
|
||||||
|
if attr not in ATTRIBUTES_ORDER:
|
||||||
|
if not attr.startswith('_') and attr not in ERASED_ATTRIBUTES:
|
||||||
|
value = getattr(space, attr)
|
||||||
|
if not isinstance(value, (list, dict)) and not value.__class__.__name__ == 'Family':
|
||||||
|
yield attr
|
||||||
|
|
||||||
|
def get_children(self,
|
||||||
|
space,
|
||||||
|
):
|
||||||
|
for attr in dir(space):
|
||||||
|
if not attr.startswith('_') and attr not in ERASED_ATTRIBUTES:
|
||||||
|
value = getattr(space, attr)
|
||||||
|
if isinstance(value, (list, dict)):
|
||||||
|
children = getattr(space, attr)
|
||||||
|
if children.__class__.__name__ == 'Family':
|
||||||
|
children = [children]
|
||||||
|
if isinstance(children, dict):
|
||||||
|
children = list(children.values())
|
||||||
|
if children and isinstance(children, list):
|
||||||
|
yield attr, children
|
||||||
|
|
||||||
|
|
||||||
|
class Variable(Common):
|
||||||
|
def __init__(self,
|
||||||
|
elt,
|
||||||
|
storage,
|
||||||
|
is_follower,
|
||||||
|
is_leader,
|
||||||
|
path,
|
||||||
|
):
|
||||||
|
super().__init__(elt,
|
||||||
|
storage,
|
||||||
|
is_leader,
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
self.is_follower = is_follower
|
||||||
|
convert_option = CONVERT_OPTION[elt.type]
|
||||||
|
del elt.type
|
||||||
|
self.object_type = convert_option['opttype']
|
||||||
|
self.attrib.update(convert_option.get('initkwargs', {}))
|
||||||
|
if self.object_type != 'SymLinkOption':
|
||||||
|
self.attrib['properties'] = []
|
||||||
|
self.attrib['validators'] = []
|
||||||
|
self.elt = elt
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
if self.option_name is None:
|
||||||
|
self.populate_attrib()
|
||||||
|
if self.object_type == 'SymLinkOption':
|
||||||
|
self.attrib['opt'] = self.storage.get(self.attrib['opt']).get()
|
||||||
|
else:
|
||||||
|
self.parse_children()
|
||||||
|
attrib = self.get_attrib(self.attrib)
|
||||||
|
self.option_name = self.storage.get_name(self.path)
|
||||||
|
self.storage.text.append(f'{self.option_name} = {self.object_type}({attrib})')
|
||||||
|
self.populate_informations()
|
||||||
|
return self.option_name
|
||||||
|
|
||||||
|
def populate_attrib(self):
|
||||||
|
for key in self.get_attributes(self.elt):
|
||||||
|
value = getattr(self.elt, key)
|
||||||
|
if key in FORCE_INFORMATIONS:
|
||||||
|
if key == 'test':
|
||||||
|
value = value.split(',')
|
||||||
|
if self.object_type == 'IntOption':
|
||||||
|
value = [int(v) for v in value]
|
||||||
|
self.informations[key] = value
|
||||||
|
else:
|
||||||
|
self.attrib[key] = value
|
||||||
|
|
||||||
|
def parse_children(self):
|
||||||
|
if not 'default' in self.attrib or self.attrib['multi']:
|
||||||
|
self.attrib['default'] = []
|
||||||
|
if self.attrib['multi'] == 'submulti' and self.is_follower:
|
||||||
|
self.attrib['default_multi'] = []
|
||||||
|
choices = []
|
||||||
|
if 'properties' in self.attrib:
|
||||||
|
if self.attrib['properties']:
|
||||||
|
self.attrib['properties'] = "'" + "', '".join(sorted(list(self.attrib['properties']))) + "'"
|
||||||
|
else:
|
||||||
|
self.attrib['properties'] = ''
|
||||||
|
for tag, children in self.get_children(self.elt):
|
||||||
|
for child in children:
|
||||||
|
if tag == 'property':
|
||||||
|
self.populate_properties(child)
|
||||||
|
elif tag == 'value':
|
||||||
|
if child.type == 'calculation':
|
||||||
|
self.attrib['default'] = self.calculation_value(child, [])
|
||||||
|
else:
|
||||||
|
self.populate_value(child)
|
||||||
|
elif tag == 'check':
|
||||||
|
self.attrib['validators'].append(self.calculation_value(child, ['ParamSelfOption()']))
|
||||||
|
elif tag == 'choice':
|
||||||
|
choices.append(child.name)
|
||||||
|
if choices:
|
||||||
|
self.attrib['values'] = tuple(choices)
|
||||||
|
if self.attrib['default'] == []:
|
||||||
|
del self.attrib['default']
|
||||||
|
elif not self.attrib['multi'] and isinstance(self.attrib['default'], list):
|
||||||
|
self.attrib['default'] = self.attrib['default'][-1]
|
||||||
|
if self.attrib['validators'] == []:
|
||||||
|
del self.attrib['validators']
|
||||||
|
else:
|
||||||
|
self.attrib['validators'] = '[' + ', '.join(self.attrib['validators']) + ']'
|
||||||
|
|
||||||
|
def calculation_value(self, child, args):
|
||||||
|
kwargs = []
|
||||||
|
if hasattr(child, 'name'):
|
||||||
|
# has parameters
|
||||||
|
function = child.name
|
||||||
|
if hasattr(child, 'param'):
|
||||||
|
for param in child.param:
|
||||||
|
value = self.populate_param(param)
|
||||||
|
if not hasattr(param, 'name'):
|
||||||
|
args.append(str(value))
|
||||||
|
else:
|
||||||
|
kwargs.append(f"'{param.name}': " + value)
|
||||||
|
else:
|
||||||
|
# function without any parameter
|
||||||
|
function = child.text.strip()
|
||||||
|
ret = f"Calculation(func.{function}, Params((" + ', '.join(args) + "), kwargs=" + "{" + ', '.join(kwargs) + "})"
|
||||||
|
if hasattr(child, 'warnings_only'):
|
||||||
|
ret += f', warnings_only={child.warnings_only}'
|
||||||
|
return ret + ')'
|
||||||
|
|
||||||
|
def populate_param(self,
|
||||||
|
param,
|
||||||
|
):
|
||||||
|
if param.type == 'string':
|
||||||
|
return f'ParamValue("{param.text}")'
|
||||||
|
elif param.type == 'number':
|
||||||
|
return f'ParamValue({param.text})'
|
||||||
|
elif param.type == 'variable':
|
||||||
|
value = {'option': param.text,
|
||||||
|
'notraisepropertyerror': param.notraisepropertyerror,
|
||||||
|
'todict': param.text in FUNC_TO_DICT,
|
||||||
|
}
|
||||||
|
if hasattr(param, 'suffix'):
|
||||||
|
value['suffix'] = param.suffix
|
||||||
|
return self.build_param(value)
|
||||||
|
raise LoaderError(_('unknown param type {}').format(param.type))
|
||||||
|
|
||||||
|
def populate_value(self,
|
||||||
|
child,
|
||||||
|
):
|
||||||
|
value = child.name
|
||||||
|
if self.attrib['multi'] == 'submulti':
|
||||||
|
self.attrib['default_multi'].append(value)
|
||||||
|
elif self.is_follower:
|
||||||
|
self.attrib['default_multi'] = value
|
||||||
|
elif self.attrib['multi']:
|
||||||
|
self.attrib['default'].append(value)
|
||||||
|
if not self.is_leader:
|
||||||
|
self.attrib['default_multi'] = value
|
||||||
|
elif isinstance(value, int):
|
||||||
|
self.attrib['default'].append(value)
|
||||||
|
else:
|
||||||
|
self.attrib['default'].append("'" + value + "'")
|
||||||
|
|
||||||
|
def build_param(self,
|
||||||
|
param,
|
||||||
|
):
|
||||||
|
option_name = self.storage.get(param['option']).get()
|
||||||
|
if 'suffix' in param:
|
||||||
|
family = '.'.join(param['option'].split('.')[:-1])
|
||||||
|
family_option = self.storage.get_name(family)
|
||||||
|
return f"ParamDynOption({option_name}, '{param['suffix']}', {family_option}, notraisepropertyerror={param['notraisepropertyerror']}, todict={param['todict']})"
|
||||||
|
return f"ParamOption({option_name}, notraisepropertyerror={param['notraisepropertyerror']}, todict={param['todict']})"
|
||||||
|
|
||||||
|
|
||||||
|
class Family(Common):
|
||||||
|
def __init__(self,
|
||||||
|
elt,
|
||||||
|
storage,
|
||||||
|
is_leader,
|
||||||
|
path,
|
||||||
|
):
|
||||||
|
super().__init__(elt,
|
||||||
|
storage,
|
||||||
|
is_leader,
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
self.children = []
|
||||||
|
self.elt = elt
|
||||||
|
|
||||||
|
def add(self, child):
|
||||||
|
self.children.append(child)
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
if not self.option_name:
|
||||||
|
self.populate_attrib()
|
||||||
|
self.parse_children()
|
||||||
|
self.option_name = self.storage.get_name(self.path)
|
||||||
|
object_name = self.get_object_name()
|
||||||
|
attrib = self.get_attrib(self.attrib) + ', children=[' + ', '.join([child.get() for child in self.children]) + ']'
|
||||||
|
self.storage.text.append(f'{self.option_name} = {object_name}({attrib})')
|
||||||
|
self.populate_informations()
|
||||||
|
return self.option_name
|
||||||
|
|
||||||
|
def populate_attrib(self):
|
||||||
|
for key in self.get_attributes(self.elt):
|
||||||
|
value = getattr(self.elt, key)
|
||||||
|
if key in FORCE_INFORMATIONS:
|
||||||
|
self.informations[key] = value
|
||||||
|
elif key == 'dynamic':
|
||||||
|
dynamic = self.storage.get(value).get()
|
||||||
|
self.attrib['suffixes'] = f"Calculation(func.calc_value, Params((ParamOption({dynamic}))))"
|
||||||
|
else:
|
||||||
|
self.attrib[key] = value
|
||||||
|
|
||||||
|
def parse_children(self):
|
||||||
|
if 'properties' in self.attrib:
|
||||||
|
self.attrib['properties'] = "'" + "', '".join(sorted(list(self.attrib['properties']))) + "'"
|
||||||
|
if hasattr(self.elt, 'property'):
|
||||||
|
#self.attrib['properties'] = ''
|
||||||
|
for child in self.elt.property:
|
||||||
|
self.populate_properties(child)
|
||||||
|
if not self.attrib['properties']:
|
||||||
|
del self.attrib['properties']
|
||||||
|
|
||||||
|
def get_object_name(self):
|
||||||
|
if 'suffixes' in self.attrib:
|
||||||
|
return 'ConvertDynOptionDescription'
|
||||||
|
elif not self.is_leader:
|
||||||
|
return 'OptionDescription'
|
||||||
|
return 'Leadership'
|
|
@ -6,9 +6,8 @@ from os import listdir
|
||||||
from lxml.etree import DTD, parse, tostring # , XMLParser
|
from lxml.etree import DTD, parse, tostring # , XMLParser
|
||||||
|
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .error import CreoleDictConsistencyError
|
from .error import DictConsistencyError
|
||||||
|
|
||||||
HIGH_COMPATIBILITY = True
|
|
||||||
|
|
||||||
class XMLReflector(object):
|
class XMLReflector(object):
|
||||||
"""Helper class for loading the Creole XML file,
|
"""Helper class for loading the Creole XML file,
|
||||||
|
@ -35,23 +34,18 @@ class XMLReflector(object):
|
||||||
|
|
||||||
:returns: the root element tree object
|
:returns: the root element tree object
|
||||||
"""
|
"""
|
||||||
# FIXME zephir2
|
|
||||||
# document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True))
|
# document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True))
|
||||||
document = parse(xmlfile)
|
document = parse(xmlfile)
|
||||||
if not self.dtd.validate(document):
|
if not self.dtd.validate(document):
|
||||||
raise CreoleDictConsistencyError(_("not a valid xml file: {}").format(xmlfile))
|
raise DictConsistencyError(_("not a valid xml file: {}").format(xmlfile))
|
||||||
return document.getroot()
|
return document.getroot()
|
||||||
|
|
||||||
def load_xml_from_folders(self, xmlfolders, from_zephir):
|
def load_xml_from_folders(self, xmlfolders):
|
||||||
"""Loads all the XML files located in the xmlfolders' list
|
"""Loads all the XML files located in the xmlfolders' list
|
||||||
|
|
||||||
:param xmlfolders: list of full folder's name
|
:param xmlfolders: list of full folder's name
|
||||||
"""
|
"""
|
||||||
documents = []
|
documents = []
|
||||||
if from_zephir:
|
|
||||||
for idx, xmlfile in enumerate(xmlfolders):
|
|
||||||
documents.append(('generate_{}'.format(idx), self.parse_xmlfile(xmlfile, from_zephir=from_zephir)))
|
|
||||||
else:
|
|
||||||
if not isinstance(xmlfolders, list):
|
if not isinstance(xmlfolders, list):
|
||||||
xmlfolders = [xmlfolders]
|
xmlfolders = [xmlfolders]
|
||||||
for xmlfolder in xmlfolders:
|
for xmlfolder in xmlfolders:
|
||||||
|
|
|
@ -24,10 +24,6 @@ def get_mount_point_device(*args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def valid_entier(*args, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def valid_differ(*args, **kwargs):
|
def valid_differ(*args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -59,3 +55,7 @@ def cdrom_minormajor(*args, **kwargs):
|
||||||
|
|
||||||
def device_type(*args, **kwargs):
|
def device_type(*args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def calc_list(*args, **kwargs):
|
||||||
|
return []
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family name="services">
|
|
||||||
<family name="service0" doc="tata">
|
|
||||||
<property>basic</property>
|
|
||||||
</family>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_2 = OptionDescription(name='tata', doc='tata', children=[])
|
||||||
|
option_2.impl_set_information("manage", True)
|
||||||
|
option_1 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1,8 +1,6 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<rougail>
|
<rougail>
|
||||||
|
|
||||||
<services/>
|
|
||||||
|
|
||||||
<variables>
|
<variables>
|
||||||
<family name="général">
|
<family name="général">
|
||||||
<variable name="mode_conteneur_actif" type="oui/non" description="No change" auto_freeze="True">
|
<variable name="mode_conteneur_actif" type="oui/non" description="No change" auto_freeze="True">
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif": "non", "creole.general.module_instancie": "non"}
|
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.module_instancie": "non"}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>basic</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<property>force_store_value</property>
|
|
||||||
<property>auto_freeze</property>
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>basic</property>
|
|
||||||
<property expected="oui" inverse="True" source="creole.general.module_instancie" type="calculation">auto_frozen</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="module_instancie" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'auto_freeze', 'basic', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_4, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'basic'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif": "non", "creole.general.module_instancie": "non"}
|
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.module_instancie": "non"}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<property>force_store_value</property>
|
|
||||||
<property>auto_freeze</property>
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>expert</property>
|
|
||||||
<property expected="oui" inverse="True" source="creole.general.module_instancie" type="calculation">auto_frozen</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="module_instancie" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'auto_freeze', 'expert', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_4, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif": "non"}
|
{"rougail.general.mode_conteneur_actif": "non"}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>basic</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<property>force_store_value</property>
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>basic</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'basic', 'force_store_value', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'basic'}), children=[option_3])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif": "non"}
|
{"rougail.general.mode_conteneur_actif": "non"}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>expert</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<property>force_store_value</property>
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>expert</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'expert', 'force_store_value', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'expert'}), children=[option_3])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -0,0 +1 @@
|
||||||
|
{"rougail.general.mode_conteneur_actif": "non"}
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.without_type": "non"}
|
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.without_type": "non"}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="without_type" multi="False" name="without_type" type="string">
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value>non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_4 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='without_type', doc='without_type', multi=False, default='non')
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -0,0 +1 @@
|
||||||
|
{"rougail.general.mode_conteneur_actif": "non"}
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -0,0 +1 @@
|
||||||
|
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1": "non"}
|
|
@ -1,29 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="général" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -16,9 +16,9 @@
|
||||||
</variables>
|
</variables>
|
||||||
|
|
||||||
<constraints>
|
<constraints>
|
||||||
<auto name="calc_val" target="mode_conteneur_actif">
|
<fill name="calc_val" target="mode_conteneur_actif">
|
||||||
<param type="variable">mode_conteneur_actif1</param>
|
<param type="variable">mode_conteneur_actif1</param>
|
||||||
</auto>
|
</fill>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
||||||
<help/>
|
<help/>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif1": "non"}
|
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non"}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value name="calc_val" type="calculation">
|
|
||||||
<param transitive="False" type="variable">creole.general.mode_conteneur_actif1</param>
|
|
||||||
</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -16,8 +16,8 @@
|
||||||
</variables>
|
</variables>
|
||||||
|
|
||||||
<constraints>
|
<constraints>
|
||||||
<auto name="calc_val" target="mode_conteneur_actif">
|
<fill name="calc_val" target="mode_conteneur_actif">
|
||||||
</auto>
|
</fill>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
||||||
<help/>
|
<help/>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif1": "non"}
|
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non"}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="calculation">calc_val</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((), kwargs={})), values=('oui', 'non'))
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -0,0 +1 @@
|
||||||
|
{"rougail.general.mode_conteneur_actif": ["non"]}
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="Redefine description" multi="True" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='Redefine description', multi=True, default=['non'], default_multi='non', values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1,22 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<rougail>
|
|
||||||
|
|
||||||
<services/>
|
|
||||||
|
|
||||||
<variables>
|
|
||||||
<family name="general">
|
|
||||||
<variable name="mode_conteneur_actif" type="oui/non" description="Redefine description" hidden="True" submulti="True">
|
|
||||||
<value>non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</variables>
|
|
||||||
|
|
||||||
<constraints>
|
|
||||||
</constraints>
|
|
||||||
|
|
||||||
<help/>
|
|
||||||
|
|
||||||
</rougail>
|
|
||||||
<!-- vim: ts=4 sw=4 expandtab
|
|
||||||
-->
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="Redefine description" multi="submulti" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non", "creole.general.module_instancie": "non"}
|
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non", "rougail.general.module_instancie": "non"}
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>basic</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<property>force_store_value</property>
|
|
||||||
<property>auto_freeze</property>
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>basic</property>
|
|
||||||
<property expected="oui" inverse="True" source="creole.general.module_instancie" type="calculation">auto_frozen</property>
|
|
||||||
<value name="calc_val" type="calculation">
|
|
||||||
<param transitive="False" type="variable">creole.general.mode_conteneur_actif1</param>
|
|
||||||
</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="module_instancie" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'auto_freeze', 'basic', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_5, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4, option_5])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"}
|
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non"}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>basic</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<property>force_store_value</property>
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>basic</property>
|
|
||||||
<value name="calc_val" type="calculation">
|
|
||||||
<param transitive="False" type="variable">creole.general.mode_conteneur_actif1</param>
|
|
||||||
</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'basic', 'force_store_value', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif1": "non"}
|
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non"}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="general" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value name="calc_val" type="calculation">
|
|
||||||
<param transitive="False" type="variable">creole.general.mode_conteneur_actif1</param>
|
|
||||||
</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
|
@ -1 +1 @@
|
||||||
{"creole.general.mode_conteneur_actif1": "non"}
|
{"rougail.general.mode_conteneur_actif": null, "rougail.general.mode_conteneur_actif1": "non"}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<creole>
|
|
||||||
<family doc="" name="creole">
|
|
||||||
<family doc="Général" name="general">
|
|
||||||
<property>normal</property>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>force_default_on_freeze</property>
|
|
||||||
<property>frozen</property>
|
|
||||||
<property>hidden</property>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value name="calc_val" type="calculation">
|
|
||||||
<param transitive="False" type="variable">creole.general.mode_conteneur_actif1</param>
|
|
||||||
</value>
|
|
||||||
</variable>
|
|
||||||
<variable doc="No change" multi="False" name="mode_conteneur_actif1" type="choice">
|
|
||||||
<choice type="string">oui</choice>
|
|
||||||
<choice type="string">non</choice>
|
|
||||||
<property>mandatory</property>
|
|
||||||
<property>normal</property>
|
|
||||||
<value type="string">non</value>
|
|
||||||
</variable>
|
|
||||||
</family>
|
|
||||||
<separators/>
|
|
||||||
</family>
|
|
||||||
</creole>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from rougail.tiramisu import ConvertDynOptionDescription
|
||||||
|
import imp
|
||||||
|
func = imp.load_source('func', 'tests/flattener_dicos/../eosfunc/test.py')
|
||||||
|
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
|
||||||
|
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
|
||||||
|
option_2 = OptionDescription(name='general', doc='Général', properties=frozenset({'normal'}), children=[option_3, option_4])
|
||||||
|
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
|
||||||
|
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue