diff --git a/src/rougail/structural_directory/__init__.py b/src/rougail/structural_directory/__init__.py new file mode 100644 index 000000000..5939dae32 --- /dev/null +++ b/src/rougail/structural_directory/__init__.py @@ -0,0 +1,153 @@ +""" +Silique (https://www.silique.fr) +Copyright (C) 2022-2024 + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by the +Free Software Foundation, either version 3 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 Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +""" + +from typing import Union, List, Iterator, Optional +from itertools import chain +from pathlib import Path + +from ruamel.yaml import YAML + +from ..utils import normalize_family +from ..path import Paths + + +class Walker: + def __init__( + self, + convert, + ) -> None: + """Parse directories content""" + self.convert = convert + self.yaml = YAML() + rougailconfig = self.convert.rougailconfig + self.sort_dictionaries_all = rougailconfig["sort_dictionaries_all"] + if rougailconfig["main_namespace"]: + self.convert.paths = Paths(rougailconfig["main_namespace"]) + self.load_with_extra( + rougailconfig["extra_dictionaries"], + rougailconfig["main_namespace"], + rougailconfig["main_dictionaries"], + ) + else: + self.convert.namespace = None + namespace_path = "" + if namespace_path in self.convert.parents: + raise Exception("pfff") + for filename in self.get_sorted_filename( + rougailconfig["main_dictionaries"] + ): + self.parse_variable_file( + filename, + namespace_path, + ) + + def load_with_extra( + self, + extra_structures: dict, + main_namespace: Optional[str] = None, + main_structures: Optional[List[str]] = None, + ) -> None: + self.convert.has_namespace = True + if main_namespace: + directory_dict = chain( + ( + ( + main_namespace, + main_structures, + ), + ), + extra_structures.items(), + ) + else: + directory_dict = extra_structures.items() + for namespace, extra_dirs in directory_dict: + # if namespace is None: + # self.convert.namespace = namespace + # else: + self.convert.namespace = normalize_family(namespace) + namespace_path = self.convert.namespace + if namespace_path in self.convert.parents: + raise Exception("pfff") + for idx, filename in enumerate(self.get_sorted_filename(extra_dirs)): + if not idx: + # create only for the first file + self.convert.create_namespace(namespace, namespace_path) + self.parse_variable_file( + filename, + namespace_path, + ) + + def get_sorted_filename( + self, + directories: Union[str, List[str]], + ) -> Iterator[str]: + """Sort filename""" + if not isinstance(directories, list): + directories = [directories] + if self.sort_dictionaries_all: + filenames = {} + for directory_name in directories: + directory = Path(directory_name) + if not self.sort_dictionaries_all: + filenames = {} + if directory.is_file(): + self.get_filename(directory, filenames) + else: + for file_path in directory.iterdir(): + self.get_filename(file_path, filenames) + if not self.sort_dictionaries_all: + for filename in sorted(filenames): + yield filenames[filename] + if self.sort_dictionaries_all: + for filename in sorted(filenames): + yield filenames[filename] + + def get_filename(self, file_path, filenames: List[str]) -> None: + if file_path.suffix not in [".yml", ".yaml"]: + return + if file_path.name in filenames: + raise DictConsistencyError( + _("duplicate dictionary file name {0}").format(file_path.name), + 78, + [filenames[file_path.name][1]], + ) + filenames[file_path.name] = str(file_path) + + def parse_variable_file( + self, + filename: str, + path: str, + ) -> None: + """Parse file""" + with open(filename, encoding="utf8") as file_fh: + objects = self.yaml.load(file_fh) + version = self.convert.validate_file_version( + objects, + filename, + ) + if objects is None: + return + self.convert.parse_root_file( + filename, + path, + version, + objects, + ) + + +__all__ = ("Walker",) diff --git a/src/rougail/structural_directory/config.py b/src/rougail/structural_directory/config.py new file mode 100644 index 000000000..31839357a --- /dev/null +++ b/src/rougail/structural_directory/config.py @@ -0,0 +1,99 @@ +""" +Silique (https://www.silique.fr) +Copyright (C) 2024 + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by the +Free Software Foundation, either version 3 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 Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +""" + +from ..utils import _ + + +def get_rougail_config( + *, + backward_compatibility=True, +) -> dict: + if backward_compatibility: + main_namespace_default = "rougail" + else: + main_namespace_default = "null" + options = f"""main_dictionaries: + description: {_("Directories where dictionary files are placed")} + type: unix_filename + alternative_name: m + params: + allow_relative: True + test_existence: True + multi: true + disabled: + jinja: >- + {{% if 'directory' not in step.structural %}} + directory is not in step.structural + {{% endif %}} + +sort_dictionaries_all: + description: {_("Sort dictionaries from differents directories")} + negative_description: Sort dictionaries directory by directory + default: false + disabled: + jinja: >- + {{% if 'directory' not in step.structural %}} + directory is not in step.structural + {{% endif %}} + +main_namespace: + description: {_("Main namespace name")} + default: {main_namespace_default} + alternative_name: s + mandatory: false + disabled: + jinja: >- + {{% if 'directory' not in step.structural %}} + directory is not in step.structural + {{% endif %}} + +extra_dictionaries: + description: {_("Extra namespaces")} + type: leadership + disabled: + jinja: >- + {{% if 'directory' not in step.structural %}} + directory is not in step.structural + {{% endif %}} + + names: + description: {_("Extra namespace name")} + alternative_name: xn + multi: true + mandatory: false + + directories: + description: {_("Directories where extra dictionary files are placed")} + alternative_name: xd + type: unix_filename + params: + allow_relative: true + test_existence: true + types: + - directory + multi: true +""" + return { + "name": "directory", + "process": "structural", + "options": options, + "level": 5, + } + + +__all__ = "get_rougail_config"