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