Compare commits

..

42 Commits

Author SHA1 Message Date
7eb78e5346 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-21 08:11:39 +01:00
d18906e011 better debug 2020-11-21 08:11:34 +01:00
11553e6f09 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-20 18:02:55 +01:00
62bccfc352 set good path in include file and patch file 2020-11-20 18:02:40 +01:00
0722e76fcc Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-18 22:18:54 +01:00
7db3e2c2a9 allow filename with \ 2020-11-18 22:18:16 +01:00
adaafde2e5 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-15 11:22:19 +01:00
3ad1bf0604 valid_not_equal must be launch with 'todict' argument 2020-11-15 11:22:09 +01:00
19d9fdc705 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-15 11:02:10 +01:00
d5129d6fe7 add float support 2020-11-15 11:02:04 +01:00
11294fdd61 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-14 17:21:05 +01:00
6bda645903 leadership name 2020-11-14 17:20:55 +01:00
4351662f2e Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-14 08:02:45 +01:00
a835e5a017 valid_in_network should works with CIDR 2020-11-14 08:02:38 +01:00
5a45885ed8 family and var with same name 2020-11-11 16:59:44 +01:00
3d49f2fe8c add xmlfiles in various error message 2020-11-11 16:24:06 +01:00
5bf8d69e91 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-08 18:06:45 +01:00
f7db6b0289 add remove_fill attribute 2020-11-08 09:51:33 +01:00
8f01d2c1d8 can add personal function (tests file) 2020-11-08 09:43:45 +01:00
a9c74d68ff Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-10-14 18:17:45 +02:00
4b21b1507f can add personal function 2020-10-14 18:17:31 +02:00
43e30bba47 support empty param 2020-10-04 20:11:00 +02:00
3040a11de9 cherry-pick 2020-10-04 17:34:48 +02:00
8cb27a79d6 doc 2020-10-04 17:28:07 +02:00
101dfefaa9 dynamic variable and calculation 2020-10-04 17:27:55 +02:00
5eba872969 add OptionInformation support 2020-10-04 17:25:42 +02:00
246ac25791 refactor valid_enum 2020-10-04 17:23:55 +02:00
48d190d39b update dependencies 2020-08-12 12:22:19 +02:00
f474edd8ae rougail => python3-rougail 2020-08-12 11:14:02 +02:00
61fc9b15e5 ajout de la dependance vers cheetah 2020-08-12 08:41:54 +02:00
79312cc8c8 Merge branch 'develop' into dist/risotto/risotto-2.7.1/develop 2020-08-12 08:37:12 +02:00
d789787d5c change Config object 2020-08-12 08:23:38 +02:00
d3670c6476 try tiramisu3 before tiramisu 2020-08-08 11:03:06 +02:00
4eb42e4290 merge flattener_dico and templates in tests 2020-08-08 08:58:35 +02:00
0da8b868ac Merge branch 'develop' into dist/risotto/risotto-2.7.1/develop 2020-08-07 17:18:01 +02:00
f07f76a4ef import de tiramisu ou tiramisu3 2020-08-07 17:17:42 +02:00
cdc4013450 extra dependencies 2020-08-05 12:17:37 +02:00
a2e8b5dad4 Merge branch 'develop' into dist/risotto/risotto-2.7.1/develop 2020-08-05 10:33:54 +02:00
f65e772b39 Merge branch 'master' into develop 2020-08-05 10:31:37 +02:00
58b3880e9b Delete changelog 2020-07-29 09:56:15 +02:00
413ab6dbb0 Add debian folder in packaging branch 2020-07-29 09:55:51 +02:00
534b5f4413 Do not include debian folder in code branch 2020-07-29 09:54:48 +02:00
1207 changed files with 3865 additions and 3031 deletions

5
debian/changelog vendored
View File

@ -1,5 +0,0 @@
rougail (0.1) unstable; urgency=low
* first version
-- Cadoles <contact@cadoles.com> Tue, 31 Mar 2020 10:40:42 +0200

6
debian/control vendored
View File

@ -2,13 +2,13 @@ Source: rougail
Section: admin
Priority: extra
Maintainer: Cadoles <contact@cadoles.com>
Build-depends: debhelper (>=11), python3-all, python3-setuptools
Build-depends: debhelper (>=11), python3-all, python3-setuptools, dh-python
Standards-Version: 3.9.4
Homepage: https://forge.cadoles.com/Infra/rougail
Package: rougail
Package: python3-rougail
Architecture: any
Pre-Depends: dpkg, python3, ${misc:Pre-Depends}
Depends: ${python:Depends}, ${misc:Depends}
Depends: ${python:Depends}, ${misc:Depends}, python3-cheetah, python3-tiramisu3
Description: configuration manager

View File

