Compare commits

..

12 Commits

59 changed files with 579 additions and 125 deletions

View File

@ -34,11 +34,38 @@ def mode_factory():
modes = mode_factory() modes = mode_factory()
CONVERT_OPTION = {'number': dict(opttype="IntOption", func=int),
'float': dict(opttype="FloatOption", func=float),
'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}),
}
# 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', 'remove_fill') 'level', 'remove_fill', 'xmlfiles')
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'],
@ -56,8 +83,6 @@ KEY_TYPE = {'variable': 'symlink',
'URLOption': 'web_address', 'URLOption': 'web_address',
'FilenameOption': 'filename'} 'FilenameOption': 'filename'}
CONVERSION = {'number': int}
FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie' FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze', PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
@ -108,7 +133,7 @@ class GroupAnnotator:
self.manage_follower(namespace, self.manage_follower(namespace,
leader_family_name, leader_family_name,
variable, variable,
leader_name, leadership_name,
follower_names, follower_names,
leader_space, leader_space,
leader_is_hidden, leader_is_hidden,
@ -125,9 +150,14 @@ class GroupAnnotator:
# if variable.hidden: # if variable.hidden:
# leader_is_hidden = True # leader_is_hidden = True
else: else:
leader_space = self.objectspace.Leadership() leader_space = self.objectspace.Leadership(variable.xmlfiles)
if hasattr(group, 'name'):
leadership_name = group.name
else:
leadership_name = leader_name
leader_is_hidden = self.manage_leader(leader_space, leader_is_hidden = self.manage_leader(leader_space,
leader_family_name, leader_family_name,
leadership_name,
leader_name, leader_name,
namespace, namespace,
variable, variable,
@ -142,6 +172,7 @@ class GroupAnnotator:
def manage_leader(self, def manage_leader(self,
leader_space: 'Leadership', leader_space: 'Leadership',
leader_family_name: str, leader_family_name: str,
leadership_name: str,
leader_name: str, leader_name: str,
namespace: str, namespace: str,
variable: 'Variable', variable: 'Variable',
@ -152,7 +183,7 @@ class GroupAnnotator:
if variable.multi is not True: if variable.multi is not True:
raise DictConsistencyError(_('the variable {} in a group must be multi').format(variable.name)) raise DictConsistencyError(_('the variable {} in a group must be multi').format(variable.name))
leader_space.variable = [] leader_space.variable = []
leader_space.name = leader_name leader_space.name = leadership_name
leader_space.hidden = variable.hidden leader_space.hidden = variable.hidden
if variable.hidden: if variable.hidden:
leader_is_hidden = True leader_is_hidden = True
@ -167,9 +198,9 @@ class GroupAnnotator:
leader_space.doc = variable.description leader_space.doc = variable.description
else: else:
leader_space.doc = variable.name leader_space.doc = variable.name
leader_path = namespace + '.' + leader_family_name + '.' + leader_name leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name
self.objectspace.paths.add_family(namespace, self.objectspace.paths.add_family(namespace,
leader_path, leadership_path,
leader_space, leader_space,
) )
leader_family = self.objectspace.space.variables[namespace].family[leader_family_name] leader_family = self.objectspace.space.variables[namespace].family[leader_family_name]
@ -233,7 +264,7 @@ class ServiceAnnotator:
families = {} families = {}
for idx, service_name in enumerate(self.objectspace.space.services.service.keys()): for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
service = self.objectspace.space.services.service[service_name] service = self.objectspace.space.services.service[service_name]
new_service = self.objectspace.service() new_service = self.objectspace.service(service.xmlfiles)
for elttype, values in vars(service).items(): for elttype, values in vars(service).items():
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES: if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
setattr(new_service, elttype, values) setattr(new_service, elttype, values)
@ -242,6 +273,7 @@ class ServiceAnnotator:
path = '.'.join(['services', service_name, eltname]) path = '.'.join(['services', service_name, eltname])
family = self.gen_family(eltname, family = self.gen_family(eltname,
path, path,
service.xmlfiles,
) )
if isinstance(values, dict): if isinstance(values, dict):
values = list(values.values()) values = list(values.values())
@ -258,8 +290,9 @@ class ServiceAnnotator:
def gen_family(self, def gen_family(self,
name, name,
path, path,
xmlfiles
): ):
family = self.objectspace.family() family = self.objectspace.family(xmlfiles)
family.name = normalize_family(name) family.name = normalize_family(name)
family.doc = name family.doc = name
family.mode = None family.mode = None
@ -307,7 +340,10 @@ class ServiceAnnotator:
if not self.objectspace.paths.family_is_defined(subpath): if not self.objectspace.paths.family_is_defined(subpath):
break break
idx += 1 idx += 1
family = self.gen_family(c_name, subpath) family = self.gen_family(c_name,
subpath,
elt.xmlfiles,
)
family.variable = [] family.variable = []
listname = '{}list'.format(name) listname = '{}list'.format(name)
activate_path = '.'.join([subpath, 'activate']) activate_path = '.'.join([subpath, 'activate'])
@ -345,7 +381,7 @@ class ServiceAnnotator:
elt, elt,
path, path,
): ):
variable = self.objectspace.variable() variable = self.objectspace.variable(elt.xmlfiles)
variable.name = normalize_family(key) variable.name = normalize_family(key)
variable.mode = None variable.mode = None
if key == 'name': if key == 'name':
@ -370,7 +406,7 @@ class ServiceAnnotator:
variable.multi = None variable.multi = None
else: else:
variable.doc = key variable.doc = key
val = self.objectspace.value() val = self.objectspace.value(elt.xmlfiles)
val.type = type_ val.type = type_
val.name = value val.name = value
variable.value = [val] variable.value = [val]
@ -454,7 +490,7 @@ class VariableAnnotator:
for value in variable.value: for value in variable.value:
if not hasattr(value, 'type'): if not hasattr(value, 'type'):
value.type = variable.type value.type = variable.type
value.name = CONVERSION.get(value.type, str)(value.name) value.name = CONVERT_OPTION.get(value.type, {}).get('func', str)(value.name)
for key, value in RENAME_ATTIBUTES.items(): for key, value in RENAME_ATTIBUTES.items():
setattr(variable, value, getattr(variable, key)) setattr(variable, value, getattr(variable, key))
setattr(variable, key, None) setattr(variable, key, None)
@ -469,23 +505,28 @@ class VariableAnnotator:
path, path,
): ):
if variable.type in FORCE_CHOICE: if variable.type in FORCE_CHOICE:
check = self.objectspace.check() check = self.objectspace.check(variable.xmlfiles)
check.name = 'valid_enum' check.name = 'valid_enum'
check.target = path check.target = path
check.namespace = namespace check.namespace = namespace
check.param = [] check.param = []
for value in FORCE_CHOICE[variable.type]: for value in FORCE_CHOICE[variable.type]:
param = self.objectspace.param() param = self.objectspace.param(variable.xmlfiles)
param.text = value param.text = value
check.param.append(param) check.param.append(param)
if not hasattr(self.objectspace.space, 'constraints'): if not hasattr(self.objectspace.space, 'constraints'):
self.objectspace.space.constraints = self.objectspace.constraints() self.objectspace.space.constraints = self.objectspace.constraints(variable.xmlfiles)
self.objectspace.space.constraints.namespace = namespace self.objectspace.space.constraints.namespace = namespace
if not hasattr(self.objectspace.space.constraints, 'check'): if not hasattr(self.objectspace.space.constraints, 'check'):
self.objectspace.space.constraints.check = [] self.objectspace.space.constraints.check = []
self.objectspace.space.constraints.check.append(check) self.objectspace.space.constraints.check.append(check)
variable.type = 'string' variable.type = 'string'
def _valid_type(variable):
if variable.type not in CONVERT_OPTION:
xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles)
raise DictConsistencyError(_(f'unvalid type "{variable.type}" for variable "{variable.name}" in {xmlfiles}'))
if not hasattr(self.objectspace.space, 'variables'): if not hasattr(self.objectspace.space, 'variables'):
return return
for families in self.objectspace.space.variables.values(): for families in self.objectspace.space.variables.values():
@ -515,6 +556,7 @@ class VariableAnnotator:
follower, follower,
path, path,
) )
_valid_type(follower)
else: else:
path = '{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name) path = '{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name)
_convert_variable(variable, _convert_variable(variable,
@ -524,6 +566,7 @@ class VariableAnnotator:
variable, variable,
path, path,
) )
_valid_type(variable)
def convert_helps(self): def convert_helps(self):
if not hasattr(self.objectspace.space, 'help'): if not hasattr(self.objectspace.space, 'help'):
@ -542,14 +585,14 @@ class VariableAnnotator:
def convert_auto_freeze(self): # pylint: disable=C0111 def convert_auto_freeze(self): # pylint: disable=C0111
def _convert_auto_freeze(variable, namespace): def _convert_auto_freeze(variable, namespace):
if variable.auto_freeze: if variable.auto_freeze:
new_condition = self.objectspace.condition() new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_hidden_if_not_in' new_condition.name = 'auto_hidden_if_not_in'
new_condition.namespace = namespace new_condition.namespace = namespace
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param = self.objectspace.param() new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = 'oui' new_param.text = 'oui'
new_condition.param = [new_param] new_condition.param = [new_param]
new_target = self.objectspace.target() new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = 'variable' new_target.type = 'variable'
path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name
new_target.name = path new_target.name = path
@ -583,7 +626,8 @@ class VariableAnnotator:
subpath = self.objectspace.paths.get_variable_path(separator.name, subpath = self.objectspace.paths.get_variable_path(separator.name,
separator.namespace, separator.namespace,
) )
raise DictConsistencyError(_('{} already has a separator').format(subpath)) xmlfiles = self.objectspace.display_xmlfiles(separator.xmlfiles)
raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'))
option.separator = separator.text option.separator = separator.text
del family.separators del family.separators
@ -622,7 +666,8 @@ class ConstraintAnnotator:
remove_indexes = [] remove_indexes = []
for check_idx, check in enumerate(self.objectspace.space.constraints.check): for check_idx, check in enumerate(self.objectspace.space.constraints.check):
if not check.name in self.functions: if not check.name in self.functions:
raise DictConsistencyError(_('cannot find check function {}').format(check.name)) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'))
if hasattr(check, 'param'): if hasattr(check, 'param'):
param_option_indexes = [] param_option_indexes = []
for idx, param in enumerate(check.param): for idx, param in enumerate(check.param):
@ -630,7 +675,8 @@ class ConstraintAnnotator:
if param.optional is True: if param.optional is True:
param_option_indexes.append(idx) param_option_indexes.append(idx)
else: else:
raise DictConsistencyError(_(f'unknown param {param.text} in check')) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'))
if param.type != 'variable': if param.type != 'variable':
param.notraisepropertyerror = None param.notraisepropertyerror = None
param_option_indexes = list(set(param_option_indexes)) param_option_indexes = list(set(param_option_indexes))
@ -766,7 +812,7 @@ class ConstraintAnnotator:
for listvar in listvars: for listvar in listvars:
variable = self.objectspace.paths.get_variable_obj(listvar) variable = self.objectspace.paths.get_variable_obj(listvar)
type_ = 'variable' type_ = 'variable'
new_target = self.objectspace.target() new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = type_ new_target.type = type_
new_target.name = listvar new_target.name = listvar
new_target.index = target.index new_target.index = target.index
@ -891,7 +937,7 @@ class ConstraintAnnotator:
if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True: if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True:
continue continue
for idx, action in enumerate(actions): for idx, action in enumerate(actions):
prop = self.objectspace.property_() prop = self.objectspace.property_(leader_or_variable.xmlfiles)
prop.type = 'calculation' prop.type = 'calculation'
prop.inverse = inverse prop.inverse = inverse
prop.source = condition.source prop.source = condition.source
@ -924,10 +970,10 @@ class ConstraintAnnotator:
} }
choices = [] choices = []
for value in values: for value in values:
choice = self.objectspace.choice() choice = self.objectspace.choice(variable.xmlfiles)
try: try:
if value is not None: if value is not None:
choice.name = CONVERSION.get(type_, str)(value) choice.name = CONVERT_OPTION[type_].get('func', str)(value)
else: else:
choice.name = value choice.name = value
except: except:
@ -942,13 +988,13 @@ class ConstraintAnnotator:
for value in variable.value: for value in variable.value:
value.type = type_ value.type = type_
try: try:
cvalue = CONVERSION.get(type_, str)(value.name) cvalue = CONVERT_OPTION[type_].get('func', str)(value.name)
except: except:
raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"')) raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"'))
if cvalue not in choices: if cvalue not in choices:
raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices)) raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
else: else:
new_value = self.objectspace.value() new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = choices[0] new_value.name = choices[0]
new_value.type = type_ new_value.type = type_
variable.value = [new_value] variable.value = [new_value]
@ -973,26 +1019,30 @@ class ConstraintAnnotator:
else: else:
raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}')) raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'))
else: else:
check_ = self.objectspace.check() check_ = self.objectspace.check(variable.xmlfiles)
if name == 'valid_differ': if name == 'valid_differ':
name = 'valid_not_equal' name = 'valid_not_equal'
elif name == 'valid_network_netmask': elif name == 'valid_network_netmask':
params_len = 1 params_len = 1
if len(check.param) != params_len: if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len)) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_ipnetmask': elif name == 'valid_ipnetmask':
params_len = 1 params_len = 1
if len(check.param) != params_len: if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len)) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
name = 'valid_ip_netmask' name = 'valid_ip_netmask'
elif name == 'valid_broadcast': elif name == 'valid_broadcast':
params_len = 2 params_len = 2
if len(check.param) != params_len: if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len)) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_in_network': elif name == 'valid_in_network':
if len(check.param) not in (1, 2):
params_len = 2 params_len = 2
if len(check.param) != params_len: xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_('{} must have {} param').format(name, params_len)) raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
check_.name = name check_.name = name
check_.warnings_only = check.warnings_only check_.warnings_only = check.warnings_only
if hasattr(check, 'param'): if hasattr(check, 'param'):
@ -1026,7 +1076,8 @@ class ConstraintAnnotator:
) )
if suffix is not None: if suffix is not None:
raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"')) raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"'))
value = self.objectspace.value() variable = self.objectspace.paths.get_variable_obj(fill.target)
value = self.objectspace.value(variable.xmlfiles)
value.type = 'calculation' value.type = 'calculation'
value.name = fill.name value.name = fill.name
if hasattr(fill, 'param'): if hasattr(fill, 'param'):
@ -1058,7 +1109,6 @@ class ConstraintAnnotator:
for param_idx in param_to_delete: for param_idx in param_to_delete:
fill.param.pop(param_idx) fill.param.pop(param_idx)
value.param = fill.param value.param = fill.param
variable = self.objectspace.paths.get_variable_obj(fill.target)
variable.value = [value] variable.value = [value]
del self.objectspace.space.constraints.fill del self.objectspace.space.constraints.fill
@ -1066,6 +1116,7 @@ class ConstraintAnnotator:
if hasattr(self.objectspace.space.constraints, 'index'): if hasattr(self.objectspace.space.constraints, 'index'):
del self.objectspace.space.constraints.index del self.objectspace.space.constraints.index
del self.objectspace.space.constraints.namespace del self.objectspace.space.constraints.namespace
del self.objectspace.space.constraints.xmlfiles
if vars(self.objectspace.space.constraints): if vars(self.objectspace.space.constraints):
raise Exception('constraints again?') raise Exception('constraints again?')
del self.objectspace.space.constraints del self.objectspace.space.constraints
@ -1126,7 +1177,7 @@ class FamilyAnnotator:
# 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'
if not hasattr(variable, 'value') and variable.type == 'boolean': if not hasattr(variable, 'value') and variable.type == 'boolean':
new_value = self.objectspace.value() new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = True new_value.name = True
new_value.type = 'boolean' new_value.type = 'boolean'
variable.value = [new_value] variable.value = [new_value]

