dynamic option description and filename with calculation
This commit is contained in:
parent
729b35d372
commit
024fecddbb
14 changed files with 172 additions and 23 deletions
|
@ -149,6 +149,7 @@
|
||||||
|
|
||||||
<!ELEMENT file EMPTY>
|
<!ELEMENT file EMPTY>
|
||||||
<!ATTLIST file name CDATA #REQUIRED >
|
<!ATTLIST file name CDATA #REQUIRED >
|
||||||
|
<!ATTLIST file name_type (UnicodeOption|SymLinkOption) "UnicodeOption">
|
||||||
<!ATTLIST file source CDATA #IMPLIED>
|
<!ATTLIST file source CDATA #IMPLIED>
|
||||||
<!ATTLIST file mode CDATA #IMPLIED >
|
<!ATTLIST file mode CDATA #IMPLIED >
|
||||||
<!ATTLIST file owner CDATA #IMPLIED >
|
<!ATTLIST file owner CDATA #IMPLIED >
|
||||||
|
@ -166,6 +167,7 @@
|
||||||
<!ATTLIST family mode (basic|normal|expert) "basic">
|
<!ATTLIST family mode (basic|normal|expert) "basic">
|
||||||
<!ATTLIST family icon CDATA #IMPLIED>
|
<!ATTLIST family icon CDATA #IMPLIED>
|
||||||
<!ATTLIST family hidden (True|False) "False">
|
<!ATTLIST family hidden (True|False) "False">
|
||||||
|
<!ATTLIST family dynamic CDATA #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT variable (#PCDATA | value)*>
|
<!ELEMENT variable (#PCDATA | value)*>
|
||||||
<!ATTLIST variable name CDATA #REQUIRED>
|
<!ATTLIST variable name CDATA #REQUIRED>
|
||||||
|
|
|
@ -266,8 +266,12 @@ class ContainerAnnotator:
|
||||||
disknod.permission = 'allow'
|
disknod.permission = 'allow'
|
||||||
|
|
||||||
def _update_file(self, file_, index, container_path):
|
def _update_file(self, file_, index, container_path):
|
||||||
if not hasattr(file_, 'source'):
|
if file_.name_type == "UnicodeOption":
|
||||||
file_.source = basename(file_.name)
|
if not hasattr(file_, 'source'):
|
||||||
|
file_.source = basename(file_.name)
|
||||||
|
elif not hasattr(file_, 'source'):
|
||||||
|
raise CreoleDictConsistencyError(_('attribute source mandatory for file with SymLinkOption name '
|
||||||
|
'for {}').format(file_.name))
|
||||||
|
|
||||||
def _split_elts(self, name, key, value, elt):
|
def _split_elts(self, name, key, value, elt):
|
||||||
"""for example::
|
"""for example::
|
||||||
|
@ -483,6 +487,7 @@ class SpaceAnnotator(object):
|
||||||
self.remove_empty_families()
|
self.remove_empty_families()
|
||||||
self.change_variable_mode()
|
self.change_variable_mode()
|
||||||
self.change_family_mode()
|
self.change_family_mode()
|
||||||
|
self.dynamic_families()
|
||||||
self.filter_separators()
|
self.filter_separators()
|
||||||
self.absolute_path_for_symlink_in_containers()
|
self.absolute_path_for_symlink_in_containers()
|
||||||
self.convert_helps()
|
self.convert_helps()
|
||||||
|
@ -611,6 +616,17 @@ class SpaceAnnotator(object):
|
||||||
else:
|
else:
|
||||||
family.mode = mode
|
family.mode = mode
|
||||||
|
|
||||||
|
def dynamic_families(self): # pylint: disable=C0111
|
||||||
|
if not hasattr(self.space, 'variables'):
|
||||||
|
return
|
||||||
|
for family in self.space.variables.values():
|
||||||
|
if hasattr(family, 'family'):
|
||||||
|
for family in family.family.values():
|
||||||
|
if 'dynamic' in vars(family):
|
||||||
|
namespace = self.paths.get_variable_namespace(family.dynamic)
|
||||||
|
varpath = self.paths.get_variable_path(family.dynamic, namespace)
|
||||||
|
family.dynamic = varpath
|
||||||
|
|
||||||
def _annotate_variable(self, variable, family_mode, path, is_follower=False):
|
def _annotate_variable(self, variable, family_mode, path, is_follower=False):
|
||||||
if (HIGH_COMPATIBILITY and variable.type == 'choice' and variable.mode != modes_level[-1] and variable.mandatory is True and path in self.default_has_no_value):
|
if (HIGH_COMPATIBILITY and variable.type == 'choice' and variable.mode != modes_level[-1] and variable.mandatory is True and path in self.default_has_no_value):
|
||||||
variable.mode = modes_level[0]
|
variable.mode = modes_level[0]
|
||||||
|
|
|
@ -6,7 +6,7 @@ from os import listdir
|
||||||
#from ast import literal_eval
|
#from ast import literal_eval
|
||||||
from lxml.etree import parse, DTD
|
from lxml.etree import parse, DTD
|
||||||
|
|
||||||
from tiramisu.option import (StrOption, OptionDescription, PortOption,
|
from tiramisu.option import (StrOption, OptionDescription, DynOptionDescription, PortOption,
|
||||||
IntOption, ChoiceOption, BoolOption, SymLinkOption, IPOption,
|
IntOption, ChoiceOption, BoolOption, SymLinkOption, IPOption,
|
||||||
NetworkOption, NetmaskOption, DomainnameOption, BroadcastOption,
|
NetworkOption, NetmaskOption, DomainnameOption, BroadcastOption,
|
||||||
URLOption, EmailOption, FilenameOption, UsernameOption, DateOption,
|
URLOption, EmailOption, FilenameOption, UsernameOption, DateOption,
|
||||||
|
@ -117,9 +117,9 @@ class PopulateTiramisuObjects(object):
|
||||||
|
|
||||||
def make_tiramisu_objects(self, xmlroot, creolefunc_file):
|
def make_tiramisu_objects(self, xmlroot, creolefunc_file):
|
||||||
elt = Elt({'name': 'baseoption'})
|
elt = Elt({'name': 'baseoption'})
|
||||||
family = Family(elt, self.booleans, self.storage)
|
|
||||||
self.storage.add('.', family)
|
|
||||||
self.eosfunc = imp.load_source('eosfunc', creolefunc_file)
|
self.eosfunc = imp.load_source('eosfunc', creolefunc_file)
|
||||||
|
family = Family(elt, self.booleans, self.storage, self.eosfunc)
|
||||||
|
self.storage.add('.', family)
|
||||||
|
|
||||||
elts = {}
|
elts = {}
|
||||||
for elt in xmlroot:
|
for elt in xmlroot:
|
||||||
|
@ -167,7 +167,7 @@ class PopulateTiramisuObjects(object):
|
||||||
force_icon = False
|
force_icon = False
|
||||||
else:
|
else:
|
||||||
force_icon = not subpath.startswith('containers') and not subpath.startswith('actions')
|
force_icon = not subpath.startswith('containers') and not subpath.startswith('actions')
|
||||||
family = Family(elt, self.booleans, self.storage, force_icon)
|
family = Family(elt, self.booleans, self.storage, self.eosfunc, force_icon)
|
||||||
path = self._build_path(subpath, elt)
|
path = self._build_path(subpath, elt)
|
||||||
self.storage.add(path, family)
|
self.storage.add(path, family)
|
||||||
return family
|
return family
|
||||||
|
@ -181,7 +181,7 @@ class PopulateTiramisuObjects(object):
|
||||||
|
|
||||||
def _iter_leader(self, leader, subpath):
|
def _iter_leader(self, leader, subpath):
|
||||||
subpath = self._build_path(subpath, leader)
|
subpath = self._build_path(subpath, leader)
|
||||||
family = Family(leader, self.booleans, self.storage)
|
family = Family(leader, self.booleans, self.storage, self.eosfunc)
|
||||||
family.set_leader()
|
family.set_leader()
|
||||||
self.storage.add(subpath, family)
|
self.storage.add(subpath, family)
|
||||||
leader_name = None
|
leader_name = None
|
||||||
|
@ -474,7 +474,7 @@ class Variable(Common):
|
||||||
|
|
||||||
|
|
||||||
class Family(Common):
|
class Family(Common):
|
||||||
def __init__(self, elt, booleans, storage, force_icon=False):
|
def __init__(self, elt, booleans, storage, eosfunc, force_icon=False):
|
||||||
self.option = None
|
self.option = None
|
||||||
self.attrib = {}
|
self.attrib = {}
|
||||||
self.is_leader = False
|
self.is_leader = False
|
||||||
|
@ -484,6 +484,7 @@ class Family(Common):
|
||||||
self.informations = {}
|
self.informations = {}
|
||||||
self.children = []
|
self.children = []
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
|
self.eosfunc = eosfunc
|
||||||
self.attrib['properties'] = []
|
self.attrib['properties'] = []
|
||||||
for key, value in elt.attrib.items():
|
for key, value in elt.attrib.items():
|
||||||
if key in booleans:
|
if key in booleans:
|
||||||
|
@ -528,11 +529,16 @@ class Family(Common):
|
||||||
self.attrib['children'].append(child.get())
|
self.attrib['children'].append(child.get())
|
||||||
self.build_properties()
|
self.build_properties()
|
||||||
try:
|
try:
|
||||||
if not self.is_leader:
|
if 'dynamic' in self.attrib:
|
||||||
|
dynamic = self.storage.get(self.attrib['dynamic']).get()
|
||||||
|
del self.attrib['dynamic']
|
||||||
|
self.attrib['suffixes'] = Calculation(self.eosfunc.calc_value,
|
||||||
|
Params((ParamOption(dynamic),)))
|
||||||
|
option = DynOptionDescription(**self.attrib)
|
||||||
|
elif not self.is_leader:
|
||||||
option = OptionDescription(**self.attrib)
|
option = OptionDescription(**self.attrib)
|
||||||
else:
|
else:
|
||||||
option = Leadership(**self.attrib)
|
option = Leadership(**self.attrib)
|
||||||
#option = OptionDescription(**self.attrib)
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise CreoleLoaderError(_('cannot create optiondescription {}: {}').format(self.attrib['name'], err))
|
raise CreoleLoaderError(_('cannot create optiondescription {}: {}').format(self.attrib['name'], err))
|
||||||
for key, value in self.informations.items():
|
for key, value in self.informations.items():
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from tiramisu import valid_not_equal, valid_ip_netmask
|
from tiramisu import valid_not_equal, valid_ip_netmask, calc_value
|
||||||
|
|
||||||
def calc_val(*args, **kwargs):
|
def calc_val(*args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
15
tests/flattener_dicos/20family_dynamic/00-base.xml
Normal file
15
tests/flattener_dicos/20family_dynamic/00-base.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<creole>
|
||||||
|
<variables>
|
||||||
|
<family name='general'>
|
||||||
|
<variable name='varname' type='string' description="No change" multi="True">
|
||||||
|
<value>val1</value>
|
||||||
|
<value>val2</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
<family name='dyn' dynamic="varname">
|
||||||
|
<variable name='vardyn' type='string' description="No change"/>
|
||||||
|
</family>
|
||||||
|
</variables>
|
||||||
|
</creole>
|
|
@ -0,0 +1 @@
|
||||||
|
{"creole.general.varname": ["val1", "val2"], "creole.dynval1.vardynval1": null, "creole.dynval2.vardynval2": null}
|
20
tests/flattener_dicos/20family_dynamic/result/00-base.xml
Normal file
20
tests/flattener_dicos/20family_dynamic/result/00-base.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<creole>
|
||||||
|
<family doc="" name="creole">
|
||||||
|
<family doc="general" name="general">
|
||||||
|
<property>normal</property>
|
||||||
|
<variable doc="No change" multi="True" name="varname" type="string">
|
||||||
|
<property>mandatory</property>
|
||||||
|
<property>normal</property>
|
||||||
|
<value>val1</value>
|
||||||
|
<value>val2</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
<family dynamic="creole.general.varname" doc="dyn" name="dyn">
|
||||||
|
<property>normal</property>
|
||||||
|
<variable doc="No change" multi="False" name="vardyn" type="string">
|
||||||
|
<property>normal</property>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
|
</creole>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<creole>
|
||||||
|
<containers>
|
||||||
|
<container name='test' id='23'>
|
||||||
|
<file name='file_name' name_type="SymLinkOption" source="mailname"/>
|
||||||
|
</container>
|
||||||
|
</containers>
|
||||||
|
<variables>
|
||||||
|
<family name='général'>
|
||||||
|
<variable name='mode_conteneur_actif' type='oui/non' description="No change" hidden="True">
|
||||||
|
<value>oui</value>
|
||||||
|
</variable>
|
||||||
|
<variable name='file_name' type='string' multi='True'>
|
||||||
|
<value>/etc/mailname</value>
|
||||||
|
<value>/etc/mailname2</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
<separators/>
|
||||||
|
</variables>
|
||||||
|
</creole>
|
|
@ -0,0 +1 @@
|
||||||
|
{"creole.general.file_name": ["/etc/mailname", "/etc/mailname2"], "containers.container0.files.file0.mkdir": false, "containers.container0.files.file0.name": ["/etc/mailname", "/etc/mailname2"], "containers.container0.files.file0.rm": false, "containers.container0.files.file0.source": "mailname", "containers.container0.files.file0.activate": true}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<creole>
|
||||||
|
<family name="containers">
|
||||||
|
<family name="container0" doc="test">
|
||||||
|
<family doc="files" name="files">
|
||||||
|
<family doc="file0" name="file0">
|
||||||
|
<variable doc="" multi="False" name="mkdir" type="boolean">
|
||||||
|
<value>False</value>
|
||||||
|
</variable>
|
||||||
|
<variable multi="False" name="name" opt="creole.general.file_name" type="symlink"/>
|
||||||
|
<variable doc="" multi="False" name="rm" type="boolean">
|
||||||
|
<value>False</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="source" type="string">
|
||||||
|
<value>mailname</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="activate" type="boolean">
|
||||||
|
<value>True</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
|
<property>basic</property>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
|
<family doc="" name="creole">
|
||||||
|
<family doc="général" name="general">
|
||||||
|
<property>normal</property>
|
||||||
|
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
||||||
|
<choice type="string">oui</choice>
|
||||||
|
<choice type="string">non</choice>
|
||||||
|
<property>force_default_on_freeze</property>
|
||||||
|
<property>frozen</property>
|
||||||
|
<property>hidden</property>
|
||||||
|
<property>mandatory</property>
|
||||||
|
<property>normal</property>
|
||||||
|
<value type="string">oui</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="file_name" multi="True" name="file_name" type="string">
|
||||||
|
<property>mandatory</property>
|
||||||
|
<property>normal</property>
|
||||||
|
<value>/etc/mailname</value>
|
||||||
|
<value>/etc/mailname2</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
<separators/>
|
||||||
|
</family>
|
||||||
|
</creole>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<creole>
|
||||||
|
<containers>
|
||||||
|
<container name='test' id='23'>
|
||||||
|
<file name='file_name' name_type="SymLinkOption"/>
|
||||||
|
</container>
|
||||||
|
</containers>
|
||||||
|
<variables>
|
||||||
|
<family name='général'>
|
||||||
|
<variable name='mode_conteneur_actif' type='oui/non' description="No change" hidden="True">
|
||||||
|
<value>oui</value>
|
||||||
|
</variable>
|
||||||
|
<variable name='file_name' type='string'>
|
||||||
|
<value>/etc/mailname</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
<separators/>
|
||||||
|
</variables>
|
||||||
|
</creole>
|
|
@ -4,11 +4,9 @@ from pytest import fixture, raises
|
||||||
from os import listdir
|
from os import listdir
|
||||||
from json import load
|
from json import load
|
||||||
|
|
||||||
#from creole.xmlreflector import CreoleObjSpace, CreoleDictConsistencyError
|
|
||||||
#from creole import xmlreflector
|
|
||||||
from rougail import objspace, annotator
|
from rougail import objspace, annotator
|
||||||
from creole.xml_compare import xml_compare
|
from rougail.xml_compare import xml_compare
|
||||||
from creole.error import CreoleDictConsistencyError
|
from rougail.error import CreoleDictConsistencyError
|
||||||
from rougail.config import dtdfilename
|
from rougail.config import dtdfilename
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,7 +83,7 @@ def launch_flattener(test_dir):
|
||||||
eolobj.save(destfile)
|
eolobj.save(destfile)
|
||||||
result_file = join(test_dir, 'result/00-base.xml')
|
result_file = join(test_dir, 'result/00-base.xml')
|
||||||
if isfile(result_file):
|
if isfile(result_file):
|
||||||
# eolobj.save(result_file)
|
# eolobj.save(result_file)
|
||||||
compare_xml(destfile, result_file)
|
compare_xml(destfile, result_file)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ for test in listdir(dico_dirs):
|
||||||
excludes = set([])
|
excludes = set([])
|
||||||
excludes = set([])
|
excludes = set([])
|
||||||
test_ok -= excludes
|
test_ok -= excludes
|
||||||
#test_ok = ['70container_all']
|
#test_ok = ['20family_dynamic']
|
||||||
|
|
||||||
|
|
||||||
test_ok = list(test_ok)
|
test_ok = list(test_ok)
|
||||||
|
|
|
@ -22,13 +22,11 @@ def test_dictionary(test_dir):
|
||||||
test_dir = join(template_dirs, test_dir)
|
test_dir = join(template_dirs, test_dir)
|
||||||
tmp_dir = join(test_dir, 'tmp')
|
tmp_dir = join(test_dir, 'tmp')
|
||||||
funcs_file = join(template_dirs, '../eosfunc/test.py')
|
funcs_file = join(template_dirs, '../eosfunc/test.py')
|
||||||
template.distrib_dir = join(test_dir, 'tmpl')
|
distrib_dir = join(test_dir, 'tmpl')
|
||||||
template.templatedir = tmp_dir
|
|
||||||
if isdir(tmp_dir):
|
if isdir(tmp_dir):
|
||||||
rmtree(tmp_dir)
|
rmtree(tmp_dir)
|
||||||
mkdir(tmp_dir)
|
mkdir(tmp_dir)
|
||||||
dest_dir = join(test_dir, 'dest')
|
dest_dir = join(test_dir, 'dest')
|
||||||
template.dest_dir = dest_dir
|
|
||||||
if isdir(dest_dir):
|
if isdir(dest_dir):
|
||||||
rmtree(dest_dir)
|
rmtree(dest_dir)
|
||||||
mkdir(dest_dir)
|
mkdir(dest_dir)
|
||||||
|
@ -41,13 +39,19 @@ def test_dictionary(test_dir):
|
||||||
config = Config(optiondescription)
|
config = Config(optiondescription)
|
||||||
config.property.read_only()
|
config.property.read_only()
|
||||||
template.generate(config,
|
template.generate(config,
|
||||||
funcs_file)
|
funcs_file,
|
||||||
|
distrib_dir,
|
||||||
|
tmp_dir,
|
||||||
|
dest_dir)
|
||||||
|
|
||||||
list_templates = set(listdir(dest_dir))
|
if isdir(join(dest_dir, 'test')):
|
||||||
|
list_templates = set(listdir(join(dest_dir, 'test')))
|
||||||
|
else:
|
||||||
|
list_templates = set()
|
||||||
list_results = set(listdir(join(test_dir, 'result')))
|
list_results = set(listdir(join(test_dir, 'result')))
|
||||||
assert list_templates == list_results
|
assert list_templates == list_results
|
||||||
for result in listdir(join(test_dir, 'result')):
|
for result in listdir(join(test_dir, 'result')):
|
||||||
template_file = join(dest_dir, result)
|
template_file = join(dest_dir, 'test', result)
|
||||||
if not isfile(template_file):
|
if not isfile(template_file):
|
||||||
raise Exception(f'{template_file} is not generated')
|
raise Exception(f'{template_file} is not generated')
|
||||||
with open(join(test_dir, 'result', result), 'r') as fh:
|
with open(join(test_dir, 'result', result), 'r') as fh:
|
||||||
|
|
Loading…
Reference in a new issue