@ -159,6 +159,14 @@ Un paramètre de type "variable" peut être "optional" :
Dans ce cas la fonction "return_value" est exécuté sans paramètre.
Paramètre avec variable potentiellement désactivée
--------------------------------------------------
FIXME :
<!ATTLIST param notraisepropertyerror (True|False) "False">
Il n'y a pas spécialement de test !
Les variables suiveuses
-----------------------

View File

@ -34,11 +34,38 @@ def 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
# that shall not be present in the exported (flatened) XML
ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace',
'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership',
'level') # , '_real_container')
'level', 'remove_fill', 'xmlfiles')
ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group')
FORCE_CHOICE = {'oui/non': ['oui', 'non'],
@ -56,8 +83,6 @@ KEY_TYPE = {'variable': 'symlink',
'URLOption': 'web_address',
'FilenameOption': 'filename'}
CONVERSION = {'number': int}
FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze',
@ -108,7 +133,7 @@ class GroupAnnotator:
self.manage_follower(namespace,
leader_family_name,
variable,
leader_name,
leadership_name,
follower_names,
leader_space,
leader_is_hidden,
@ -125,9 +150,14 @@ class GroupAnnotator:
# if variable.hidden:
# leader_is_hidden = True
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_family_name,
leadership_name,
leader_name,
namespace,
variable,
@ -142,6 +172,7 @@ class GroupAnnotator:
def manage_leader(self,
leader_space: 'Leadership',
leader_family_name: str,
leadership_name: str,
leader_name: str,
namespace: str,
variable: 'Variable',
@ -152,7 +183,7 @@ class GroupAnnotator:
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.name = leadership_name
leader_space.hidden = variable.hidden
if variable.hidden:
leader_is_hidden = True
@ -167,9 +198,9 @@ class GroupAnnotator:
leader_space.doc = variable.description
else:
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,
leader_path,
leadership_path,
leader_space,
)
leader_family = self.objectspace.space.variables[namespace].family[leader_family_name]
@ -233,7 +264,7 @@ class ServiceAnnotator:
families = {}
for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
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():
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
setattr(new_service, elttype, values)
@ -242,6 +273,7 @@ class ServiceAnnotator:
path = '.'.join(['services', service_name, eltname])
family = self.gen_family(eltname,
path,
service.xmlfiles,
)
if isinstance(values, dict):
values = list(values.values())
@ -258,8 +290,9 @@ class ServiceAnnotator:
def gen_family(self,
name,
path,
xmlfiles
):
family = self.objectspace.family()
family = self.objectspace.family(xmlfiles)
family.name = normalize_family(name)
family.doc = name
family.mode = None
@ -307,7 +340,10 @@ class ServiceAnnotator:
if not self.objectspace.paths.family_is_defined(subpath):
break
idx += 1
family = self.gen_family(c_name, subpath)
family = self.gen_family(c_name,
subpath,
elt.xmlfiles,
)
family.variable = []
listname = '{}list'.format(name)
activate_path = '.'.join([subpath, 'activate'])
@ -345,7 +381,7 @@ class ServiceAnnotator:
elt,
path,
):
variable = self.objectspace.variable()
variable = self.objectspace.variable(elt.xmlfiles)
variable.name = normalize_family(key)
variable.mode = None
if key == 'name':
@ -370,7 +406,7 @@ class ServiceAnnotator:
variable.multi = None
else:
variable.doc = key
val = self.objectspace.value()
val = self.objectspace.value(elt.xmlfiles)
val.type = type_
val.name = value
variable.value = [val]
@ -454,7 +490,7 @@ class VariableAnnotator:
for value in variable.value:
if not hasattr(value, '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():
setattr(variable, value, getattr(variable, key))
setattr(variable, key, None)
@ -469,23 +505,28 @@ class VariableAnnotator:
path,
):
if variable.type in FORCE_CHOICE:
check = self.objectspace.check()
check = self.objectspace.check(variable.xmlfiles)
check.name = 'valid_enum'
check.target = path
check.namespace = namespace
check.param = []
for value in FORCE_CHOICE[variable.type]:
param = self.objectspace.param()
param = self.objectspace.param(variable.xmlfiles)
param.text = value
check.param.append(param)
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
if not hasattr(self.objectspace.space.constraints, 'check'):
self.objectspace.space.constraints.check = []
self.objectspace.space.constraints.check.append(check)
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'):
return
for families in self.objectspace.space.variables.values():
@ -515,6 +556,7 @@ class VariableAnnotator:
follower,
path,
)
_valid_type(follower)
else:
path = '{}.{}.{}'.format(namespace, normalize_family(family.name), variable.name)
_convert_variable(variable,
@ -524,6 +566,7 @@ class VariableAnnotator:
variable,
path,
)
_valid_type(variable)
def convert_helps(self):
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(variable, namespace):
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.namespace = namespace
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param = self.objectspace.param()
new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = 'oui'
new_condition.param = [new_param]
new_target = self.objectspace.target()
new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = 'variable'
path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name
new_target.name = path
@ -583,7 +626,8 @@ class VariableAnnotator:
subpath = self.objectspace.paths.get_variable_path(separator.name,
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
del family.separators
@ -596,7 +640,9 @@ class ConstraintAnnotator:
if not hasattr(objectspace.space, 'constraints'):
return
self.objectspace = objectspace
self.eosfunc = imp.load_source('eosfunc', eosfunc_file)
eosfunc = imp.load_source('eosfunc', eosfunc_file)
self.functions = dir(eosfunc)
self.functions.extend(INTERNAL_FUNCTIONS)
self.valid_enums = {}
if hasattr(self.objectspace.space.constraints, 'check'):
self.check_check()
@ -618,11 +664,10 @@ class ConstraintAnnotator:
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 not check.name in self.functions:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'))
if hasattr(check, 'param'):
param_option_indexes = []
for idx, param in enumerate(check.param):
@ -630,7 +675,8 @@ class ConstraintAnnotator:
if param.optional is True:
param_option_indexes.append(idx)
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':
param.notraisepropertyerror = None
param_option_indexes = list(set(param_option_indexes))
@ -766,7 +812,7 @@ class ConstraintAnnotator:
for listvar in listvars:
variable = self.objectspace.paths.get_variable_obj(listvar)
type_ = 'variable'
new_target = self.objectspace.target()
new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = type_
new_target.name = listvar
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:
continue
for idx, action in enumerate(actions):
prop = self.objectspace.property_()
prop = self.objectspace.property_(leader_or_variable.xmlfiles)
prop.type = 'calculation'
prop.inverse = inverse
prop.source = condition.source
@ -924,10 +970,10 @@ class ConstraintAnnotator:
}
choices = []
for value in values:
choice = self.objectspace.choice()
choice = self.objectspace.choice(variable.xmlfiles)
try:
if value is not None:
choice.name = CONVERSION.get(type_, str)(value)
choice.name = CONVERT_OPTION[type_].get('func', str)(value)
else:
choice.name = value
except:
@ -942,13 +988,13 @@ class ConstraintAnnotator:
for value in variable.value:
value.type = type_
try:
cvalue = CONVERSION.get(type_, str)(value.name)
cvalue = CONVERT_OPTION[type_].get('func', 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 = self.objectspace.value(variable.xmlfiles)
new_value.name = choices[0]
new_value.type = type_
variable.value = [new_value]
@ -973,26 +1019,30 @@ class ConstraintAnnotator:
else:
raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'))
else:
check_ = self.objectspace.check()
check_ = self.objectspace.check(variable.xmlfiles)
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))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_ipnetmask':
params_len = 1
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'
elif name == 'valid_broadcast':
params_len = 2
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':
if len(check.param) not in (1, 2):
params_len = 2
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}'))
check_.name = name
check_.warnings_only = check.warnings_only
if hasattr(check, 'param'):
@ -1008,7 +1058,6 @@ class ConstraintAnnotator:
indexes = list(fills.keys())
indexes.sort()
targets = []
eosfunc = dir(self.eosfunc)
for idx in indexes:
fill = fills[idx]
# test if it's redefined calculation
@ -1016,7 +1065,7 @@ class ConstraintAnnotator:
raise DictConsistencyError(_(f"A fill already exists for the target: {fill.target}"))
targets.append(fill.target)
#
if fill.name not in eosfunc:
if fill.name not in self.functions:
raise DictConsistencyError(_('cannot find fill function {}').format(fill.name))
namespace = fill.namespace
@ -1027,7 +1076,8 @@ class ConstraintAnnotator:
)
if suffix is not None:
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.name = fill.name
if hasattr(fill, 'param'):
@ -1037,6 +1087,9 @@ class ConstraintAnnotator:
raise DictConsistencyError(_(f"All '{param.type}' variables must have a value in order to calculate {fill.target}"))
if param.type == 'suffix' and hasattr(param, 'text'):
raise DictConsistencyError(_(f"All '{param.type}' variables must not have a value in order to calculate {fill.target}"))
if param.type == 'string':
if not hasattr(param, 'text'):
param.text = None
if param.type == 'variable':
try:
param.text, suffix = self.objectspace.paths.get_variable_path(param.text,
@ -1056,7 +1109,6 @@ class ConstraintAnnotator:
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
@ -1064,6 +1116,7 @@ class ConstraintAnnotator:
if hasattr(self.objectspace.space.constraints, 'index'):
del self.objectspace.space.constraints.index
del self.objectspace.space.constraints.namespace
del self.objectspace.space.constraints.xmlfiles
if vars(self.objectspace.space.constraints):
raise Exception('constraints again?')
del self.objectspace.space.constraints
@ -1124,7 +1177,7 @@ class FamilyAnnotator:
# if the variable is mandatory and doesn't have any value
# then the variable's mode is set to 'basic'
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.type = 'boolean'
variable.value = [new_value]

View File

@ -3,17 +3,20 @@
fichier de configuration pour rougail
"""
from os.path import join, isfile, abspath, dirname
from pathlib import Path
from os.path import join, abspath, dirname
rougailroot = '/var/rougail'
patch_dir = join(rougailroot, 'patches')
manifests_dir = join(rougailroot, 'manifests')
templates_dir = join(rougailroot, 'templates')
dtddir = join(dirname(abspath(__file__)), 'data')
dtdfilename = join(dtddir, 'rougail.dtd')
Config = {'rougailroot': rougailroot,
'patch_dir': join(rougailroot, 'patches'),
'manifests_dir': join(rougailroot, 'manifests'),
'templates_dir': join(rougailroot, 'templates'),
'dtdfilename': join(dtddir, 'rougail.dtd'),
'dtddir': dtddir,
# chemin du répertoire source des fichiers templates
patch_dir = '/srv/rougail/patch'
variable_namespace = 'rougail'
'patch_dir': '/srv/rougail/patch',
'variable_namespace': 'rougail',
}

View File

@ -45,7 +45,7 @@
<!ELEMENT services (service*)>
<!ELEMENT service ((port* | tcpwrapper* | ip* | interface* | package* | file* | digitalcertificate* | override*)*) >
<!ELEMENT service ((port* | tcpwrapper* | ip* | interface* | package* | file* | override*)*) >
<!ATTLIST service name CDATA #REQUIRED>
<!ATTLIST service manage (True|False) "True">
@ -75,14 +75,6 @@
<!ATTLIST file redefine (True|False) "False">
<!ATTLIST file templating (True|False) "True">
<!ELEMENT digitalcertificate EMPTY>
<!ATTLIST digitalcertificate name CDATA #REQUIRED >
<!ATTLIST digitalcertificate digitalcertificate_type (variable) "variable">
<!ATTLIST digitalcertificate certificate CDATA #REQUIRED >
<!ATTLIST digitalcertificate certificate_type (variable) "variable">
<!ATTLIST digitalcertificate type CDATA #REQUIRED >
<!ATTLIST digitalcertificate ca CDATA #REQUIRED >
<!ELEMENT override EMPTY>
<!ATTLIST override source CDATA #IMPLIED >
<!ATTLIST override templating (True|False) "True">
@ -110,6 +102,7 @@
<!ATTLIST variable mode (basic|normal|expert) "normal">
<!ATTLIST variable remove_check (True|False) "False">
<!ATTLIST variable remove_condition (True|False) "False">
<!ATTLIST variable remove_fill (True|False) "False">
<!ATTLIST variable test CDATA #IMPLIED>
<!ELEMENT separators (separator*)>
@ -138,6 +131,7 @@
<!ELEMENT group (follower+)>
<!ATTLIST group leader CDATA #REQUIRED>
<!ATTLIST group name CDATA #IMPLIED>
<!ATTLIST group description CDATA #IMPLIED>
<!ELEMENT param (#PCDATA)>

View File

@ -32,7 +32,7 @@ from .tiramisureflector import TiramisuReflector
from .utils import normalize_family
from .error import OperationError, SpaceObjShallNotBeUpdated, DictConsistencyError
from .path import Path
from .config import variable_namespace
from .config import Config
# CreoleObjSpace's elements like 'family' or 'follower', that shall be forced to the Redefinable type
FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables')
@ -59,7 +59,10 @@ CONVERT_EXPORT = {'Leadership': 'leader',
# _____________________________________________________________________________
# special types definitions for the Object Space's internal representation
class RootCreoleObject:
""
def __init__(self, xmlfiles):
if not isinstance(xmlfiles, list):
xmlfiles = [xmlfiles]
self.xmlfiles = xmlfiles
class CreoleObjSpace:
@ -92,6 +95,7 @@ class CreoleObjSpace:
self.xmlreflector = XMLReflector()
self.xmlreflector.parse_dtd(dtdfilename)
self.redefine_variables = None
self.fill_removed = None
self.check_removed = None
self.condition_removed = None
@ -153,14 +157,17 @@ class CreoleObjSpace:
"""
for xmlfile, document in self.xmlreflector.load_xml_from_folders(xmlfolders):
self.redefine_variables = []
self.fill_removed = []
self.check_removed = []
self.condition_removed = []
self.xml_parse_document(document,
self.xml_parse_document(xmlfile,
document,
self.space,
namespace,
)
def xml_parse_document(self,
xmlfile,
document,
space,
namespace,
@ -177,7 +184,7 @@ class CreoleObjSpace:
continue
if child.tag == 'family':
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'])
if child.tag == 'variables':
child.attrib['name'] = namespace
@ -186,7 +193,8 @@ class CreoleObjSpace:
continue
# variable objects creation
try:
variableobj = self.generate_variableobj(child,
variableobj = self.generate_variableobj(xmlfile,
child,
space,
namespace,
)
@ -195,7 +203,8 @@ class CreoleObjSpace:
self.set_text_to_obj(child,
variableobj,
)
self.set_xml_attributes_to_obj(child,
self.set_xml_attributes_to_obj(xmlfile,
child,
variableobj,
)
self.variableobj_tree_visitor(child,
@ -213,12 +222,14 @@ class CreoleObjSpace:
child,
)
if list(child) != []:
self.xml_parse_document(child,
self.xml_parse_document(xmlfile,
child,
variableobj,
namespace,
)
def generate_variableobj(self,
xmlfile,
child,
space,
namespace,
@ -226,9 +237,10 @@ class CreoleObjSpace:
"""
instanciates or creates Creole Object Subspace objects
"""
variableobj = getattr(self, child.tag)()
variableobj = getattr(self, child.tag)(xmlfile)
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,
child,
namespace,
@ -246,6 +258,7 @@ class CreoleObjSpace:
return variableobj
def create_or_update_redefinable_object(self,
xmlfile,
subspace,
space,
child,
@ -279,15 +292,17 @@ class CreoleObjSpace:
name = child.text
else:
name = subspace['name']
if self.is_already_exists(name,
existed_var = self.is_already_exists(name,
space,
child,
namespace,
):
)
if existed_var:
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:
existed_var.xmlfiles.append(xmlfile)
return self.translate_in_space(name,
space,
child,
@ -295,12 +310,21 @@ class CreoleObjSpace:
)
elif exists is False:
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))
exists = self.convert_boolean(subspace.get('exists', False))
if redefine is False or exists is True:
return getattr(self, child.tag)()
raise DictConsistencyError(_(f'Redefined object: {name} does not exist yet'))
return getattr(self, child.tag)(xmlfile)
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,
space,
@ -327,16 +351,25 @@ class CreoleObjSpace:
raise OperationError(_("Creole object {} "
"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 namespace != variable_namespace:
if namespace != Config['variable_namespace']:
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':
norm_name = normalize_family(name)
else:
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
"""Boolean coercion. The Creole XML may contain srings like `True` or `False`
@ -362,14 +395,14 @@ class CreoleObjSpace:
else:
norm_name = name
return getattr(family, variable.tag)[norm_name]
if namespace == variable_namespace:
if namespace == Config['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
old_family = self.space.variables[Config['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):
@ -383,6 +416,18 @@ class CreoleObjSpace:
)
return variable_obj
def remove_fill(self, name): # pylint: disable=C0111
if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'fill'):
remove_fills= []
for idx, fill in enumerate(self.space.constraints.fill): # pylint: disable=E1101
if hasattr(fill, 'target') and fill.target == name:
remove_fills.append(idx)
remove_fills = list(set(remove_fills))
remove_fills.sort(reverse=True)
for idx in remove_fills:
self.space.constraints.fill.pop(idx) # pylint: disable=E1101
def remove_check(self, name): # pylint: disable=C0111
if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'check'):
remove_checks = []
@ -437,6 +482,7 @@ class CreoleObjSpace:
variableobj.text = text
def set_xml_attributes_to_obj(self,
xmlfile,
child,
variableobj,
):
@ -449,7 +495,8 @@ class CreoleObjSpace:
# UNREDEFINABLE concerns only 'variable' node so we can fix name
# to 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:
val = self.convert_boolean(val)
if not (attr == 'name' and getattr(variableobj, 'name', None) != None):
@ -468,16 +515,21 @@ class CreoleObjSpace:
self.remove_check(variableobj.name)
if child.attrib.get('remove_condition', False):
self.remove_condition(variableobj.name)
if child.attrib.get('remove_fill', False):
self.remove_fill(variableobj.name)
if child.tag == 'fill':
# if variable is a redefine in current dictionary
# XXX not working with variable not in variable and in leader/followers
variableobj.redefine = child.attrib['target'] in self.redefine_variables
if child.attrib['target'] in self.redefine_variables and child.attrib['target'] not in self.fill_removed:
self.remove_fill(child.attrib['target'])
self.fill_removed.append(child.attrib['target'])
if not hasattr(variableobj, 'index'):
variableobj.index = self.index
if child.tag == 'check' and child.attrib['target'] in self.redefine_variables and child.attrib['target'] not in self.check_removed:
self.remove_check(child.attrib['target'])
self.check_removed.append(child.attrib['target'])
if child.tag == 'condition' and child.attrib['source'] in self.redefine_variables and child.attrib['source'] not in self.check_removed:
if child.tag == 'condition' and child.attrib['source'] in self.redefine_variables and child.attrib['source'] not in self.condition_removed:
self.remove_condition(child.attrib['source'])
self.condition_removed.append(child.attrib['source'])
variableobj.namespace = namespace
@ -501,7 +553,7 @@ class CreoleObjSpace:
document.attrib.get('dynamic') != None,
variableobj)
if child.attrib.get('redefine', 'False') == 'True':
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
self.redefine_variables.append(child.attrib['name'])
else:
self.redefine_variables.append(namespace + '.' + family_name + '.' +
@ -509,7 +561,7 @@ class CreoleObjSpace:
elif child.tag == 'family':
family_name = normalize_family(child.attrib['name'])
if namespace != variable_namespace:
if namespace != Config['variable_namespace']:
family_name = namespace + '.' + family_name
self.paths.add_family(namespace,
family_name,

View File

@ -1,7 +1,7 @@
from .i18n import _
from .utils import normalize_family
from .error import OperationError, DictConsistencyError
from .config import variable_namespace
from .config import Config
class Path:
@ -13,7 +13,8 @@ class Path:
def __init__(self):
self.variables = {}
self.families = {}
self.full_paths = {}
self.full_paths_families = {}
self.full_paths_variables = {}
# Family
def add_family(self,
@ -21,9 +22,9 @@ class Path:
name: str,
variableobj: str,
) -> str: # pylint: disable=C0111
if '.' not in name and namespace == variable_namespace:
if '.' not in name and namespace == Config['variable_namespace']:
full_name = '.'.join([namespace, name])
self.full_paths[name] = full_name
self.full_paths_families[name] = full_name
else:
full_name = name
if full_name in self.families and self.families[full_name]['variableobj'] != variableobj:
@ -41,12 +42,12 @@ class Path:
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 '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths_families:
name = self.full_paths_families[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']:
if dico['namespace'] != Config['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))
@ -55,8 +56,8 @@ class Path:
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 '.' not in name and name in self.full_paths_families:
name = self.full_paths_families[name]
if name not in self.families:
raise DictConsistencyError(_('unknown family {}').format(name))
dico = self.families[name]
@ -65,7 +66,7 @@ class Path:
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:
if '.' not in name and name not in self.families and name in self.full_paths_families:
return True
return name in self.families
@ -87,8 +88,8 @@ class Path:
False,
dico['variableobj'],
)
if namespace == variable_namespace:
self.full_paths[name] = new_path
if namespace == Config['variable_namespace']:
self.full_paths_variables[name] = new_path
else:
name = new_path
dico = self._get_variable(name)
@ -110,10 +111,10 @@ class Path:
) -> str: # pylint: disable=C0111
if '.' not in name:
full_name = '.'.join([namespace, family, name])
self.full_paths[name] = full_name
self.full_paths_variables[name] = full_name
else:
full_name = name
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
name = name.rsplit('.', 1)[1]
self.variables[full_name] = dict(name=name,
family=family,
@ -157,7 +158,7 @@ class Path:
else:
dico = self._get_variable(name)
if not allow_source:
if dico['namespace'] not in [variable_namespace, 'services'] and current_namespace != dico['namespace']:
if dico['namespace'] not in [Config['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))
@ -176,7 +177,7 @@ class Path:
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:
if '.' not in name and name not in self.variables and name in self.full_paths_variables:
return True
return name in self.variables
@ -186,8 +187,8 @@ class Path:
) -> 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 '.' not in name and name in self.full_paths_variables:
name = self.full_paths_variables[name]
if name not in self.variables:
for var_name, variable in self.variables.items():
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')
return variable, name[len(var_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):
variable = self.variables[self.full_paths[var_name]]
variable = self.variables[self.full_paths_variables[var_name]]
if variable['is_dynamic']:
if not with_suffix:
raise Exception('This option is dynamic, should use "with_suffix" attribute')

View File

@ -9,16 +9,20 @@ from shutil import copy
import logging
from typing import Dict, Any
from subprocess import call
from os import listdir, makedirs
from os.path import dirname, join, isfile
from os import listdir, makedirs, getcwd, chdir
from os.path import dirname, join, isfile, abspath, normpath, relpath
from Cheetah.Template import Template as ChtTemplate
from Cheetah.NameMapper import NotFound as CheetahNotFound
try:
from tiramisu3 import Config
from tiramisu3.error import PropertiesOptionError
except:
from tiramisu import Config
from tiramisu.error import PropertiesOptionError
from .config import patch_dir, variable_namespace
from .config import Config
from .error import FileNotFound, TemplateError
from .i18n import _
from .utils import normalize_family
@ -75,7 +79,8 @@ class CheetahTemplate(ChtTemplate):
context,
eosfunc: Dict,
destfilename,
variable):
variable,
):
"""Initialize Creole CheetahTemplate
"""
extra_context = {'is_defined' : IsDefined(context),
@ -88,6 +93,24 @@ class CheetahTemplate(ChtTemplate):
file=filename,
searchList=[context, eosfunc, extra_context])
# FORK of Cheetah fonction, do not replace '\\' by '/'
def serverSidePath(self,
path=None,
normpath=normpath,
abspath=abspath
):
# strange...
if path is None and isinstance(self, str):
path = self
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:
def __init__(self, value, follower=None, index=None):
@ -283,37 +306,43 @@ class CreoleTemplateEngine:
return CreoleExtra(families)
def patch_template(self,
filename: str):
filename: str,
tmp_dir: str,
patch_dir: str,
) -> None:
"""Apply patch to a template
"""
patch_cmd = ['patch', '-d', self.tmp_dir, '-N', '-p1']
patch_cmd = ['patch', '-d', tmp_dir, '-N', '-p1']
patch_no_debug = ['-s', '-r', '-', '--backup-if-mismatch']
# patches variante + locaux
for directory in [join(patch_dir, 'variante'), patch_dir]:
patch_file = join(directory, f'{filename}.patch')
patch_file = join(patch_dir, f'{filename}.patch')
if isfile(patch_file):
log.info(_("Patching template '{filename}' with '{patch_file}'"))
ret = call(patch_cmd + patch_no_debug + ['-i', patch_file])
rel_patch_file = relpath(patch_file, tmp_dir)
ret = call(patch_cmd + patch_no_debug + ['-i', rel_patch_file])
if ret:
patch_cmd_err = ' '.join(patch_cmd + ['-i', patch_file])
log.error(_(f"Error applying patch: '{patch_file}'\nTo reproduce and fix this error {patch_cmd_err}"))
copy(filename, self.tmp_dir)
patch_cmd_err = ' '.join(patch_cmd + ['-i', rel_patch_file])
log.error(_(f"Error applying patch: '{rel_patch_file}'\nTo reproduce and fix this error {patch_cmd_err}"))
copy(join(self.distrib_dir, filename), tmp_dir)
def prepare_template(self,
filename: str):
filename: str,
tmp_dir: str,
patch_dir: str,
) -> None:
"""Prepare template source file
"""
log.info(_("Copy template: '{filename}' -> '{self.tmp_dir}'"))
copy(filename, self.tmp_dir)
self.patch_template(filename)
log.info(_("Copy template: '{filename}' -> '{tmp_dir}'"))
copy(filename, tmp_dir)
self.patch_template(filename, tmp_dir, patch_dir)
def process(self,
source: str,
true_destfilename: str,
destfilename: str,
filevar: Dict,
variable: Any):
variable: Any,
):
"""Process a cheetah template
"""
# full path of the destination file
@ -328,16 +357,19 @@ class CreoleTemplateEngine:
data = str(cheetah_template)
except CheetahNotFound as err:
varname = err.args[0][13:-1]
raise TemplateError(_(f"Error: unknown variable used in template {destfilename} : {varname}"))
raise TemplateError(_(f"Error: unknown variable used in template {source} to {destfilename} : {varname}"))
except Exception as err:
raise TemplateError(_(f"Error while instantiating template {destfilename}: {err}"))
raise TemplateError(_(f"Error while instantiating template {source} to {destfilename}: {err}"))
with open(destfilename, 'w') as file_h:
file_h.write(data)
def instance_file(self,
filevar: Dict,
service_name: str) -> None:
service_name: str,
tmp_dir: str,
dest_dir: str,
) -> None:
"""Run templatisation on one file
"""
log.info(_("Instantiating file '{filename}'"))
@ -351,13 +383,13 @@ class CreoleTemplateEngine:
if variable:
variable = [variable]
for idx, filename in enumerate(filenames):
destfilename = join(self.dest_dir, filename[1:])
destfilename = join(dest_dir, filename[1:])
makedirs(dirname(destfilename), exist_ok=True)
if variable:
var = variable[idx]
else:
var = None
source = join(self.tmp_dir, filevar['source'])
source = join(tmp_dir, filevar['source'])
if filevar['templating']:
self.process(source,
filename,
@ -370,16 +402,21 @@ class CreoleTemplateEngine:
async def instance_files(self) -> None:
"""Run templatisation on all files
"""
ori_dir = getcwd()
tmp_dir = relpath(self.tmp_dir, self.distrib_dir)
dest_dir = relpath(self.dest_dir, self.distrib_dir)
patch_dir = relpath(Config['patch_dir'], self.distrib_dir)
chdir(self.distrib_dir)
for option in await self.config.option.list(type='all'):
namespace = await option.option.name()
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
await self.load_eole_variables_rougail(option)
else:
families = await self.load_eole_variables(namespace,
option)
self.rougail_variables_dict[namespace] = families
for template in listdir(self.distrib_dir):
self.prepare_template(join(self.distrib_dir, template))
for template in listdir('.'):
self.prepare_template(template, tmp_dir, patch_dir)
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'):
@ -387,15 +424,17 @@ class CreoleTemplateEngine:
for fill_obj in await fills.list('all'):
fill = await fill_obj.value.dict()
filename = fill['source']
distib_file = join(self.distrib_dir, filename)
if not isfile(distib_file):
raise FileNotFound(_(f"File {distib_file} does not exist."))
if not isfile(filename):
raise FileNotFound(_(f"File {filename} does not exist."))
if fill.get('activate', False):
self.instance_file(fill,
service_name,
tmp_dir,
dest_dir,
)
else:
log.debug(_("Instantiation of file '{filename}' disabled"))
chdir(ori_dir)
async def generate(config: Config,

View File

@ -1,3 +1,6 @@
try:
from tiramisu3 import DynOptionDescription
except:
from tiramisu import DynOptionDescription
from .utils import normalize_family

View File

@ -1,13 +1,10 @@
"""loader
flattened XML specific
"""
from os.path import isfile
from lxml.etree import DTD
from .config import dtdfilename, variable_namespace
from .config import Config
from .i18n import _
from .error import LoaderError
from .annotator import ERASED_ATTRIBUTES
from .annotator import ERASED_ATTRIBUTES, CONVERT_OPTION
FUNC_TO_DICT = ['valid_not_equal']
@ -15,42 +12,22 @@ 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",
self.storage.text = ["import imp",
f"func = imp.load_source('func', '{funcs_path}')",
"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",
]
self.make_tiramisu_objects(xmlroot)
# parse object
@ -80,10 +57,10 @@ class TiramisuReflector:
# 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]
if Config['variable_namespace'] in xmlroot.variables:
yield xmlroot.variables[Config['variable_namespace']]
for xmlelt, value in xmlroot.variables.items():
if xmlelt != variable_namespace:
if xmlelt != Config['variable_namespace']:
yield value
if hasattr(xmlroot, 'services'):
yield xmlroot.services
@ -341,6 +318,8 @@ class Variable(Common):
value = value.split(',')
if self.object_type == 'IntOption':
value = [int(v) for v in value]
elif self.object_type == 'FloatOption':
value = [float(v) for v in value]
self.informations[key] = value
else:
self.attrib[key] = value
@ -394,7 +373,7 @@ class Variable(Common):
function = child.name
if hasattr(child, 'param'):
for param in child.param:
value = self.populate_param(param)
value = self.populate_param(function, param)
if not hasattr(param, 'name'):
args.append(str(value))
else:
@ -408,6 +387,7 @@ class Variable(Common):
return ret + ')'
def populate_param(self,
function: str,
param,
):
if param.type == 'string':
@ -417,7 +397,7 @@ class Variable(Common):
elif param.type == 'variable':
value = {'option': param.text,
'notraisepropertyerror': param.notraisepropertyerror,
'todict': param.text in FUNC_TO_DICT,
'todict': function in FUNC_TO_DICT,
}
if hasattr(param, 'suffix'):
value['suffix'] = param.suffix
@ -440,7 +420,7 @@ class Variable(Common):
self.attrib['default'].append(value)
if not self.is_leader:
self.attrib['default_multi'] = value
elif isinstance(value, int):
elif isinstance(value, (int, float)):
self.attrib['default'].append(value)
else:
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(xmlfile)
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()
def load_xml_from_folders(self, xmlfolders):

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_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])

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_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])

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_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])

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({'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])

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({'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])

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({'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])

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 = 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])

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({'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])

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 = 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])

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_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])

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 = 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])

View File

@ -0,0 +1,20 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services>
<service name="test">
<file name="/etc/file"/>
</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.file.group": "root", "services.test.files.file.mode": "0644", "services.test.files.file.name": "/etc/file", "services.test.files.file.owner": "root", "services.test.files.file.source": "file", "services.test.files.file.templating": true, "services.test.files.file.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/file')
option_11 = StrOption(name='owner', doc='owner', multi=False, default='root')
option_12 = StrOption(name='source', doc='source', multi=False, default='file')
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='file', doc='file', 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 @@
%include "incfile"

View File

@ -0,0 +1,20 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services>
<service name="test">
<file name="/etc/file"/>
</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.file.group": "root", "services.test.files.file.mode": "0644", "services.test.files.file.name": "/etc/file", "services.test.files.file.owner": "root", "services.test.files.file.source": "file", "services.test.files.file.templating": true, "services.test.files.file.activate": true}

View File

@ -0,0 +1,5 @@
--- tmpl/file 2020-11-20 07:44:38.588472784 +0100
+++ dest/file 2020-11-20 07:44:54.588536011 +0100
@@ -1 +1 @@
-unpatched
+patched

View File

@ -0,0 +1 @@
patched

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/file')
option_11 = StrOption(name='owner', doc='owner', multi=False, default='root')
option_12 = StrOption(name='source', doc='source', multi=False, default='file')
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='file', doc='file', 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 @@
unpatched

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,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({'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])

Some files were not shown because too many files have changed in this diff Show More