View File

@ -131,6 +131,7 @@
<!ELEMENT group (follower+)> <!ELEMENT group (follower+)>
<!ATTLIST group leader CDATA #REQUIRED> <!ATTLIST group leader CDATA #REQUIRED>
<!ATTLIST group name CDATA #IMPLIED>
<!ATTLIST group description CDATA #IMPLIED> <!ATTLIST group description CDATA #IMPLIED>
<!ELEMENT param (#PCDATA)> <!ELEMENT param (#PCDATA)>

View File

@ -59,7 +59,10 @@ CONVERT_EXPORT = {'Leadership': 'leader',
# _____________________________________________________________________________ # _____________________________________________________________________________
# special types definitions for the Object Space's internal representation # special types definitions for the Object Space's internal representation
class RootCreoleObject: class RootCreoleObject:
"" def __init__(self, xmlfiles):
if not isinstance(xmlfiles, list):
xmlfiles = [xmlfiles]
self.xmlfiles = xmlfiles
class CreoleObjSpace: class CreoleObjSpace:
@ -157,12 +160,14 @@ class CreoleObjSpace:
self.fill_removed = [] self.fill_removed = []
self.check_removed = [] self.check_removed = []
self.condition_removed = [] self.condition_removed = []
self.xml_parse_document(document, self.xml_parse_document(xmlfile,
document,
self.space, self.space,
namespace, namespace,
) )
def xml_parse_document(self, def xml_parse_document(self,
xmlfile,
document, document,
space, space,
namespace, namespace,
@ -179,7 +184,7 @@ class CreoleObjSpace:
continue continue
if child.tag == 'family': if child.tag == 'family':
if child.attrib['name'] in family_names: if child.attrib['name'] in family_names:
raise DictConsistencyError(_('Family {} is set several times').format(child.attrib['name'])) raise DictConsistencyError(_(f'Family "{child.attrib["name"]}" is set several times in "{xmlfile}"'))
family_names.append(child.attrib['name']) family_names.append(child.attrib['name'])
if child.tag == 'variables': if child.tag == 'variables':
child.attrib['name'] = namespace child.attrib['name'] = namespace
@ -188,7 +193,8 @@ class CreoleObjSpace:
continue continue
# variable objects creation # variable objects creation
try: try:
variableobj = self.generate_variableobj(child, variableobj = self.generate_variableobj(xmlfile,
child,
space, space,
namespace, namespace,
) )
@ -197,7 +203,8 @@ class CreoleObjSpace:
self.set_text_to_obj(child, self.set_text_to_obj(child,
variableobj, variableobj,
) )
self.set_xml_attributes_to_obj(child, self.set_xml_attributes_to_obj(xmlfile,
child,
variableobj, variableobj,
) )
self.variableobj_tree_visitor(child, self.variableobj_tree_visitor(child,
@ -215,12 +222,14 @@ class CreoleObjSpace:
child, child,
) )
if list(child) != []: if list(child) != []:
self.xml_parse_document(child, self.xml_parse_document(xmlfile,
child,
variableobj, variableobj,
namespace, namespace,
) )
def generate_variableobj(self, def generate_variableobj(self,
xmlfile,
child, child,
space, space,
namespace, namespace,
@ -228,9 +237,10 @@ class CreoleObjSpace:
""" """
instanciates or creates Creole Object Subspace objects instanciates or creates Creole Object Subspace objects
""" """
variableobj = getattr(self, child.tag)() variableobj = getattr(self, child.tag)(xmlfile)
if isinstance(variableobj, self.Redefinable): if isinstance(variableobj, self.Redefinable):
variableobj = self.create_or_update_redefinable_object(child.attrib, variableobj = self.create_or_update_redefinable_object(xmlfile,
child.attrib,
space, space,
child, child,
namespace, namespace,
@ -248,6 +258,7 @@ class CreoleObjSpace:
return variableobj return variableobj
def create_or_update_redefinable_object(self, def create_or_update_redefinable_object(self,
xmlfile,
subspace, subspace,
space, space,
child, child,
@ -281,15 +292,17 @@ class CreoleObjSpace:
name = child.text name = child.text
else: else:
name = subspace['name'] name = subspace['name']
if self.is_already_exists(name, existed_var = self.is_already_exists(name,
space, space,
child, child,
namespace, namespace,
): )
if existed_var:
default_redefine = child.tag in FORCE_REDEFINABLES default_redefine = child.tag in FORCE_REDEFINABLES
redefine = self.convert_boolean(subspace.get('redefine', default_redefine)) redefine = self.convert_boolean(subspace.get('redefine', default_redefine))
exists = self.convert_boolean(subspace.get('exists', True)) exists = self.convert_boolean(subspace.get('exists', True))
if redefine is True: if redefine is True:
existed_var.xmlfiles.append(xmlfile)
return self.translate_in_space(name, return self.translate_in_space(name,
space, space,
child, child,
@ -297,12 +310,21 @@ class CreoleObjSpace:
) )
elif exists is False: elif exists is False:
raise SpaceObjShallNotBeUpdated() raise SpaceObjShallNotBeUpdated()
raise DictConsistencyError(_(f'Already present in another XML file, {name} cannot be re-created')) xmlfiles = self.display_xmlfiles(existed_var.xmlfiles)
raise DictConsistencyError(_(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", already defined in {xmlfiles}'))
redefine = self.convert_boolean(subspace.get('redefine', False)) redefine = self.convert_boolean(subspace.get('redefine', False))
exists = self.convert_boolean(subspace.get('exists', 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)(xmlfile)
raise DictConsistencyError(_(f'Redefined object: {name} does not exist yet')) raise DictConsistencyError(_(f'Redefined object in "{xmlfile}": "{name}" does not exist yet'))
def display_xmlfiles(self,
xmlfiles: list,
) -> str:
if len(xmlfiles) == 1:
return '"' + xmlfiles[0] + '"'
else:
return '"' + '", "'.join(xmlfiles[:-1]) + '"' + ' and ' + '"' + xmlfiles[-1] + '"'
def create_tree_structure(self, def create_tree_structure(self,
space, space,
@ -329,16 +351,25 @@ class CreoleObjSpace:
raise OperationError(_("Creole object {} " raise OperationError(_("Creole object {} "
"has a wrong type").format(type(variableobj))) "has a wrong type").format(type(variableobj)))
def is_already_exists(self, name, space, child, namespace): def is_already_exists(self,
name: str,
space: str,
child,
namespace: str,
):
if isinstance(space, self.family): # pylint: disable=E1101 if isinstance(space, self.family): # pylint: disable=E1101
if namespace != Config['variable_namespace']: if namespace != Config['variable_namespace']:
name = space.path + '.' + name name = space.path + '.' + name
return self.paths.path_is_defined(name) if self.paths.path_is_defined(name):
return self.paths.get_variable_obj(name)
return
if child.tag == 'family': if child.tag == 'family':
norm_name = normalize_family(name) norm_name = normalize_family(name)
else: else:
norm_name = name norm_name = name
return norm_name in getattr(space, child.tag, {}) children = getattr(space, child.tag, {})
if norm_name in children:
return children[norm_name]
def convert_boolean(self, value): # pylint: disable=R0201 def convert_boolean(self, value): # pylint: disable=R0201
"""Boolean coercion. The Creole XML may contain srings like `True` or `False` """Boolean coercion. The Creole XML may contain srings like `True` or `False`
@ -451,6 +482,7 @@ class CreoleObjSpace:
variableobj.text = text variableobj.text = text
def set_xml_attributes_to_obj(self, def set_xml_attributes_to_obj(self,
xmlfile,
child, child,
variableobj, variableobj,
): ):
@ -463,7 +495,8 @@ class CreoleObjSpace:
# 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 DictConsistencyError(_(f'cannot redefine attribute {attr} for variable {name}')) xmlfiles = self.display_xmlfiles(variableobj.xmlfiles[:-1])
raise DictConsistencyError(_(f'cannot redefine attribute "{attr}" for variable "{name}" in "{xmlfile}", already defined in {xmlfiles}'))
if attr in self.booleans_attributs: if attr in self.booleans_attributs:
val = self.convert_boolean(val) val = self.convert_boolean(val)
if not (attr == 'name' and getattr(variableobj, 'name', None) != None): if not (attr == 'name' and getattr(variableobj, 'name', None) != None):

View File

@ -13,7 +13,8 @@ class Path:
def __init__(self): def __init__(self):
self.variables = {} self.variables = {}
self.families = {} self.families = {}
self.full_paths = {} self.full_paths_families = {}
self.full_paths_variables = {}
# Family # Family
def add_family(self, def add_family(self,
@ -23,7 +24,7 @@ class Path:
) -> str: # pylint: disable=C0111 ) -> str: # pylint: disable=C0111
if '.' not in name and namespace == Config['variable_namespace']: if '.' not in name and namespace == Config['variable_namespace']:
full_name = '.'.join([namespace, name]) full_name = '.'.join([namespace, name])
self.full_paths[name] = full_name self.full_paths_families[name] = full_name
else: else:
full_name = name full_name = name
if full_name in self.families and self.families[full_name]['variableobj'] != variableobj: if full_name in self.families and self.families[full_name]['variableobj'] != variableobj:
@ -41,8 +42,8 @@ class Path:
check_name=False, check_name=False,
allow_dot=True, allow_dot=True,
) )
if '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths: if '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths_families:
name = self.full_paths[name] name = self.full_paths_families[name]
if current_namespace is None: # pragma: no cover if current_namespace is None: # pragma: no cover
raise OperationError('current_namespace must not be None') raise OperationError('current_namespace must not be None')
dico = self.families[name] dico = self.families[name]
@ -55,8 +56,8 @@ class Path:
def get_family_obj(self, def get_family_obj(self,
name: str, name: str,
) -> 'Family': # pylint: disable=C0111 ) -> 'Family': # pylint: disable=C0111
if '.' not in name and name in self.full_paths: if '.' not in name and name in self.full_paths_families:
name = self.full_paths[name] name = self.full_paths_families[name]
if name not in self.families: if name not in self.families:
raise DictConsistencyError(_('unknown family {}').format(name)) raise DictConsistencyError(_('unknown family {}').format(name))
dico = self.families[name] dico = self.families[name]
@ -65,7 +66,7 @@ class Path:
def family_is_defined(self, def family_is_defined(self,
name: str, name: str,
) -> str: # pylint: disable=C0111 ) -> str: # pylint: disable=C0111
if '.' not in name and name not in self.families and name in self.full_paths: if '.' not in name and name not in self.families and name in self.full_paths_families:
return True return True
return name in self.families return name in self.families
@ -88,7 +89,7 @@ class Path:
dico['variableobj'], dico['variableobj'],
) )
if namespace == Config['variable_namespace']: if namespace == Config['variable_namespace']:
self.full_paths[name] = new_path self.full_paths_variables[name] = new_path
else: else:
name = new_path name = new_path
dico = self._get_variable(name) dico = self._get_variable(name)
@ -110,7 +111,7 @@ class Path:
) -> str: # pylint: disable=C0111 ) -> str: # pylint: disable=C0111
if '.' not in name: if '.' not in name:
full_name = '.'.join([namespace, family, name]) full_name = '.'.join([namespace, family, name])
self.full_paths[name] = full_name self.full_paths_variables[name] = full_name
else: else:
full_name = name full_name = name
if namespace == Config['variable_namespace']: if namespace == Config['variable_namespace']:
@ -176,7 +177,7 @@ class Path:
def path_is_defined(self, def path_is_defined(self,
name: str, name: str,
) -> str: # pylint: disable=C0111 ) -> str: # pylint: disable=C0111
if '.' not in name and name not in self.variables and name in self.full_paths: if '.' not in name and name not in self.variables and name in self.full_paths_variables:
return True return True
return name in self.variables return name in self.variables
@ -186,8 +187,8 @@ class Path:
) -> str: ) -> str:
if name not in self.variables: if name not in self.variables:
if name not in self.variables: if name not in self.variables:
if '.' not in name and name in self.full_paths: if '.' not in name and name in self.full_paths_variables:
name = self.full_paths[name] name = self.full_paths_variables[name]
if name not in self.variables: if name not in self.variables:
for var_name, variable in self.variables.items(): for var_name, variable in self.variables.items():
if variable['is_dynamic'] and name.startswith(var_name): if variable['is_dynamic'] and name.startswith(var_name):
@ -195,9 +196,9 @@ class Path:
raise Exception('This option is dynamic, should use "with_suffix" attribute') raise Exception('This option is dynamic, should use "with_suffix" attribute')
return variable, name[len(var_name):] return variable, name[len(var_name):]
if '.' not in name: if '.' not in name:
for var_name, path in self.full_paths.items(): for var_name, path in self.full_paths_variables.items():
if name.startswith(var_name): if name.startswith(var_name):
variable = self.variables[self.full_paths[var_name]] variable = self.variables[self.full_paths_variables[var_name]]
if variable['is_dynamic']: if variable['is_dynamic']:
if not with_suffix: if not with_suffix:
raise Exception('This option is dynamic, should use "with_suffix" attribute') raise Exception('This option is dynamic, should use "with_suffix" attribute')

View File

@ -10,7 +10,7 @@ import logging
from typing import Dict, Any from typing import Dict, Any
from subprocess import call from subprocess import call
from os import listdir, makedirs from os import listdir, makedirs
from os.path import dirname, join, isfile from os.path import dirname, join, isfile, abspath, normpath
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
@ -92,6 +92,21 @@ class CheetahTemplate(ChtTemplate):
file=filename, file=filename,
searchList=[context, eosfunc, extra_context]) searchList=[context, eosfunc, extra_context])
# FORK of Cheetah fonction, do not replace '\\' by '/'
def serverSidePath(self, path=None,
normpath=normpath,
abspath=abspath
):
if path:
return normpath(abspath(path))
# return normpath(abspath(path.replace("\\", '/')))
elif hasattr(self, '_filePath') and self._filePath:
return normpath(abspath(self._filePath))
else:
return None
class CreoleLeader: class CreoleLeader:
def __init__(self, value, follower=None, index=None): def __init__(self, value, follower=None, index=None):

View File

@ -4,7 +4,7 @@ flattened XML specific
from .config import Config from .config import Config
from .i18n import _ from .i18n import _
from .error import LoaderError from .error import LoaderError
from .annotator import ERASED_ATTRIBUTES from .annotator import ERASED_ATTRIBUTES, CONVERT_OPTION
FUNC_TO_DICT = ['valid_not_equal'] FUNC_TO_DICT = ['valid_not_equal']
@ -12,32 +12,6 @@ FORCE_INFORMATIONS = ['help', 'test', 'separator', 'manage']
ATTRIBUTES_ORDER = ('name', 'doc', 'default', 'multi') 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: class TiramisuReflector:
def __init__(self, def __init__(self,
xmlroot, xmlroot,
@ -344,6 +318,8 @@ class Variable(Common):
value = value.split(',') value = value.split(',')
if self.object_type == 'IntOption': if self.object_type == 'IntOption':
value = [int(v) for v in value] value = [int(v) for v in value]
elif self.object_type == 'FloatOption':
value = [float(v) for v in value]
self.informations[key] = value self.informations[key] = value
else: else:
self.attrib[key] = value self.attrib[key] = value
@ -397,7 +373,7 @@ class Variable(Common):
function = child.name function = child.name
if hasattr(child, 'param'): if hasattr(child, 'param'):
for param in child.param: for param in child.param:
value = self.populate_param(param) value = self.populate_param(function, param)
if not hasattr(param, 'name'): if not hasattr(param, 'name'):
args.append(str(value)) args.append(str(value))
else: else:
@ -411,6 +387,7 @@ class Variable(Common):
return ret + ')' return ret + ')'
def populate_param(self, def populate_param(self,
function: str,
param, param,
): ):
if param.type == 'string': if param.type == 'string':
@ -420,7 +397,7 @@ class Variable(Common):
elif param.type == 'variable': elif param.type == 'variable':
value = {'option': param.text, value = {'option': param.text,
'notraisepropertyerror': param.notraisepropertyerror, 'notraisepropertyerror': param.notraisepropertyerror,
'todict': param.text in FUNC_TO_DICT, 'todict': function in FUNC_TO_DICT,
} }
if hasattr(param, 'suffix'): if hasattr(param, 'suffix'):
value['suffix'] = param.suffix value['suffix'] = param.suffix
@ -443,7 +420,7 @@ class Variable(Common):
self.attrib['default'].append(value) self.attrib['default'].append(value)
if not self.is_leader: if not self.is_leader:
self.attrib['default_multi'] = value self.attrib['default_multi'] = value
elif isinstance(value, int): elif isinstance(value, (int, float)):
self.attrib['default'].append(value) self.attrib['default'].append(value)
else: else:
self.attrib['default'].append("'" + value + "'") self.attrib['default'].append("'" + value + "'")

View File

@ -37,7 +37,7 @@ class XMLReflector(object):
# 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 DictConsistencyError(_("not a valid xml file: {}").format(xmlfile)) raise DictConsistencyError(_(f'"{xmlfile}" not a valid xml file: {self.dtd.error_log.filter_from_errors()[0]}'))
return document.getroot() return document.getroot()
def load_xml_from_folders(self, xmlfolders): def load_xml_from_folders(self, xmlfolders):

View File

@ -0,0 +1,20 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services>
<service name="test">
<file name="/etc/systemd-makefs@dev-disk-by\\x2dpartlabel"/>
</service>
</services>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="Description">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.group": "root", "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.mode": "0644", "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.name": "/etc/systemd-makefs@dev-disk-by\\x2dpartlabel", "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.owner": "root", "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.source": "systemd-makefs@dev-disk-by\\x2dpartlabel", "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.templating": true, "services.test.files.systemd_makefs@dev_disk_by\\x2dpartlabel.activate": true}

View File

@ -0,0 +1,26 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='Description', multi=False, default='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_8 = StrOption(name='group', doc='group', multi=False, default='root')
option_9 = StrOption(name='mode', doc='mode', multi=False, default='0644')
option_10 = StrOption(name='name', doc='name', multi=False, default='/etc/systemd-makefs@dev-disk-by\\x2dpartlabel')
option_11 = StrOption(name='owner', doc='owner', multi=False, default='root')
option_12 = StrOption(name='source', doc='source', multi=False, default='systemd-makefs@dev-disk-by\\x2dpartlabel')
option_13 = BoolOption(name='templating', doc='templating', multi=False, default=True)
option_14 = BoolOption(name='activate', doc='activate', multi=False, default=True)
option_7 = OptionDescription(name='systemd_makefs@dev_disk_by\\x2dpartlabel', doc='systemd-makefs@dev-disk-by\\x2dpartlabel', children=[option_8, option_9, option_10, option_11, option_12, option_13, option_14])
option_6 = OptionDescription(name='files', doc='files', children=[option_7])
option_5 = OptionDescription(name='test', doc='test', children=[option_6])
option_5.impl_set_information("manage", True)
option_4 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_5])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_4])

View File

@ -0,0 +1 @@
%%mode_conteneur_actif

View File

@ -0,0 +1,16 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="float" type="float" description="Description">
<value>0.527</value>
</variable>
<variable name="float_multi" type="float" description="Description" multi="True">
<value>0.527</value>
</variable>
</family>
<separators/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

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

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = FloatOption(properties=frozenset({'mandatory', 'normal'}), name='float', doc='Description', multi=False, default=0.527)
option_4 = FloatOption(properties=frozenset({'mandatory', 'normal'}), name='float_multi', doc='Description', multi=True, default=[0.527], default_multi=0.527)
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])

View File

@ -0,0 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="general" type="oui/non" description="description">
<value>non</value>
</variable>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.general": "non"}

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='general', doc='description', multi=False, default='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])

View File

@ -10,7 +10,7 @@ except:
from rougail.tiramisu import ConvertDynOptionDescription from rougail.tiramisu import ConvertDynOptionDescription
option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='b') option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='b')
option_5 = IntOption(properties=frozenset({'normal'}), name='int2', doc='No change', multi=False) option_5 = IntOption(properties=frozenset({'normal'}), name='int2', doc='No change', multi=False)
option_4 = IntOption(properties=frozenset({'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='int', doc='No change', multi=False) option_4 = IntOption(properties=frozenset({'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='int', doc='No change', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5]) option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2]) option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1]) option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -9,7 +9,7 @@ except:
from tiramisu import * from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', 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({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non')) option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4]) 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_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1]) option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -11,7 +11,7 @@ from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non')) option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', 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_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non')) option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui') option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6]) option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2]) option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1]) option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -11,7 +11,7 @@ from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non')) option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', 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_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non')) option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui') option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6]) option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2]) option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1]) option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,29 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="No change">
<value>oui</value>
</variable>
<variable name="adresse_ip_eth0" type="local_ip" description="Adresse IP de la carte" mandatory="True" mode="basic"/>
<variable name="adresse_netmask_eth0" type="netmask" description="Masque de sous réseau de la carte" mandatory="True" mode="basic"/>
<variable name="adresse_ip" type="local_ip" description="IP" mandatory="True" mode="basic"/>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_in_network" target="adresse_ip" level="warning">
<param type="variable">adresse_ip_eth0</param>
<param type="variable">adresse_netmask_eth0</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.adresse_ip_eth0": null, "rougail.general.adresse_netmask_eth0": null, "rougail.general.adresse_ip": null}

