diff --git a/src/rougail/template/base.py b/src/rougail/template/base.py index ccb49cdbe..fc794a4ad 100644 --- a/src/rougail/template/base.py +++ b/src/rougail/template/base.py @@ -62,7 +62,7 @@ log.addHandler(logging.NullHandler()) INFORMATIONS = {'files': ['source', 'mode', 'engine', 'included'], 'overrides': ['name', 'source', 'engine'], - 'service_names': ['doc', 'engine', 'type'], + 'service_names': ['doc', 'engine', 'type', 'target', 'undisable'], } DEFAULT = {'files': ['owner', 'group'], 'overrides': [], @@ -178,6 +178,10 @@ class RougailLeader: def index(self, value): return self._value.index(value) + def __str__(self): + followers_name = list(self._follower) + return f'RougailLeader({followers_name[0]}) => {followers_name[1:]}' + class RougailExtra: """Object that implement access to extra variable @@ -212,7 +216,7 @@ class RougailExtra: return self._suboption.items() def __str__(self): - return self._name + return f'RougailExtra("{self._name}") => {self._suboption}' class RougailBaseTemplate: @@ -233,7 +237,12 @@ class RougailBaseTemplate: templates_dir = [templates_dir] for templ_dir in templates_dir: self.templates_dir.append(abspath(templ_dir)) - self.patches_dir = abspath(rougailconfig['patches_dir']) + patches_dir = rougailconfig['patches_dir'] + if not isinstance(patches_dir, list): + patches_dir = [patches_dir] + self.patches_dir = [] + for p_dir in patches_dir: + self.patches_dir.append(abspath(p_dir)) eos = {} functions_file = rougailconfig['functions_file'] if not isinstance(functions_file, list): @@ -259,16 +268,17 @@ class RougailBaseTemplate: patch_cmd = ['patch', '-d', self.tmp_dir, '-N', '-p1', '-f'] patch_no_debug = ['-s', '-r', '-', '--backup-if-mismatch'] - patch_file = join(self.patches_dir, f'{filename}.patch') - if isfile(patch_file): - self.log.info(_("Patching template '{filename}' with '{patch_file}'")) - ret = call(patch_cmd + patch_no_debug + ['-i', patch_file]) - if ret: # pragma: no cover - patch_cmd_err = ' '.join(patch_cmd + ['-i', patch_file]) - msg = _(f"Error applying patch: '{patch_file}'\n" - f"To reproduce and fix this error {patch_cmd_err}") - self.log.error(_(msg)) - copy(join(templates_dir, filename), self.tmp_dir) + for patches_dir in self.patches_dir: + patch_file = join(patches_dir, f'{filename}.patch') + if isfile(patch_file): + self.log.info(_("Patching template '{filename}' with '{patch_file}'")) + ret = call(patch_cmd + patch_no_debug + ['-i', patch_file]) + if ret: # pragma: no cover + patch_cmd_err = ' '.join(patch_cmd + ['-i', patch_file]) + msg = _(f"Error applying patch: '{patch_file}'\n" + f"To reproduce and fix this error {patch_cmd_err}") + self.log.error(_(msg)) + copy(join(templates_dir, filename), self.tmp_dir) def prepare_template(self, filename: str, @@ -362,65 +372,70 @@ class RougailBaseTemplate: except FileNotFoundError: ori_dir = None chdir(self.tmp_dir) - if not self.rougail_variables_dict: - await self.load_variables() - for templates_dir in self.templates_dir: - for template in listdir(templates_dir): - self.prepare_template(template, - templates_dir, - ) - files_to_delete = [] - for included in (True, False): - for service_obj in await self.config.option('services').list('all'): - service_name = await service_obj.option.description() - if await service_obj.option('activate').value.get() is False: - if included is False and not await service_obj.information.get('undisable', False): - self.desactive_service(service_name) - continue - if not included: - engine = await service_obj.information.get('engine', None) - if engine: - self.instance_file({'engine': engine}, - 'service', - service_name, - ) - target_name = await service_obj.information.get('target', None) - if target_name: - self.target_service(service_name, - target_name, - engine is None, - ) - for fills in await service_obj.list('optiondescription'): - type_ = await fills.option.name() - for fill_obj in await fills.list('all'): - fill = await fill_obj.value.dict() - self.get_default(type_, fill, fill_obj) - await self.get_informations(type_, fill, fill_obj) - if 'included' in fill: - if (fill['included'] == 'no' and included is True) or \ - (fill['included'] != 'no' and included is False): + try: + if not self.rougail_variables_dict: + await self.load_variables() + for templates_dir in self.templates_dir: + for template in listdir(templates_dir): + self.prepare_template(template, + templates_dir, + ) + files_to_delete = [] + for included in (True, False): + for service_obj in await self.config.option('services').list('all'): + service_name = await service_obj.option.description() + if await service_obj.option('activate').value.get() is False: + if included is False and not await service_obj.information.get('undisable', False): + self.desactive_service(service_name) + continue + if not included: + engine = await service_obj.information.get('engine', None) + if engine: + self.instance_file({'engine': engine}, + 'service', + service_name, + ) + target_name = await service_obj.information.get('target', None) + if target_name: + self.target_service(service_name, + target_name, + engine is None, + ) + for fills in await service_obj.list('optiondescription'): + type_ = await fills.option.name() + for fill_obj in await fills.list('all'): + fill = await fill_obj.value.dict() + self.get_default(type_, fill, fill_obj) + await self.get_informations(type_, fill, fill_obj) + if 'included' in fill: + if (fill['included'] == 'no' and included is True) or \ + (fill['included'] != 'no' and included is False): + continue + elif included is True: continue - elif included is True: - continue - if fill['activate']: - destfilenames = self.instance_file(fill, - type_, - service_name, - ) - if included and fill.get('included', 'no') == 'content': - files_to_delete.extend(destfilenames) - elif 'name' in fill: - self.log.debug(_(f"Instantiation of file '{fill['name']}' disabled")) - self.post_instance_service(service_name) - for filename in files_to_delete: - unlink(filename) - parent = filename - while True: - parent = dirname(parent) - if listdir(parent): - break - rmdir(parent) - self.post_instance() + if fill['activate']: + destfilenames = self.instance_file(fill, + type_, + service_name, + ) + if included and fill.get('included', 'no') == 'content': + files_to_delete.extend(destfilenames) + elif 'name' in fill: + self.log.debug(_(f"Instantiation of file '{fill['name']}' disabled")) + self.post_instance_service(service_name) + for filename in files_to_delete: + unlink(filename) + parent = filename + while True: + parent = dirname(parent) + if listdir(parent): + break + rmdir(parent) + self.post_instance() + except Exception as err: + if ori_dir is not None: + chdir(ori_dir) + raise err if ori_dir is not None: chdir(ori_dir) @@ -443,12 +458,21 @@ class RougailBaseTemplate: obj: 'Option', ) -> None: for key in INFORMATIONS.get(type_, []): - default_key = f'default_{type_}_{key}' - if default_key in RougailConfig: - default_value = RougailConfig[default_key] + if key == 'target': + default_value = None + elif key == 'undisable': + default_value = False + elif key == 'engine' and type_ == 'service_names': + default_value = None else: - default_value = undefined - dico[key] = await obj.information.get(key, default_value) + default_key = f'default_{type_}_{key}' + if default_key in RougailConfig: + default_value = RougailConfig[default_key] + else: + default_value = undefined + value = await obj.information.get(key, default_value) + if key not in ['target', 'undisable'] or value != default_value: + dico[key] = await obj.information.get(key, default_value) def desactive_service(self, *args, @@ -547,7 +571,7 @@ class RougailBaseTemplate: await suboption.option.name(), path, ) - variables[leadership_name] = RougailExtra(await optiondescription.option.name(), {leader_name: leader}, await optiondescription.option.path()) + variables[leadership_name] = RougailExtra(await option.option.name(), {leader_name: leader}, await option.option.path()) else: if is_service_namespace == 'root': new_is_service_namespace = 'service_name' @@ -567,16 +591,7 @@ class RougailBaseTemplate: if is_variable_namespace: value = await option.value.get() self.rougail_variables_dict[await option.option.name()] = value - if await option.option.issymlinkoption() and await option.option.isfollower(): - value = [] - if isinstance(self.config, TiramisuOption): - path = (await option.option.path())[len_root_path:] - else: - path = await option.option.path() - for index in range(await option.value.len()): - value.append(await self.config.option(path, index).value.get()) - else: - value = await option.value.get() + value = await option.value.get() variables[await option.option.name()] = value if isinstance(is_service_namespace, str) and is_service_namespace + 's' in INFORMATIONS: self.get_default(is_service_namespace + 's', diff --git a/tests/dictionaries/80remove_fill_no_fill/__init__.py b/tests/dictionaries/80remove_fill_no_fill/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/dictionaries/80remove_fill_no_fill/errno_89 b/tests/dictionaries/80remove_fill_no_fill/errno_89 new file mode 100644 index 000000000..e69de29bb diff --git a/tests/dictionaries/80remove_fill_no_fill/xml/00-base.xml b/tests/dictionaries/80remove_fill_no_fill/xml/00-base.xml new file mode 100644 index 000000000..f5c5edc5f --- /dev/null +++ b/tests/dictionaries/80remove_fill_no_fill/xml/00-base.xml @@ -0,0 +1,13 @@ + + + + + + oui + + + non + + + + diff --git a/tests/dictionaries/80remove_fill_no_fill/xml/01-base.xml b/tests/dictionaries/80remove_fill_no_fill/xml/01-base.xml new file mode 100644 index 000000000..88d820af8 --- /dev/null +++ b/tests/dictionaries/80remove_fill_no_fill/xml/01-base.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/dictionaries/80remove_fill_no_fill/yml/00-base.yml b/tests/dictionaries/80remove_fill_no_fill/yml/00-base.yml new file mode 100644 index 000000000..5916d3e46 --- /dev/null +++ b/tests/dictionaries/80remove_fill_no_fill/yml/00-base.yml @@ -0,0 +1,16 @@ +version: '0.10' +variables: +- family: + - name: general + variables: + - variable: + - name: mode_conteneur_actif + type: string + description: No change + value: + - text: oui + - name: mode_conteneur_actif1 + type: string + description: No change + value: + - text: non diff --git a/tests/dictionaries/80remove_fill_no_fill/yml/01-base.yml b/tests/dictionaries/80remove_fill_no_fill/yml/01-base.yml new file mode 100644 index 000000000..144cc714d --- /dev/null +++ b/tests/dictionaries/80remove_fill_no_fill/yml/01-base.yml @@ -0,0 +1,9 @@ +version: '0.10' +variables: +- family: + - name: general + variables: + - variable: + - name: mode_conteneur_actif + redefine: true + remove_fill: true