""" Silique (https://www.silique.fr) Copyright (C) 2022-2025 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 Optional from ruamel.yaml import YAML from tiramisu.error import PropertiesOptionError, ConfigError from .config import OutPuts from .i18n import _ class RougailOutputDisplay: def __init__( self, config: "Config", metaconfig=None, *, rougailconfig: "RougailConfig" = None, user_data_errors: Optional[list] = None, user_data_warnings: Optional[list] = None, config_owner_is_path: bool = False, layer_datas=None, **kwargs, ) -> None: if rougailconfig is None: from rougail import RougailConfig rougailconfig = RougailConfig self.rougailconfig = rougailconfig self.config = config self.metaconfig = metaconfig self.layer_datas = layer_datas self.config_owner_is_path = config_owner_is_path self.errors = [] self.warnings = [] if user_data_errors is None: user_data_errors = [] self.user_data_errors = user_data_errors if user_data_warnings is None: user_data_warnings = [] self.user_data_warnings = user_data_warnings self.out = [] self.root = None def run(self) -> str: if self.root is None: self.root = self.get_root() self.is_mandatory = self.rougailconfig["display.mandatory"] self.show_secrets = self.rougailconfig["display.show_secrets"] return self.output.run() def print(self) -> None: return self.output.print() def get_root(self) -> None: yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) output_format = self.rougailconfig["display.output_format"] self.output = OutPuts().get()[output_format]( _("Variables:"), None, self, yaml, self.out, no_icon=True, ) return self.output def exporter(self) -> bool: if self.is_mandatory: ori_properties = self.config.property.exportation() self.config.property.read_write() if not self.user_data_errors and not self.errors: self.mandatories() self.config.property.importation(ori_properties) warnings = self.user_data_warnings + self.warnings if warnings: self.display_warnings(warnings) errors = self.user_data_errors + self.errors if errors: self.output.display_errors(errors) return False self.parse_options( self.config, self.root, ) if self.output.tree and self.output.tree.children: self.output.header() self.end() return True def mandatories(self) -> None: try: mandatories = self.config.value.mandatory() except (ConfigError, PropertiesOptionError) as err: self.errors.append(_("Error in config: {0}").format(err)) except ValueError as err: self.errors.append(str(err)) else: self.check_mandatories(mandatories) def check_mandatories(self, mandatories: list) -> None: options_with_error = [] options = [] for option in mandatories: try: option.value.get() except PropertiesOptionError: options_with_error.append(option) else: options.append(option) if options: self.errors.append( {_("The following variables are mandatory but have no value:"): self.options_to_dict(options)} ) elif options_with_error: self.errors.append( { _( "The following variables are inaccessible but are empty and mandatory:" ): self.options_to_dict(options_with_error), } ) def options_to_dict(self, mandatories: list): options = {} for option in mandatories: parents = [option] parent = option while True: parent = parent.parent() if parent.path() is None: break parents.insert(0, parent) current_options = options for child in parents: if child.isoptiondescription(): current_options = current_options.setdefault(child.description(), {}) else: current_options.setdefault(None, []).append(child.description()) return options def parse_options( self, conf, parent, ): for child in conf: if child.isoptiondescription(): if child.isleadership(): func = self.parse_leadership else: func = self.parse_options family = parent.add_family(child) func( child, family, ) else: parent.add_variable(child) def parse_leadership( self, leadership, parent, ) -> None: leader, *followers = list(leadership) leader_values = leader.value.get() followers_values = {idx: [] for idx in range(len(leader_values))} for follower in followers: followers_values[follower.index()].append(follower) for idx in followers_values: leader_obj = parent.add_family(leader) leader_obj.add_variable( leader, value=leader_values[idx], leader_index=idx, ) for follower in followers_values[idx]: leader_obj.add_variable(follower) def end(self): self.out.append(self.output.tree)