View File

@ -0,0 +1,17 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), name='adresse_ip_eth0', doc='Adresse IP de la carte', multi=False)
option_5 = NetmaskOption(properties=frozenset({'basic', 'mandatory'}), name='adresse_netmask_eth0', doc='Masque de sous réseau de la carte', multi=False)
option_6 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), validators=[Calculation(func.valid_in_network, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=True)], name='adresse_ip', doc='IP', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="No change">
<value>oui</value>
</variable>
<variable name="adresse_ip_eth0" type="cidr" description="Adresse IP de la carte" mandatory="True" mode="basic"/>
<variable name="adresse_ip" type="local_ip" description="IP" mandatory="True" mode="basic"/>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_in_network" target="adresse_ip" level="warning">
<param type="variable">adresse_ip_eth0</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.adresse_ip_eth0": null, "rougail.general.adresse_ip": null}

View File

@ -0,0 +1,16 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = IPOption(cidr=True, properties=frozenset({'basic', 'mandatory'}), name='adresse_ip_eth0', doc='Adresse IP de la carte', multi=False)
option_5 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), validators=[Calculation(func.valid_in_network, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=True)], name='adresse_ip', doc='IP', multi=False)
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])

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail>
<variables>
<family name='general'>
<variable name='mode_conteneur_actif' type='oui/non' description="No change">
<value>non</value>
</variable>
</family>
<family name='general1'>
<variable name='leader' type='string' description="leader" multi="True"/>
<variable name='follower1' type='string' description="follower1"/>
<variable name='follower2' type='string' description="follower2"/>
</family>
</variables>
<constraints>
<fill name='calc_val' target='follower1'>
<param name='valeur'>valfill</param>
</fill>
<fill name='calc_val' target='follower2'>
<param type='variable'>follower1</param>
</fill>
<group leader='leader' name="other_name">
<follower>follower1</follower>
<follower>follower2</follower>
</group>
</constraints>
</rougail>

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.other_name.leader": [], "rougail.general1.other_name.follower1": [], "rougail.general1.other_name.follower2": []}

