rougail/src/rougail/annotator/variable.py

227 lines
10 KiB
Python

"""Annotate variable
Created by:
EOLE (http://eole.orion.education.fr)
Copyright (C) 2005-2018
Forked by:
Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
distribued with GPL-2 or later license
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.objspace import convert_boolean
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"),
'secret': dict(opttype="PasswordOption"),
'mail': dict(opttype="EmailOption"),
'boolean': dict(opttype="BoolOption", func=convert_boolean),
'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}),
'domainname': 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 Walk:
"""Walk to objectspace to find variable or family
"""
objectspace = None
def get_variables(self):
"""Iter all variables from the objectspace
"""
for family in self.objectspace.space.variables.values():
yield from self._get_variables(family)
def _get_variables(self,
family: 'self.objectspace.family',
):
if not hasattr(family, 'variable'):
return
for variable in family.variable.values():
if isinstance(variable, self.objectspace.family):
yield from self._get_variables(variable)
else:
yield variable
def get_families(self):
"""Iter all families from the objectspace
"""
for family in self.objectspace.space.variables.values():
yield from self._get_families(family)
def _get_families(self,
family: 'self.objectspace.family',
):
yield family
if not hasattr(family, 'variable'):
return
for fam in family.variable.values():
if isinstance(fam, self.objectspace.family):
yield from self._get_families(fam)
class Annotator(Walk): # pylint: disable=R0903
"""Annotate variable
"""
level = 30
def __init__(self,
objectspace,
*args,
):
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()
def convert_variable(self):
"""convert variable
"""
for variable in self.get_variables():
self._convert_variable(variable)
def _convert_variable(self,
variable,
) -> 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'):
value_to_del = []
for idx, value in enumerate(variable.value):
if not hasattr(value, 'name'):
value_to_del.append(idx)
else:
if not hasattr(value, 'type'):
value.type = variable.type
value.name = CONVERT_OPTION.get(value.type, {}).get('func', str)(value.name)
value_to_del.sort(reverse=True)
for idx in value_to_del:
del variable.value[idx]
if not variable.value:
del variable.value
if hasattr(variable, 'choice'):
if variable.type != 'choice':
msg = _(f'choice for the variable "{variable.name}" not allowed with "{variable.type}" type')
raise DictConsistencyError(msg, 3, variable.xmlfiles)
values = []
choice_type = None
for choice in variable.choice:
if choice_type == 'variable':
msg = _(f'only one "variable" choice is allowed '
f'the variable "{variable.name}"')
raise DictConsistencyError(msg, 5, choice.xmlfiles)
if choice.type == 'nil':
choice.name = None
elif choice.type == 'space':
choice.name = ' '
elif choice.type == 'variable':
choice.name = self.objectspace.paths.get_variable(choice.name)
if not choice.name.multi:
msg = _(f'only multi "variable" is allowed for a choice '
f'of variable "{variable.name}"')
raise DictConsistencyError(msg, 6, choice.xmlfiles)
else:
if not hasattr(choice, 'name'):
msg = _(f'choice for variable "{variable.name}" must have a value')
raise DictConsistencyError(msg, 14, choice.xmlfiles)
choice.name = CONVERT_OPTION.get(choice.type, {}).get('func', str)(choice.name)
if choice_type is None:
choice_type = choice.type
values.append(choice.name)
if choice_type not in ['function', 'variable'] and hasattr(variable, 'value'):
for value in variable.value:
if value.name not in values:
msg = _(f'value "{value.name}" of variable "{variable.name}" is not in list '
f'of all expected values ({values})')
raise DictConsistencyError(msg, 15, value.xmlfiles)
ref_choice = variable.choice[0]
self.objectspace.valid_enums[variable.path] = {'type': ref_choice.type,
'values': values,
'xmlfiles': ref_choice.xmlfiles,
}
elif variable.type == 'choice':
msg = _(f'choice is mandatory for the variable "{variable.name}" with choice type')
raise DictConsistencyError(msg, 4, variable.xmlfiles)
variable.doc = variable.description
del variable.description
def convert_test(self):
"""Convert variable tests value
"""
for variable in self.get_variables():
if not hasattr(variable, 'test') or not variable.test:
# with we want remove test, we set "" has test value
continue
new_values = []
for value in variable.test.split('|'):
if value == '':
value = None
else:
value = CONVERT_OPTION.get(variable.type, {}).get('func', str)(value)
new_values.append(value)
if not hasattr(variable, 'information'):
variable.information = self.objectspace.information(variable.xmlfiles)
variable.information.test = tuple(new_values)
def convert_help(self):
"""Convert variable help
"""
for variable in self.get_variables():
if not hasattr(variable, 'help'):
continue
if not hasattr(variable, 'information'):
variable.information = self.objectspace.information(variable.xmlfiles)
variable.information.help = variable.help
del variable.help