"""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 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