View File

@ -0,0 +1,19 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_6 = StrOption(name='leader', doc='leader', multi=True)
option_7 = StrOption(properties=frozenset({'normal'}), name='follower1', doc='follower1', multi=True, default=Calculation(func.calc_val, Params((), kwargs={'valeur': ParamValue("valfill")})))
option_8 = StrOption(properties=frozenset({'normal'}), name='follower2', doc='follower2', multi=True, default=Calculation(func.calc_val, Params((ParamOption(option_7, notraisepropertyerror=False, todict=False)), kwargs={})))
option_5 = Leadership(name='other_name', doc='leader', properties=frozenset({'normal'}), children=[option_6, option_7, option_8])
option_4 = OptionDescription(name='general1', doc='general1', properties=frozenset({'normal'}), children=[option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2, option_4])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -1,2 +1 @@
{"rougail.proxy_authentifie.toto1": null, "rougail.proxy_authentifie.toto2": "3127"} {"rougail.proxy_authentifie.toto1": null, "rougail.proxy_authentifie.toto2": "3127"}

View File

@ -1,2 +1 @@
{"rougail.proxy_authentifie.toto1": null, "rougail.proxy_authentifie.toto2": "3127"} {"rougail.proxy_authentifie.toto1": null, "rougail.proxy_authentifie.toto2": "3127"}

