check variable and family name

This commit is contained in:
Emmanuel Garette 2021-02-16 12:08:45 +01:00
parent bd299e3d2b
commit e60fd4adbc
24 changed files with 158 additions and 57 deletions

View file

@ -34,3 +34,4 @@ Rougail est un bibliothèque python3 qui permet de charger des dictionnaires (fi
## Les templates
- Type creole
FIXME ^^

View file

@ -29,7 +29,6 @@ from typing import List, Any
from ..i18n import _
from ..error import DictConsistencyError
from ..config import RougailConfig
from .target import TargetAnnotator
from .param import ParamAnnotator
@ -75,13 +74,13 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
for variable in self.get_variables():
if not variable.auto_freeze:
continue
if variable.namespace != RougailConfig['variable_namespace']:
if variable.namespace != self.objectspace.rougailconfig['variable_namespace']:
msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}"')
raise DictConsistencyError(msg, 49, variable.xmlfiles)
new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_frozen_if_not_in'
new_condition.namespace = variable.namespace
new_condition.source = RougailConfig['auto_freeze_variable']
new_condition.source = self.objectspace.rougailconfig['auto_freeze_variable']
new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = True
new_condition.param = [new_param]
@ -114,12 +113,9 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
if condition.optional is False or \
self.objectspace.paths.path_is_defined(condition.source):
continue
if hasattr(condition, 'apply_on_fallback'):
apply_action = condition.apply_on_fallback
else:
apply_on_fallback = condition.name.endswith('_if_in'):
remove_conditions.append(idx)
if apply_action:
if (hasattr(condition, 'apply_on_fallback') and condition.apply_on_fallback) or \
(not hasattr(condition, 'apply_on_fallback') and condition.name.endswith('_if_in')):
self.force_actions_to_variable(condition)
remove_conditions.sort(reverse=True)
for idx in remove_conditions:

View file

@ -25,6 +25,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from ..i18n import _
from ..error import DictConsistencyError
from ..objspace import convert_boolean
@ -116,6 +118,9 @@ class VariableAnnotator(Walk): # pylint: disable=R0903
if not hasattr(objectspace.space, 'variables'):
return
self.objectspace = objectspace
self.forbidden_name = ['services', self.objectspace.rougailconfig['variable_namespace']]
for extra in self.objectspace.rougailconfig['extra_dictionaries']:
self.forbidden_name.append(extra)
self.convert_variable()
self.convert_test()
self.convert_help()
@ -141,6 +146,10 @@ class VariableAnnotator(Walk): # pylint: disable=R0903
variable,
variable_type: str,
) -> None:
if variable.namespace == self.objectspace.rougailconfig['variable_namespace'] and \
variable.name in self.forbidden_name:
msg = _(f'the name of the variable "{variable.name}" cannot be the same as the name of a namespace')
raise DictConsistencyError(msg, 54, variable.xmlfiles)
if variable.type != 'symlink' and not hasattr(variable, 'description'):
variable.description = variable.name
if hasattr(variable, 'value'):

View file

@ -58,16 +58,22 @@ from .error import DictConsistencyError
class RougailConvert:
"""Rougail object
"""
def __init__(self) -> None:
xmlreflector = XMLReflector()
rougailobjspace = RougailObjSpace(xmlreflector)
def __init__(self,
rougailconfig: RougailConfig=None,
) -> None:
if rougailconfig is None:
rougailconfig = RougailConfig
xmlreflector = XMLReflector(rougailconfig)
rougailobjspace = RougailObjSpace(xmlreflector,
rougailconfig,
)
self._load_dictionaries(xmlreflector,
rougailobjspace,
RougailConfig['variable_namespace'],
RougailConfig['dictionaries_dir'],
rougailconfig['variable_namespace'],
rougailconfig['dictionaries_dir'],
)
for namespace, extra_dir in RougailConfig['extra_dictionaries'].items():
if namespace in ['services', RougailConfig['variable_namespace']]:
for namespace, extra_dir in rougailconfig['extra_dictionaries'].items():
if namespace in ['services', rougailconfig['variable_namespace']]:
msg = _(f'Namespace name "{namespace}" is not allowed')
raise DictConsistencyError(msg, 21, None)
self._load_dictionaries(xmlreflector,
@ -75,7 +81,7 @@ class RougailConvert:
namespace,
extra_dir,
)
functions_file = RougailConfig['functions_file']
functions_file = rougailconfig['functions_file']
SpaceAnnotator(rougailobjspace,
functions_file,
)

View file

