diff --git a/src/rougail/annotator/service.py b/src/rougail/annotator/service.py index 588afa3e..66f2902a 100644 --- a/src/rougail/annotator/service.py +++ b/src/rougail/annotator/service.py @@ -1,4 +1,7 @@ +"""Annotate services +""" from os.path import basename +from typing import Tuple from ..i18n import _ from ..utils import normalize_family @@ -11,13 +14,13 @@ ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check KEY_TYPE = {'variable': 'symlink', - 'SymLinkOption': 'symlink', 'PortOption': 'port', 'UnicodeOption': 'string', 'NetworkOption': 'network', 'NetmaskOption': 'netmask', 'URLOption': 'web_address', - 'FilenameOption': 'filename'} + 'FilenameOption': 'filename', + } class ServiceAnnotator: @@ -33,14 +36,15 @@ class ServiceAnnotator: """ def __init__(self, objectspace): self.objectspace = objectspace - self.convert_services() + if hasattr(self.objectspace.space, 'services'): + if not hasattr(self.objectspace.space.services, 'service'): + del self.objectspace.space.services + else: + self.convert_services() def convert_services(self): - if not hasattr(self.objectspace.space, 'services'): - return - if not hasattr(self.objectspace.space.services, 'service'): - del self.objectspace.space.services - return + """convert services to variables + """ self.objectspace.space.services.hidden = True self.objectspace.space.services.name = 'services' self.objectspace.space.services.doc = 'services' @@ -54,10 +58,10 @@ class ServiceAnnotator: continue eltname = elttype + 's' path = '.'.join(['services', service_name, eltname]) - family = self.gen_family(eltname, - path, - service.xmlfiles, - ) + family = self._gen_family(eltname, + path, + service.xmlfiles, + ) if isinstance(values, dict): values = list(values.values()) family.family = self.make_group_from_elts(service_name, @@ -70,11 +74,87 @@ class ServiceAnnotator: families[service_name] = new_service self.objectspace.space.services.service = families - def gen_family(self, - name, - path, - xmlfiles - ): + def make_group_from_elts(self, + service_name, + elttype, + elts, + path, + ): + """Splits each objects into a group (and `OptionDescription`, in tiramisu terms) + and build elements and its attributes (the `Options` in tiramisu terms) + """ + families = [] + for elt in elts: + # try to launch _update_xxxx() function + update_elt = '_update_' + elttype + if hasattr(self, update_elt): + getattr(self, update_elt)(elt, + service_name, + ) + c_name, subpath = self._get_name_path(elt, + path, + ) + family = self._gen_family(c_name, + subpath, + elt.xmlfiles, + ) + family.variable = [] + activate_path = '.'.join([subpath, 'activate']) + for key in dir(elt): + if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: + continue + value = getattr(elt, key) + listname = '{}list'.format(elttype) + if key == listname: + self.objectspace.list_conditions.setdefault(listname, + {}).setdefault( + value, + []).append(activate_path) + continue + family.variable.append(self._generate_element(self._get_type(key, + elttype, + elt, + ), + key, + value, + elt.xmlfiles, + f'{subpath}.{key}' + )) + # FIXME ne devrait pas etre True par défaut + # devrait etre un calcule + family.variable.append(self._generate_element('boolean', + 'activate', + True, + elt.xmlfiles, + activate_path, + )) + families.append(family) + return families + + def _get_name_path(self, + elt, + path: str, + ) -> Tuple[str, str]: + # create element name, if already exists, add _xx to be uniq + if hasattr(elt, 'source'): + name = elt.source + else: + name = elt.name + idx = 0 + while True: + c_name = name + if idx: + c_name += f'_{idx}' + subpath = '{}.{}'.format(path, c_name) + if not self.objectspace.paths.family_is_defined(subpath): + return c_name, subpath + idx += 1 + + def _gen_family(self, + name, + path, + xmlfiles + ): family = self.objectspace.family(xmlfiles) family.name = normalize_family(name) family.doc = name @@ -85,111 +165,25 @@ class ServiceAnnotator: ) return family - def make_group_from_elts(self, - service_name, - name, - elts, - path, - ): - """Splits each objects into a group (and `OptionDescription`, in tiramisu terms) - and build elements and its attributes (the `Options` in tiramisu terms) - """ - families = [] - new_elts = self._reorder_elts(name, - elts, - ) - for index, elt_info in enumerate(new_elts): - elt = elt_info['elt'] - elt_name = elt_info['elt_name'] - - # try to launch _update_xxxx() function - update_elt = '_update_' + elt_name - if hasattr(self, update_elt): - getattr(self, update_elt)(elt, - index, - path, - service_name, - ) - - idx = 0 - while True: - if hasattr(elt, 'source'): - c_name = elt.source - else: - c_name = elt.name - if idx: - c_name += f'_{idx}' - subpath = '{}.{}'.format(path, c_name) - if not self.objectspace.paths.family_is_defined(subpath): - break - idx += 1 - family = self.gen_family(c_name, - subpath, - elt.xmlfiles, - ) - family.variable = [] - listname = '{}list'.format(name) - activate_path = '.'.join([subpath, 'activate']) - for key in dir(elt): - if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: - continue - value = getattr(elt, key) - if key == listname: - self.objectspace.list_conditions.setdefault(listname, - {}).setdefault( - value, - []).append(activate_path) - continue - family.variable.append(self._generate_element(elt_name, - key, - value, - elt, - f'{subpath}.{key}' - )) - # FIXME ne devrait pas etre True par défaut - # devrait etre un calcule - family.variable.append(self._generate_element(elt_name, - 'activate', - True, - elt, - activate_path, - )) - families.append(family) - return families - def _generate_element(self, - elt_name, + type_, key, value, - elt, + xmlfiles, path, ): - variable = self.objectspace.variable(elt.xmlfiles) + variable = self.objectspace.variable(xmlfiles) variable.name = normalize_family(key) variable.mode = None - if key == 'name': - true_key = elt_name - else: - true_key = key - dtd_key_type = true_key + '_type' - if key == 'activate': - type_ = 'boolean' - elif hasattr(elt, dtd_key_type): - type_ = KEY_TYPE[getattr(elt, dtd_key_type)] - elif key in self.objectspace.booleans_attributs: - type_ = 'boolean' - else: - type_ = 'string' variable.type = type_ if type_ == 'symlink': variable.opt = self.objectspace.paths.get_variable_path(value, 'services', ) -# variable.opt = value variable.multi = None else: variable.doc = key - val = self.objectspace.value(elt.xmlfiles) + val = self.objectspace.value(xmlfiles) val.type = type_ val.name = value variable.value = [val] @@ -201,28 +195,23 @@ class ServiceAnnotator: ) return variable - def _reorder_elts(self, - name, - elts, - ): - """Reorders by index the elts - """ - new_elts = {} - # reorder elts by index - for idx, elt in enumerate(elts): - new_elts.setdefault(idx, []).append(elt) - idxes = list(new_elts.keys()) - idxes.sort() - result_elts = [] - for idx in idxes: - for elt in new_elts[idx]: - result_elts.append({'elt_name': name, 'elt': elt}) - return result_elts + def _get_type(self, + key: str, + elt_name: str, + elt, + ) -> str: + if key == 'name': + dtd_key_type = elt_name + '_type' + else: + dtd_key_type = key + '_type' + if key in self.objectspace.booleans_attributs: + return 'boolean' + if hasattr(elt, dtd_key_type): + return KEY_TYPE[getattr(elt, dtd_key_type)] + return 'string' def _update_override(self, file_, - index, - service_path, service_name, ): file_.name = f'/systemd/system/{service_name}.service.d/rougail.conf' @@ -232,15 +221,11 @@ class ServiceAnnotator: if not hasattr(file_, 'source'): file_.source = f'{service_name}.service' self._update_file(file_, - index, - service_path, service_name, ) def _update_file(self, file_, - index, - service_path, service_name, ): if not hasattr(file_, 'file_type') or file_.file_type == "UnicodeOption": @@ -248,5 +233,6 @@ class ServiceAnnotator: file_.source = basename(file_.name) elif not hasattr(file_, 'source'): xmlfiles = self.objectspace.display_xmlfiles(file_.xmlfiles) - raise DictConsistencyError(_(f'attribute "source" is mandatory for the file "{file_.name}" in {xmlfiles}'), 34) - + msg = _(f'attribute "source" is mandatory for the file "{file_.name}" ' + f'"({service_name})" in {xmlfiles}') + raise DictConsistencyError(msg, 34)