View File

@ -0,0 +1,25 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="extra">
<variable name="mode_conteneur_actif" type="oui/non" description="No change" hidden="True">
<value>non</value>
</variable>
<variable name="activer_ejabberd" type="oui/non" description="No change" hidden="True">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail>
<variables>
<family name='ejabberd'>
<variable name="description" type="string">
<value>Exportation de la base de ejabberd</value>
</variable>
<variable name="day" type="schedule"></variable>
<variable name="mode" type="schedulemod">
<value>pre</value>
</variable>
</family>
</variables>
<constraints>
<fill name='calc_multi_condition' target='extra.ejabberd.day'>
<param>non</param>
<param type='variable' name='condition_1' notraisepropertyerror='True'>activer_ejabberd</param>
<param name='match'>none</param>
<param name='mismatch'>daily</param>
</fill>
</constraints>
</rougail>

View File

@ -0,0 +1 @@
{"rougail.extra.mode_conteneur_actif": "non", "rougail.extra.activer_ejabberd": "non", "extra.ejabberd.description": "Exportation de la base de ejabberd", "extra.ejabberd.day": null, "extra.ejabberd.mode": "pre"}

View File

@ -0,0 +1,20 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
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='activer_ejabberd', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='extra', doc='extra', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_7 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='description', doc='description', multi=False, default='Exportation de la base de ejabberd')
option_8 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='day', doc='day', multi=False, default=Calculation(func.calc_multi_condition, Params((ParamValue("non")), kwargs={'condition_1': ParamOption(option_4, notraisepropertyerror=True, todict=False), 'match': ParamValue("none"), 'mismatch': ParamValue("daily")})), values=('none', 'daily', 'weekly', 'monthly'))
option_9 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode', doc='mode', multi=False, default='pre', values=('pre', 'post'))
option_6 = OptionDescription(name='ejabberd', doc='ejabberd', properties=frozenset({'normal'}), children=[option_7, option_8, option_9])
option_5 = OptionDescription(name='extra', doc='extra', children=[option_6])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_5])