@ -32,7 +32,6 @@ from .xmlreflector import XMLReflector
from .utils import normalize_family
from .error import SpaceObjShallNotBeUpdated, DictConsistencyError
from .path import Path
from .config import RougailConfig
# RougailObjSpace's elements that shall be forced to the Redefinable type
FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables')
@ -101,9 +100,10 @@ class RougailObjSpace:
def __init__(self,
xmlreflector: XMLReflector,
rougailconfig: 'RougailConfig',
) -> None:
self.space = ObjSpace()
self.paths = Path()
self.paths = Path(rougailconfig)
self.forced_text_elts_as_name = set(FORCED_TEXT_ELTS_AS_NAME)
self.list_conditions = {}
@ -112,6 +112,7 @@ class RougailObjSpace:
self.has_dyn_option = False
self.make_object_space_classes(xmlreflector)
self.rougailconfig = rougailconfig
def make_object_space_classes(self,
xmlreflector: XMLReflector,
@ -197,7 +198,7 @@ class RougailObjSpace:
family_names.append(child.attrib['name'])
try:
# variable objects creation
variableobj = self.get_variableobj(xmlfile,
exists, variableobj = self.get_variableobj(xmlfile,
child,
space,
namespace,
@ -216,6 +217,7 @@ class RougailObjSpace:
variableobj,
redefine_variables,
)
if not exists:
self.set_path(namespace,
document,
variableobj,
@ -260,11 +262,12 @@ class RougailObjSpace:
if child.tag in vars(space):
# Atom instance has to be a singleton here
# we do not re-create it, we reuse it
return getattr(space, child.tag)
return obj(xmlfile, name)
return False, getattr(space, child.tag)
return False, obj(xmlfile, name)
# UnRedefinable object
if child.tag not in vars(space):
setattr(space, child.tag, [])
return obj(xmlfile, name)
return False, obj(xmlfile, name)
def _get_name(self,
child,
@ -301,12 +304,12 @@ class RougailObjSpace:
redefine = convert_boolean(subspace.get('redefine', default_redefine))
if redefine is True:
if isinstance(existed_var, self.variable): # pylint: disable=E1101
if namespace == RougailConfig['variable_namespace']:
if namespace == self.rougailconfig['variable_namespace']:
redefine_variables.append(name)
else:
redefine_variables.append(space.path + '.' + name)
existed_var.xmlfiles.append(xmlfile)
return existed_var
return True, existed_var
exists = convert_boolean(subspace.get('exists', True))
if exists is False:
raise SpaceObjShallNotBeUpdated()
@ -327,7 +330,7 @@ class RougailObjSpace:
if tag not in vars(space):
setattr(space, tag, {})
obj = getattr(self, child.tag)(xmlfile, name)
return obj
return False, obj
def get_existed_obj(self,
name: str,
@ -340,7 +343,7 @@ class RougailObjSpace:
if child.tag in ['variable', 'family']:
name = normalize_family(name)
if child.tag == 'variable': # pylint: disable=E1101
if namespace != RougailConfig['variable_namespace']:
if namespace != self.rougailconfig['variable_namespace']:
name = space.path + '.' + name
if not self.paths.path_is_defined(name):
return None
@ -474,7 +477,7 @@ class RougailObjSpace:
)
elif isinstance(variableobj, self.family): # pylint: disable=E1101
family_name = normalize_family(variableobj.name)
if namespace != RougailConfig['variable_namespace']:
if namespace != self.rougailconfig['variable_namespace']:
family_name = namespace + '.' + family_name
self.paths.add_family(namespace,
family_name,

View file

@ -26,7 +26,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from .i18n import _
from .error import DictConsistencyError
from .config import RougailConfig
from .utils import normalize_family
@ -36,11 +35,14 @@ class Path:
sample: path="creole.general.condition"
"""
def __init__(self):
def __init__(self,
rougailconfig: 'RougailConfig',
) -> None:
self.variables = {}
self.families = {}
self.full_paths_families = {}
self.full_paths_variables = {}
self.variable_namespace = rougailconfig['variable_namespace']
# Family
def add_family(self,
@ -51,8 +53,10 @@ class Path:
) -> str: # pylint: disable=C0111
"""Add a new family
"""
if namespace == RougailConfig['variable_namespace']:
if namespace == self.variable_namespace:
full_name = '.'.join([subpath, name])
if name in self.full_paths_families:
raise DictConsistencyError(_(f'Duplicate family name "{name}"'), 55, variableobj.xmlfiles)
self.full_paths_families[name] = full_name
else:
if '.' not in name: # pragma: no cover
@ -93,7 +97,7 @@ class Path:
if name not in self.families:
raise DictConsistencyError(_(f'unknown option {name}'), 42, [])
dico = self.families[name]
if current_namespace not in [RougailConfig['variable_namespace'], 'services'] and \
if current_namespace not in [self.variable_namespace, 'services'] and \
current_namespace != dico['namespace']:
msg = _(f'A family located in the "{dico["namespace"]}" namespace '
f'shall not be used in the "{current_namespace}" namespace')
@ -117,7 +121,7 @@ class Path:
self.variables[new_path]['leader'] = leadership_path
self.variables[new_path]['variableobj'].path = new_path
self.variables[new_path]['family'] = leadership_path
if namespace == RougailConfig['variable_namespace']:
if namespace == self.variable_namespace:
self.full_paths_variables[name] = new_path
def is_leader(self, path): # pylint: disable=C0111
@ -141,7 +145,7 @@ class Path:
"""
if '.' not in name:
full_path = '.'.join([family, name])
if namespace == RougailConfig['variable_namespace']:
if namespace == self.variable_namespace:
self.full_paths_variables[name] = full_path
else:
full_path = name
@ -180,7 +184,7 @@ class Path:
with_suffix=True,
)
namespace = dico['variableobj'].namespace
if namespace not in [RougailConfig['variable_namespace'], 'services'] and \
if namespace not in [self.variable_namespace, 'services'] and \
current_namespace != namespace:
msg = _(f'A variable located in the "{namespace}" namespace shall not be used '
f'in the "{current_namespace}" namespace')

View file

@ -223,14 +223,17 @@ class RougailTemplate:
"""
def __init__(self, # pylint: disable=R0913
config: Config,
rougailconfig: RougailConfig=None,
) -> None:
if rougailconfig is None:
rougailconfig = RougailConfig
self.config = config
self.destinations_dir = abspath(RougailConfig['destinations_dir'])
self.tmp_dir = abspath(RougailConfig['tmp_dir'])
self.templates_dir = abspath(RougailConfig['templates_dir'])
self.patches_dir = abspath(RougailConfig['patches_dir'])
self.destinations_dir = abspath(rougailconfig['destinations_dir'])
self.tmp_dir = abspath(rougailconfig['tmp_dir'])
self.templates_dir = abspath(rougailconfig['templates_dir'])
self.patches_dir = abspath(rougailconfig['patches_dir'])
eos = {}
functions_file = RougailConfig['functions_file']
functions_file = rougailconfig['functions_file']
if isfile(functions_file):
eosfunc = load_modules(functions_file)
for func in dir(eosfunc):
@ -238,6 +241,7 @@ class RougailTemplate:
eos[func] = getattr(eosfunc, func)
self.eosfunc = eos
self.rougail_variables_dict = {}
self.rougailconfig = rougailconfig
def patch_template(self,
filename: str,
@ -343,7 +347,7 @@ class RougailTemplate:
chdir(self.templates_dir)
for option in await self.config.option.list(type='all'):
namespace = await option.option.name()
is_variable_namespace = namespace == RougailConfig['variable_namespace']
is_variable_namespace = namespace == self.rougailconfig['variable_namespace']
self.rougail_variables_dict[namespace] = await self.load_variables(option,
is_variable_namespace,
)

View file

@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from json import dumps
from os.path import isfile
from .config import RougailConfig
from .annotator import CONVERT_OPTION
from .objspace import RootRougailObject
@ -96,10 +95,10 @@ class TiramisuReflector:
because `extra` family could use `variable_namespace` variables.
"""
if hasattr(self.objectspace.space, 'variables'):
if RougailConfig['variable_namespace'] in self.objectspace.space.variables:
yield self.objectspace.space.variables[RougailConfig['variable_namespace']]
if self.objectspace.rougailconfig['variable_namespace'] in self.objectspace.space.variables:
yield self.objectspace.space.variables[self.objectspace.rougailconfig['variable_namespace']]
for elt, value in self.objectspace.space.variables.items():
if elt != RougailConfig['variable_namespace']:
if elt != self.objectspace.rougailconfig['variable_namespace']:
yield value
if hasattr(self.objectspace.space, 'services'):
yield self.objectspace.space.services

View file

@ -32,7 +32,6 @@ from lxml.etree import DTD, parse, XMLSyntaxError # pylint: disable=E0611
from .i18n import _
from .error import DictConsistencyError
from .config import RougailConfig
class XMLReflector:
@ -40,14 +39,16 @@ class XMLReflector:
parsing it, validating against the Creole DTD,
writing the xml result on the disk
"""
def __init__(self):
def __init__(self,
rougailconfig: 'RougailConfig',
) -> None:
"""Loads the Creole DTD
:raises IOError: if the DTD is not found
:param dtdfilename: the full filename of the Creole DTD
"""
dtdfilename = RougailConfig['dtdfilename']
dtdfilename = rougailconfig['dtdfilename']
if not isfile(dtdfilename):
raise IOError(_("no such DTD file: {}").format(dtdfilename))
with open(dtdfilename, 'r') as dtdfd:

View file

@ -0,0 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="général">
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
<value>non</value>
</variable>
<variable name="activer_ejabberd" type="string" description="No change" hidden="True">
<value>non</value>
</variable>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail>
<variables>
<variable name="extra"/>
</variables>
</rougail>

View file

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.activer_ejabberd": "non", "extra.extra": null}

View file

@ -0,0 +1,20 @@
from importlib.machinery import SourceFileLoader
from importlib.util import spec_from_loader, module_from_spec
loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
spec = spec_from_loader(loader.name, loader)
func = module_from_spec(spec)
loader.exec_module(func)
for key, value in dict(locals()).items():
if key != ['SourceFileLoader', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
option_4 = StrOption(name="activer_ejabberd", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
option_2 = OptionDescription(name="general", doc="général", children=[option_3, option_4], properties=frozenset({"normal"}))
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
option_6 = StrOption(name="extra", doc="extra", properties=frozenset({"normal"}))
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,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<family name="general">
<variable name="my_variable"/>
</family>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View file

@ -0,0 +1,8 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<variable name="extra"/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail>
<variables>
<variable name="day"/>
</variables>
</rougail>

View file

@ -0,0 +1,8 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<variable name="rougail"/>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->