rougail/src/rougail/annotator/variable.py

234 lines
9.5 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 ..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"),
'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}),
'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}),
}
FORCE_CHOICE = {'schedule': ['none', 'daily', 'weekly', 'monthly'],
'schedulemod': ['pre', 'post'],
}
class Walk:
"""Walk to objectspace to find variable or family
"""
def get_variables(self,
with_leadership: bool=False,
):
"""Iter all variables from the objectspace
"""
for family in self.objectspace.space.variables.values():
yield from self._get_variables(family, with_leadership)
def _get_variables(self,
family: 'self.objectspace.family',
with_leadership: bool
):
if hasattr(family, 'variable'):
for variable in family.variable.values():
if isinstance(variable, self.objectspace.family):
yield from self._get_variables(variable, with_leadership)
continue
if not with_leadership and isinstance(variable, self.objectspace.leadership):
for follower in variable.variable:
yield follower
continue
yield variable
# if hasattr(family, 'family'):
# for fam in family.family.values():
# yield from self._get_variables(fam, with_leadership)
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 hasattr(family, 'variable'):
for fam in family.variable.values():
if isinstance(fam, self.objectspace.family):
yield from self._get_families(fam)
class VariableAnnotator(Walk): # pylint: disable=R0903
"""Annotate variable
"""
def __init__(self,
objectspace,
):
if not hasattr(objectspace.space, 'variables'):
return
self.objectspace = objectspace
self.convert_variable()
self.convert_test()
self.convert_help()
def convert_variable(self):
"""convert variable
"""
for variable in self.get_variables(with_leadership=True):
if isinstance(variable, self.objectspace.leadership):
# first variable is a leader, others are follower
variable_type = 'leader'
for follower in variable.variable:
self._convert_variable(follower,
variable_type,
)
variable_type = 'follower'
else:
self._convert_variable(variable,
'variable',
)
def _convert_variable(self,
variable,
variable_type: str,
) -> None:
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
variable.doc = variable.description
del variable.description
if variable_type == 'follower':
if variable.multi is True:
variable.multi = 'submulti'
else:
variable.multi = True
self._convert_valid_enum(variable)
def _convert_valid_enum(self,
variable,
):
"""some types are, in fact, choices
convert this kind of variables into choice
"""
if variable.type in FORCE_CHOICE:
if not hasattr(self.objectspace.space, 'constraints'):
xmlfiles = variable.xmlfiles
self.objectspace.space.constraints = self.objectspace.constraints(xmlfiles)
self.objectspace.space.constraints.namespace = variable.namespace
if not hasattr(self.objectspace.space.constraints, 'check'):
self.objectspace.space.constraints.check = []
check = self.objectspace.check(variable.xmlfiles)
check.name = 'valid_enum'
target = self.objectspace.target(variable.xmlfiles)
target.name = variable.path
check.target = [target]
check.namespace = variable.namespace
check.param = []
for value in FORCE_CHOICE[variable.type]:
param = self.objectspace.param(variable.xmlfiles)
param.text = value
check.param.append(param)
self.objectspace.space.constraints.check.append(check)
variable.type = 'string'
def convert_test(self):
"""Convert variable tests value
"""
for variable in self.get_variables():
self._convert_test(variable)
def _convert_test(self,
variable,
) -> None:
if not hasattr(variable, 'information'):
variable.information = self.objectspace.information(variable.xmlfiles)
if hasattr(variable, 'test'):
if variable.test:
values = variable.test.split('|')
new_values = []
for value in values:
if value == '':
value = None
else:
value = CONVERT_OPTION.get(variable.type, {}).get('func', str)(value)
new_values.append(value)
variable.information.test = tuple(new_values)
del variable.test
def convert_help(self):
"""Convert variable help
"""
for variable in self.get_variables():
self._convert_help(variable)
@staticmethod
def _convert_help(variable) -> None:
if hasattr(variable, 'help'):
variable.information.help = variable.help
del variable.help