View File

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
<variable name="int" type="number" description="No change"/>
</family>
<separators/>
</variables>
<constraints>
<check name="unknown" target="int">
<param name="mini">0</param>
<param name="maxi">100</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="string" description="No change">
<value>b</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
<check name="valid_differ" target="mode_conteneur_actif">
<param type="variable">int3</param>
</check>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1,10 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="unknown" description="Description"/>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -1,4 +1,4 @@
from tiramisu import valid_not_equal, valid_ip_netmask, calc_value from tiramisu import valid_not_equal, valid_ip_netmask, calc_value, valid_in_network
def calc_val(*args, **kwargs): def calc_val(*args, **kwargs):
if len(args) > 0: if len(args) > 0:

View File

@ -17,6 +17,8 @@ for test in listdir(dico_dirs):
if isdir(join(dico_dirs, test, 'tiramisu')): if isdir(join(dico_dirs, test, 'tiramisu')):
test_ok.add(test) test_ok.add(test)
debug = False
#debug = True
excludes = set([]) excludes = set([])
#excludes = set(['70container_services']) #excludes = set(['70container_services'])
test_ok -= excludes test_ok -= excludes
@ -33,8 +35,6 @@ def test_dir(request):
async def launch_flattener(test_dir): async def launch_flattener(test_dir):
debug = False
#debug = True
makedict_dir = join(test_dir, 'makedict') makedict_dir = join(test_dir, 'makedict')
makedict_file = join(makedict_dir, 'base.json') makedict_file = join(makedict_dir, 'base.json')