feat: document output

This commit is contained in:
egarette@silique.fr 2025-12-02 13:59:33 +01:00
parent 07a8478444
commit 62fb0eab60
6889 changed files with 45239 additions and 38336 deletions

22
README.fr.md Normal file
View file

@ -0,0 +1,22 @@
---
gitea: none
include_toc: true
---
[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
## Afficher les variables et les valeurs
> [!NOTE]
>
> Retrouver toutes les variables et leurs valeurs de votre configuration (structures et données utilisateurs). Des informations complémentaires sont disponibles, comme la valeur par défaut, le lieu de chargement de la valeur, ...\
> **Chemin** : display\
> *`désactivé`*\
> **Désactivé** : si display n'est pas défini dans "[Sélection pour sortie](#step.output)"
| Variable | Description | Valeur par défaut | Type | Validateur |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|--------------------------|
| **<a id="display.show_secrets" name="display.show_secrets">display.show_secrets</a>**<br/>**Ligne de commande** : <br/>&nbsp;--display.show_secrets<br/>&nbsp;--display.no-show_secrets<br/>**Variable d'environnement** : ROUGAILCLI_DISPLAY.SHOW_SECRETS | Voir les secrets plutôt que de les obscurcir. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | |
| **<a id="display.mandatory" name="display.mandatory">display.mandatory</a>**<br/>**Ligne de commande** : <br/>&nbsp;--display.mandatory<br/>&nbsp;--display.no-mandatory<br/>**Variable d'environnement** : ROUGAILCLI_DISPLAY.MANDATORY | Test les variables obligatoires avant de les afficher dans la display. | ne pas tester si "[Configuration in output step is in read_write mode](#cli.read_write)" est activé | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | |
| **<a id="display.max_width" name="display.max_width">display.max_width</a>**<br/>**Ligne de commande** : --display.max_width<br/>**Variable d'environnement** : ROUGAILCLI_DISPLAY.MAX_WIDTH | Nombre maximal de caractères par ligne.<br/>Null signifie illimité. | | [`integer`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | The minimum value is 50. |

View file

@ -1,2 +1,22 @@
# rougail-output-console
---
gitea: none
include_toc: true
---
[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
## Display variables and values
> [!NOTE]
>
> Find all the variables and their values in your configuration (structural and user datas). Additional informations are available, such as the default value, the location where the value is loaded, etc.\
> **Path**: display\
> *`disabled`*\
> **Disabled**: if display is not set in "[Select for output](#step.output)"
| Variable | Description | Default value | Type | Validator |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|--------------------------|
| **<a id="display.show_secrets" name="display.show_secrets">display.show_secrets</a>**<br/>**Command line**: <br/>&nbsp;--display.show_secrets<br/>&nbsp;--display.no-show_secrets<br/>**Environment variable**: ROUGAILCLI_DISPLAY.SHOW_SECRETS | Show secrets instead of obscuring them. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | |
| **<a id="display.mandatory" name="display.mandatory">display.mandatory</a>**<br/>**Command line**: <br/>&nbsp;--display.mandatory<br/>&nbsp;--display.no-mandatory<br/>**Environment variable**: ROUGAILCLI_DISPLAY.MANDATORY | Test mandatories variables before display in display. | do not test if "[Configuration in output step is in read_write mode](#cli.read_write)" is true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | |
| **<a id="display.max_width" name="display.max_width">display.max_width</a>**<br/>**Command line**: --display.max_width<br/>**Environment variable**: ROUGAILCLI_DISPLAY.MAX_WIDTH | Maximum number of characters per line.<br/>Null means unlimited. | | [`integer`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | The minimum value is 50. |

View file

@ -1,109 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2025-11-08 22:16+0100\n"
"PO-Revision-Date: 2025-11-08 22:17+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 3.7\n"
#: src/rougail/output_console/__init__.py:90
msgid "Error in config: {0}"
msgstr "Erreur dans la config : {0}"
#: src/rougail/output_console/__init__.py:120
msgid "The following variables are mandatory but have no value:"
msgstr "Les variables suivantes sont obligatoire mais n'ont pas de valeur :"
#: src/rougail/output_console/__init__.py:126
msgid "The following variables are inaccessible but are empty and mandatory:"
msgstr ""
"Les variables suivantes sont inaccessibles mais sont vides et obligatoires :"
#: src/rougail/output_console/__init__.py:212
msgid "Variable"
msgstr "Variable"
#: src/rougail/output_console/__init__.py:214
msgid "Undocumented variable"
msgstr "Variable non documentée"
#: src/rougail/output_console/__init__.py:216
msgid "Undocumented but modified variable"
msgstr "Variable non documentée mais modifiée"
#: src/rougail/output_console/__init__.py:218
msgid "Unmodifiable variable"
msgstr "Variable non modifiable"
#: src/rougail/output_console/__init__.py:221
msgid "Default value"
msgstr "Valeur par défaut"
#: src/rougail/output_console/__init__.py:223
msgid "Modified value"
msgstr "Valeur modifiée"
#: src/rougail/output_console/__init__.py:225
msgid "Original default value"
msgstr "Valeur par défaut d'origine"
#: src/rougail/output_console/__init__.py:229
msgid "Caption"
msgstr "Légende"
#: src/rougail/output_console/__init__.py:248
msgid "Layers"
msgstr "Couches"
#: src/rougail/output_console/__init__.py:255
msgid "ERRORS"
msgstr "ERREURS"
#: src/rougail/output_console/__init__.py:283
msgid "WARNINGS"
msgstr "AVERTISSEMENTS"
#: src/rougail/output_console/__init__.py:294
msgid "Variables:"
msgstr "Variables :"
#: src/rougail/output_console/__init__.py:325
#: src/rougail/output_console/__init__.py:485
msgid "{0}:"
msgstr "{0} :"
#: src/rougail/output_console/__init__.py:491
msgid "{0}: {1}"
msgstr "{0} : {1}"
#: src/rougail/output_console/config.py:30
msgid "Configuration for rougail-console"
msgstr "Configuration de rougail-console"
#: src/rougail/output_console/config.py:37
msgid "Show secrets instead of obscuring them"
msgstr "Voir les secrets plutôt que de les obscurcir"
#: src/rougail/output_console/config.py:40
msgid "test mandatories variables before display in console"
msgstr "Test les variables obligatoires avant de les afficher dans la console"
#: src/rougail/output_console/config.py:50
msgid ""
"In tree the key is the family or variable description inside of it's name"
msgstr ""
"Dans l'arborescence la clé est la description de la famille ou de la "
"variable au lieux de son nom"
#~ msgid "Display variables available in read_write mode"
#~ msgstr "Afficher les variables visible dans le mode lecture écriture"

View file

@ -0,0 +1,132 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2025-12-03 21:05+0100\n"
"PO-Revision-Date: 2025-12-03 21:06+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 3.8\n"
#: src/rougail/output_display/config.py:30
msgid "Display variables and values"
msgstr "Afficher les variables et les valeurs"
#: src/rougail/output_display/config.py:31
msgid ""
"Find all the variables and their values in your configuration (structural "
"and user datas). Additional informations are available, such as the default "
"value, the location where the value is loaded, etc."
msgstr ""
"Retrouver toutes les variables et leurs valeurs de votre configuration "
"(structures et données utilisateurs). Des informations complémentaires sont "
"disponibles, comme la valeur par défaut, le lieu de chargement de la "
"valeur, ..."
#: src/rougail/output_display/config.py:40
msgid "if display is not set in \"step.output\""
msgstr "si display n'est pas défini dans \"step.output\""
#: src/rougail/output_display/config.py:42
msgid "Show secrets instead of obscuring them"
msgstr "Voir les secrets plutôt que de les obscurcir"
#: src/rougail/output_display/config.py:45
msgid "test mandatories variables before display in display"
msgstr "test les variables obligatoires avant de les afficher dans la display"
#: src/rougail/output_display/config.py:54
msgid "do not test if \"cli.read_write\" is true"
msgstr "ne pas tester si \"cli.read_write\" est activé"
#: src/rougail/output_display/config.py:57
msgid "Maximum number of characters per line"
msgstr "Nombre maximal de caractères par ligne"
#: src/rougail/output_display/config.py:58
msgid "null means unlimited"
msgstr "null signifie illimité"
#: src/rougail/output_display/display.py:77
msgid "Variables:"
msgstr "Variables :"
#: src/rougail/output_display/display.py:114
msgid "Error in config: {0}"
msgstr "Erreur dans la config : {0}"
#: src/rougail/output_display/display.py:132
msgid "The following variables are mandatory but have no value:"
msgstr "Les variables suivantes sont obligatoire mais n'ont pas de valeur :"
#: src/rougail/output_display/display.py:137
msgid "The following variables are inaccessible but are empty and mandatory:"
msgstr ""
"Les variables suivantes sont inaccessibles mais sont vides et obligatoires :"
#: src/rougail/output_display/output/console.py:50
msgid "Variable"
msgstr "Variable"
#: src/rougail/output_display/output/console.py:52
msgid "Unmodifiable variable"
msgstr "Variable non modifiable"
#: src/rougail/output_display/output/console.py:55
msgid "Default value"
msgstr "Valeur par défaut"
#: src/rougail/output_display/output/console.py:57
msgid "Modified value"
msgstr "Valeur modifiée"
#: src/rougail/output_display/output/console.py:59
msgid "Original default value"
msgstr "Valeur par défaut d'origine"
#: src/rougail/output_display/output/console.py:63
msgid "Caption"
msgstr "Légende"
#: src/rougail/output_display/output/console.py:82
msgid "Layers"
msgstr "Couches"
#: src/rougail/output_display/output/console.py:86
msgid "ERRORS"
msgstr "ERREURS"
#: src/rougail/output_display/output/console.py:98
msgid "WARNINGS"
msgstr "AVERTISSEMENTS"
#: src/rougail/output_display/output/console.py:111
msgid "{0}:"
msgstr "{0} :"
#: src/rougail/output_display/output/console.py:117
msgid "{0}: {1}"
msgstr "{0} : {1}"
#~ msgid ""
#~ "In tree the key is the family or variable description inside of it's name"
#~ msgstr ""
#~ "Dans l'arborescence la clé est la description de la famille ou de la "
#~ "variable au lieux de son nom"
#~ msgid "Configuration for rougail-display"
#~ msgstr "Configuration de rougail-display"
#~ msgid "Undocumented variable"
#~ msgstr "Variable non documentée"
#~ msgid "Undocumented but modified variable"
#~ msgstr "Variable non documentée mais modifiée"

View file

@ -1,102 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2025-11-08 22:17+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
#: src/rougail/output_console/__init__.py:90
msgid "Error in config: {0}"
msgstr ""
#: src/rougail/output_console/__init__.py:120
msgid "The following variables are mandatory but have no value:"
msgstr ""
#: src/rougail/output_console/__init__.py:126
msgid "The following variables are inaccessible but are empty and mandatory:"
msgstr ""
#: src/rougail/output_console/__init__.py:212
msgid "Variable"
msgstr ""
#: src/rougail/output_console/__init__.py:214
msgid "Undocumented variable"
msgstr ""
#: src/rougail/output_console/__init__.py:216
msgid "Undocumented but modified variable"
msgstr ""
#: src/rougail/output_console/__init__.py:218
msgid "Unmodifiable variable"
msgstr ""
#: src/rougail/output_console/__init__.py:221
msgid "Default value"
msgstr ""
#: src/rougail/output_console/__init__.py:223
msgid "Modified value"
msgstr ""
#: src/rougail/output_console/__init__.py:225
msgid "Original default value"
msgstr ""
#: src/rougail/output_console/__init__.py:229
msgid "Caption"
msgstr ""
#: src/rougail/output_console/__init__.py:248
msgid "Layers"
msgstr ""
#: src/rougail/output_console/__init__.py:255
msgid "ERRORS"
msgstr ""
#: src/rougail/output_console/__init__.py:283
msgid "WARNINGS"
msgstr ""
#: src/rougail/output_console/__init__.py:294
msgid "Variables:"
msgstr ""
#: src/rougail/output_console/__init__.py:325
#: src/rougail/output_console/__init__.py:485
msgid "{0}:"
msgstr ""
#: src/rougail/output_console/__init__.py:491
msgid "{0}: {1}"
msgstr ""
#: src/rougail/output_console/config.py:30
msgid "Configuration for rougail-console"
msgstr ""
#: src/rougail/output_console/config.py:37
msgid "Show secrets instead of obscuring them"
msgstr ""
#: src/rougail/output_console/config.py:40
msgid "test mandatories variables before display in console"
msgstr ""
#: src/rougail/output_console/config.py:50
msgid "In tree the key is the family or variable description inside of it's name"
msgstr ""

View file

@ -0,0 +1,109 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2025-12-03 21:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
#: src/rougail/output_display/config.py:30
msgid "Display variables and values"
msgstr ""
#: src/rougail/output_display/config.py:31
msgid "Find all the variables and their values in your configuration (structural and user datas). Additional informations are available, such as the default value, the location where the value is loaded, etc."
msgstr ""
#: src/rougail/output_display/config.py:40
msgid "if display is not set in \"step.output\""
msgstr ""
#: src/rougail/output_display/config.py:42
msgid "Show secrets instead of obscuring them"
msgstr ""
#: src/rougail/output_display/config.py:45
msgid "test mandatories variables before display in display"
msgstr ""
#: src/rougail/output_display/config.py:54
msgid "do not test if \"cli.read_write\" is true"
msgstr ""
#: src/rougail/output_display/config.py:57
msgid "Maximum number of characters per line"
msgstr ""
#: src/rougail/output_display/config.py:58
msgid "null means unlimited"
msgstr ""
#: src/rougail/output_display/display.py:77
msgid "Variables:"
msgstr ""
#: src/rougail/output_display/display.py:114
msgid "Error in config: {0}"
msgstr ""
#: src/rougail/output_display/display.py:132
msgid "The following variables are mandatory but have no value:"
msgstr ""
#: src/rougail/output_display/display.py:137
msgid "The following variables are inaccessible but are empty and mandatory:"
msgstr ""
#: src/rougail/output_display/output/console.py:50
msgid "Variable"
msgstr ""
#: src/rougail/output_display/output/console.py:52
msgid "Unmodifiable variable"
msgstr ""
#: src/rougail/output_display/output/console.py:55
msgid "Default value"
msgstr ""
#: src/rougail/output_display/output/console.py:57
msgid "Modified value"
msgstr ""
#: src/rougail/output_display/output/console.py:59
msgid "Original default value"
msgstr ""
#: src/rougail/output_display/output/console.py:63
msgid "Caption"
msgstr ""
#: src/rougail/output_display/output/console.py:82
msgid "Layers"
msgstr ""
#: src/rougail/output_display/output/console.py:86
msgid "ERRORS"
msgstr ""
#: src/rougail/output_display/output/console.py:98
msgid "WARNINGS"
msgstr ""
#: src/rougail/output_display/output/console.py:111
msgid "{0}:"
msgstr ""
#: src/rougail/output_display/output/console.py:117
msgid "{0}: {1}"
msgstr ""

View file

@ -1,621 +0,0 @@
"""
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 <http://www.gnu.org/licenses/>.
"""
from typing import Any, List, Optional
from io import BytesIO
from rich.tree import Tree
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from ruamel.yaml import YAML
from tiramisu import owners
from tiramisu.error import PropertiesOptionError, ConfigError
from rougail.utils import undefined
from .i18n import _
from .__version__ import __version__
class RougailOutputConsole:
variable_hidden_color = "orange1"
variable_undocumented_color = "bright_blue"
variable_undocumented_and_modified_color = "red1"
value_unmodified_color = "gold1"
value_default_color = "green"
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.is_mandatory = self.rougailconfig["console.mandatory"]
self.show_secrets = self.rougailconfig["console.show_secrets"]
self.key_is_description = self.rougailconfig["console.key_is_description"]
try:
self.undocumented_modes = set(self.rougailconfig["console.undocumented_modes"])
except Exception:
self.undocumented_modes = set()
self.variable_default_enable = False
self.variable_hidden_enable = False
self.variable_undocumented_enable = False
self.variable_undocumented_and_modified_enable = False
self.value_modified_enable = False
self.value_unmodified_enable = False
self.value_default_enable = False
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.console = Console(force_terminal=True)
self.out = []
self.root = self.get_root()
def mandatory(self):
try:
mandatories = self.config.value.mandatory()
except (ConfigError, PropertiesOptionError) as err:
self.errors.append(_("Error in config: {0}").format(err))
return
except ValueError as err:
self.errors.append(str(err))
return
options_with_error = []
options = {}
for option in mandatories:
try:
option.value.get()
except PropertiesOptionError:
options_with_error.append(option)
else:
parent = self.config
current_options = options
for child_path in option.path().split("."):
child = parent.option(child_path)
if self.key_is_description:
description = child.description(uncalculated=True)
else:
description = child.path(uncalculated=True)
if child.isdynamic() and "{{ identifier }}" in description:
description = description.replace(
"{{ identifier }}", child.identifiers()[-1]
)
if child.isoptiondescription():
current_options = current_options.setdefault(description, {})
parent = child
else:
current_options.setdefault(None, []).append(description)
if options:
self.errors.append(
{_("The following variables are mandatory but have no value:"): options}
)
elif options_with_error:
if self.key_is_description:
variables = [option.description() for option in options_with_error]
else:
variables = [option.path() for option in options_with_error]
self.errors.append(
{
_(
"The following variables are inaccessible but are empty and mandatory:"
): variables
}
)
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.mandatory()
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.display_errors(errors)
return False
old_path_in_description = self.config.information.get(
"path_in_description", True
)
self.config.information.set("path_in_description", False)
self.parse_options(
self.config,
self.root,
)
self.config.information.set("path_in_description", old_path_in_description)
if self.output.tree.children:
self.header()
self.end()
return True
def run(self) -> str:
with self.console.capture() as capture:
ret = self.print()
return ret, capture.get()
def print(self) -> None:
ret = self.exporter()
for out in self.out:
self.console.print(out)
return ret
def parse_options(
self,
conf,
parent,
):
for option in conf:
if option.isoptiondescription():
family = parent.add_family(option)
if option.isleadership():
self.parse_leadership(
option,
family,
)
else:
self.parse_options(
option,
family,
)
else:
parent.add_variable(option)
def parse_leadership(
self,
conf,
parent,
):
leader, *followers = list(conf)
leader_values = leader.value.get()
for idx, leader_value in enumerate(leader_values):
leader_obj = parent.add_family(leader)
leader_obj.add_variable(
leader,
value=leader_value,
leader_index=idx,
)
for follower in followers:
if follower.index() != idx:
continue
leader_obj.add_variable(follower)
def header(self):
caption_line = ""
if self.variable_default_enable:
caption_line += _("Variable") + "\n"
if self.variable_undocumented_enable:
caption_line += f'[{self.variable_undocumented_color}]{_("Undocumented variable")}[/{self.variable_undocumented_color}]\n'
if self.variable_undocumented_and_modified_enable:
caption_line += f'[{self.variable_undocumented_and_modified_color}]{_("Undocumented but modified variable")}[/{self.variable_undocumented_and_modified_color}]\n'
if self.variable_hidden_enable:
caption_line += f'[{self.variable_hidden_color}]{_("Unmodifiable variable")}[/{self.variable_hidden_color}]\n'
header_value = ""
if self.value_unmodified_enable:
header_value = f'[{self.value_unmodified_color}]{_("Default value")}[/{self.value_unmodified_color}]\n'
if self.value_modified_enable:
header_value += _("Modified value") + "\n"
if self.value_default_enable:
header_value += f'([{self.value_default_color}]:hourglass_flowing_sand: {_("Original default value")}[/{self.value_default_color}])\n'
caption = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
caption.add_row(caption_line[:-1], header_value[:-1])
self.out.append(Panel.fit(caption, title=_("Caption")))
#
layers = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
if self.layer_datas:
max_len = 0
for datas in self.layer_datas.values():
for data in datas.values():
max_len = max(max_len, len(data))
display_layers = ["" for i in range(max_len)]
for datas in self.layer_datas.values():
for data in datas.values():
last_index = len(data) - 1
for idx in range(max_len):
if last_index < idx:
display_layers[idx] += "\n"
else:
display_layers[idx] += data[idx] + "\n"
layers.add_row(*[layer[:-1] for layer in display_layers])
self.out.append(Panel.fit(layers, title=_("Layers")))
def display_errors(
self,
errors,
) -> None:
tree = Tree(
f"[bold][bright_red]:stop_sign: {_('ERRORS')}[/bright_red][/bold]",
guide_style="bold bright_red",
)
for error in errors:
self.display_error(tree, error)
self.out.append(tree)
def display_error(self, tree, error):
if isinstance(error, list):
for err in error:
self.display_error(tree, err)
return tree
elif isinstance(error, dict):
for key, value in error.items():
if key is None:
# it's variables, no more families
self.display_error(tree, value)
else:
sub_tree = self.display_error(tree, key)
self.display_error(sub_tree, value)
else:
return tree.add(error)
def display_warnings(
self,
warnings: list,
) -> None:
tree = Tree(
f"[bold][bright_yellow]:bell: {_('WARNINGS')}[/bright_yellow][/bold]",
guide_style="bold bright_yellow",
)
for warning in warnings:
tree.add(warning)
self.out.append(tree)
def get_root(self) -> None:
yaml = YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
self.output = OutputFamily(
_("Variables:"),
None,
self,
yaml,
self.key_is_description,
self.undocumented_modes,
no_icon=True,
)
return self.output
def end(self):
self.out.append(self.output.tree)
class OutputFamily:
def __init__(
self,
family,
parent,
root,
_yaml,
key_is_description,
undocumented_modes,
*,
is_leader: bool = False,
no_icon: bool = False,
) -> None:
if parent is None:
tree = Tree
else:
tree = parent.add
if is_leader:
self.tree = tree(
":notebook: " + _("{0}:").format(family),
guide_style="bold bright_blue",
)
elif no_icon:
self.tree = tree(
f"{family}",
guide_style="bold bright_blue",
)
else:
self.tree = tree(
f":open_file_folder: {family}",
guide_style="bold bright_blue",
)
self.root = root
self._yaml = _yaml
self.key_is_description = key_is_description
self.undocumented_modes = undocumented_modes
def add_family(
self,
option,
) -> None:
properties = option.property.get()
if "hidden" in properties:
self.root.variable_hidden_enable = True
color = self.root.variable_hidden_color
elif self.undocumented_modes & properties:
self.root.variable_undocumented_enable = True
color = self.root.variable_undocumented_color
else:
self.root.variable_default_enable = True
color = None
if self.key_is_description:
key_name = option.description()
else:
key_name = option.name()
return OutputFamily(
self.colorize(
[
{
"value": key_name,
"color": color,
"loaded_from": None,
}
]
),
self.tree,
self.root,
self._yaml,
self.key_is_description,
self.undocumented_modes,
)
def add_variable(
self, option, value: Any = undefined, leader_index: Optional[int] = None
):
# value is undefined but not for leader variable
properties = option.property.get()
color = None
variable_color = None
undocumented = self.undocumented_modes & properties
hidden = False
if "hidden" in properties:
if undocumented:
self.root.variable_undocumented_enable = True
variable_color = self.root.variable_undocumented_color
else:
self.root.variable_hidden_enable = True
variable_color = self.root.variable_hidden_color
elif undocumented:
self.root.variable_undocumented_and_modified_enable = True
variable_color = self.root.variable_undocumented_and_modified_color
else:
self.root.variable_default_enable = True
values = []
collect_values = []
if not option.owner.isdefault():
self.root.value_modified_enable = True
follower_index = option.index()
if follower_index is not None:
loaded_from = option.information.get(
f"loaded_from_{follower_index}", None
)
else:
loaded_from = option.information.get("loaded_from", None)
if value is undefined:
value = option.value.get()
values.append(
{
"value": value,
"color": color,
"loaded_from": loaded_from,
}
)
suboption = option
subconfig = self.root.config
if "force_store_value" not in option.property.get() and option.information.get(
"default_value_makes_sense", True
):
while True:
default_value = suboption.value.default()
if leader_index is not None:
if len(default_value) > leader_index:
default_value = default_value[leader_index]
else:
default_value = None
is_root_metaconfig = False
if (
subconfig is None
or not subconfig.path()
or "." not in subconfig.path()
):
is_root_metaconfig = True
subconfig = self.get_subconfig_with_default_value(suboption)
if (
(values and default_value is None) or default_value == []
) and is_root_metaconfig:
break
if not values:
self.root.value_unmodified_enable = True
color = self.root.value_unmodified_color
else:
self.root.value_default_enable = True
color = self.root.value_default_color
index = option.index()
parent_option = subconfig.option(option.path(), index)
if is_root_metaconfig:
loaded_from = None
else:
parent_option = subconfig.option(option.path(), index)
if index is not None:
key = f"loaded_from_{index}"
else:
key = "loaded_from"
loaded_from = parent_option.information.get(key, None)
values.append(
{
"value": default_value,
"color": color,
"loaded_from": loaded_from,
}
)
if is_root_metaconfig:
break
elif not values:
if leader_index is None and option.index() is not None:
if not option.isfollower() or not option.issubmulti():
default_value = None
else:
default_value = []
else:
default_value = None
if not values:
self.root.value_unmodified_enable = True
color = self.root.value_unmodified_color
else:
self.root.value_default_enable = True
color = self.root.value_default_color
values.append(
{
"value": None,
"color": color,
"loaded_from": loaded_from,
}
)
if self.key_is_description:
key_name = option.description()
else:
key_name = option.name()
key = self.colorize(
[
{
"value": key_name,
"color": variable_color,
"loaded_from": None,
}
]
)
value = self.colorize(
values,
option,
)
if isinstance(value, list):
subtree = self.tree.add(
":notebook: " + _("{0}:").format(key),
guide_style="bold bright_blue",
)
for val in value:
subtree.add(str(val))
else:
self.tree.add(":notebook: " + _("{0}: {1}").format(key, value))
def get_subconfig_with_default_value(self, suboption):
default_owner = suboption.owner.default()
if default_owner == owners.default:
return self.root.config
if not self.root.config_owner_is_path:
subconfig = self.root.config
while True:
subconfig = subconfig.parent()
if not subconfig.owner.isdefault():
break
else:
subconfig = self.root.metaconfig
for child in default_owner.split(".")[1:]:
subconfig = subconfig.config(child)
return subconfig
def colorize(
self,
values,
option=None,
) -> str:
multi = False
ret = []
default = []
for idx, data in enumerate(values):
value = data["value"]
if isinstance(value, list):
multi = True
else:
value = [value]
for vidx, val in enumerate(value):
if len(ret) == vidx:
ret.append("")
default.append(False)
if idx:
if not default[vidx]:
if ret[vidx]:
ret[vidx] += " "
ret[vidx] += "("
default[vidx] = True
else:
ret[vidx] += " "
ret[vidx] += ":hourglass_flowing_sand: "
if option:
val = self.convert_value(
option,
val,
)
color = data["color"]
if color is not None:
ret[vidx] += f"[{color}]{val}[/{color}]"
else:
ret[vidx] += val
loaded_from = data["loaded_from"]
if loaded_from:
ret[vidx] += f" :arrow_backward: {loaded_from}"
for idx in range(len(ret)):
if default[idx]:
ret[idx] += ")"
if not multi:
if not ret:
return ""
return ret[0]
return ret
def convert_value(
self,
option,
value: Any,
) -> str:
"""Dump variable, means transform bool, ... to yaml string"""
if (
value is not None
and not self.root.show_secrets
and option.type() == "password"
):
return "*" * 10
if isinstance(value, str):
return value
with BytesIO() as ymlfh:
self._yaml.dump(value, ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip()
if ret.endswith("..."):
ret = ret[:-3].strip()
return ret
RougailOutput = RougailOutputConsole
__all__ = ("RougailOutputConsole",)

View file

@ -1,77 +0,0 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-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 <http://www.gnu.org/licenses/>.
"""
from pathlib import Path
from .i18n import _
def get_rougail_config(
*,
backward_compatibility=True,
) -> dict:
options = f"""
console:
description: {_('Configuration for rougail-console')}
disabled:
jinja: |
{{% if step.output is propertyerror or step.output != 'console' %}}
disabled
{{% endif %}}
show_secrets: false # {_('Show secrets instead of obscuring them')}
mandatory:
description: {_('test mandatories variables before display in console')}
type: boolean
default:
jinja: |-
{{% if cli.read_write is defined and cli.read_write %}}
false
{{% else %}}
true
{{% endif %}}
key_is_description: true # {_("In tree the key is the family or variable description inside of it's name")}
undocumented_modes:
description: {_('Variables with those modes are not documented')}
multi: true
mandatory: false
disabled:
jinja: |
{{% if not modes_level %}}
there is no mode
{{% endif %}}
description: {_('disabled when there is no mode available')}
validators:
- jinja: |
{{% if _.undocumented_modes not in modes_level %}}
this mode is not available
{{% endif %}}
description: {_('verify if disable modes already exists')}
"""
return {
"name": "console",
"process": "output",
"options": options,
"level": 40,
}
__all__ = ("get_rougail_config",)

View file

@ -0,0 +1,24 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 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 <http://www.gnu.org/licenses/>.
"""
from .display import RougailOutputDisplay
from .__version__ import __version__
RougailOutput = RougailOutputDisplay
__all__ = ("RougailOutputDisplay",)

View file

@ -0,0 +1,72 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-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 <http://www.gnu.org/licenses/>.
"""
from pathlib import Path
from .i18n import _
def get_rougail_config(
*,
backward_compatibility=True,
) -> dict:
options = f"""
display:
description: {_('Display variables and values')}
help: {_('Find all the variables and their values in your configuration (structural and user datas). Additional informations are available, such as the default value, the location where the value is loaded, etc.')}
disabled:
jinja: |-
{{% if step.output is propertyerror or step.output != 'display' %}}
true
{{% else %}}
false
{{% endif %}}
return_type: boolean
description: {_('if display is not set in "step.output"')}
show_secrets: false # {_('Show secrets instead of obscuring them')}
mandatory:
description: {_('test mandatories variables before display in display')}
type: boolean
default:
jinja: |-
{{% if cli.read_write is defined and cli.read_write == true %}}
false
{{% else %}}
true
{{% endif %}}
description: {_('do not test if "cli.read_write" is true')}
max_width:
description: {_("Maximum number of characters per line")}
help: {_('null means unlimited')}
type: integer
mandatory: false
params:
min_integer: 50
"""
return {
"name": "display",
"process": "output",
"options": options,
"level": 40,
}
__all__ = ("get_rougail_config",)

View file

@ -0,0 +1,201 @@
"""
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 <http://www.gnu.org/licenses/>.
"""
from typing import Optional
from ruamel.yaml import YAML
from tiramisu.error import PropertiesOptionError, ConfigError
from .i18n import _
from .output.console import OutputFamily
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:
ret = self.exporter()
self.output.print()
return ret
def get_root(self) -> None:
yaml = YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
self.output = OutputFamily(
_("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)

View file

@ -20,7 +20,7 @@ from gettext import translation
from pathlib import Path
t = translation(
"rougail_output_console", str(Path(__file__).parent / "locale"), fallback=True
"rougail_output_display", str(Path(__file__).parent / "locale"), fallback=True
)
_ = t.gettext

View file

@ -0,0 +1,190 @@
"""
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 <http://www.gnu.org/licenses/>.
"""
from rich.console import Console
from rich.tree import Tree
from rich.table import Table
from rich.panel import Panel
from ..i18n import _
from ..util import CommonOutput
class OutputFamily(CommonOutput):
variable_hidden_color = "orange1"
variable_normal_color = None
value_unmodified_color = "gold1"
value_modified_color = "green"
value_default_color = None
def run(self):
max_width = self.root.rougailconfig["display.max_width"]
self.console = Console(force_terminal=True, width=max_width)
with self.console.capture() as capture:
ret = self.root.print()
return ret, capture.get()
def print(self) -> None:
for out in self.out:
self.console.print(out)
def header(self):
caption_line = ""
if self.root_family.variable_default_enable:
caption_line += _("Variable") + "\n"
if self.root_family.variable_hidden_enable:
caption_line += f'[{self.variable_hidden_color}]{_("Unmodifiable variable")}[/{self.variable_hidden_color}]\n'
header_value = ""
if self.root_family.value_unmodified_enable:
header_value = f'[{self.value_unmodified_color}]{_("Default value")}[/{self.value_unmodified_color}]\n'
if self.root_family.value_modified_enable:
header_value += f'[{self.value_modified_color}]{_("Modified value")}[/{self.value_modified_color}]\n'
if self.root_family.value_default_enable:
header_value += f'(:hourglass_flowing_sand: {_("Original default value")})\n'
caption = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
caption.add_row(caption_line[:-1], header_value[:-1])
self.out.append(Panel.fit(caption, title=_("Caption")))
#
layers = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
if self.root.layer_datas:
max_len = 0
for datas in self.root.layer_datas.values():
for data in datas.values():
max_len = max(max_len, len(data))
display_layers = ["" for i in range(max_len)]
for datas in self.root.layer_datas.values():
for data in datas.values():
last_index = len(data) - 1
for idx in range(max_len):
if last_index < idx:
display_layers[idx] += "\n"
else:
display_layers[idx] += data[idx] + "\n"
layers.add_row(*[layer[:-1] for layer in display_layers])
self.out.append(Panel.fit(layers, title=_("Layers")))
def error_header(self):
return Tree(
f"[bold][bright_red]:stop_sign: {_('ERRORS')}[/bright_red][/bold]",
guide_style="bold bright_red",
)
def display_error(self, tree, error):
return tree.add(error)
def display_warnings(
self,
warnings: list,
) -> None:
tree = Tree(
f"[bold][bright_yellow]:bell: {_('WARNINGS')}[/bright_yellow][/bold]",
guide_style="bold bright_yellow",
)
for warning in warnings:
tree.add(warning)
self.out.append(tree)
def add_variable(
self, *args, **kwargs,
):
key, value = super().add_variable(*args, **kwargs)
if isinstance(value, list):
subtree = self.get_tree().add(
":notebook: " + _("{0}:").format(key),
guide_style="bold bright_blue",
)
for val in value:
subtree.add(str(val))
else:
self.get_tree().add(":notebook: " + _("{0}: {1}").format(key, value))
def colorize(
self,
values,
option=None,
) -> str:
multi = False
ret = []
default = []
for idx, data in enumerate(values):
value = data["value"]
if isinstance(value, list):
multi = True
else:
value = [value]
for vidx, val in enumerate(value):
if len(ret) == vidx:
ret.append("")
default.append(False)
if idx:
if not default[vidx]:
if ret[vidx]:
ret[vidx] += " "
ret[vidx] += "("
default[vidx] = True
else:
ret[vidx] += " "
ret[vidx] += ":hourglass_flowing_sand: "
if option:
val = self.convert_value(
option,
val,
)
color = data["color"]
if color is not None:
ret[vidx] += f"[{color}]{val}[/{color}]"
else:
ret[vidx] += val
loaded_from = data["loaded_from"]
if loaded_from:
ret[vidx] += f" :arrow_backward: {loaded_from}"
for idx in range(len(ret)):
if default[idx]:
ret[idx] += ")"
if not multi:
if not ret:
return ""
return ret[0]
return ret
def get_tree(self):
if self.tree is None:
if self.parent is None:
tree = Tree
else:
tree = self.parent.add
# if self.is_leader:
# self.tree = tree(
# ":notebook: " + _("{0}:").format(self.family),
# guide_style="bold bright_blue",
# )
# elif self.no_icon:
if self.no_icon:
self.tree = tree(
self.family,
guide_style="bold bright_blue",
)
else:
self.tree = tree(
f":open_file_folder: {self.family}",
guide_style="bold bright_blue",
)
return self.tree

View file

@ -0,0 +1,280 @@
"""
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 <http://www.gnu.org/licenses/>.
"""
from typing import Any, Optional
from io import BytesIO
from tiramisu import owners
from rougail.utils import undefined
class CommonOutput:
def __init__(
self,
family,
parent,
root,
_yaml,
out,
*,
# is_leader: bool = False,
root_family: Optional["OutputFamily"] = None,
no_icon: bool = False,
) -> None:
self.tree = None
self.root = root
self.parent = parent
if isinstance(family, tuple):
raise Exception()
self.family = family
# self.is_leader = is_leader
self.no_icon = no_icon
self._yaml = _yaml
self.out = out
if root_family is None:
root_family = self
self.variable_default_enable = False
self.variable_hidden_enable = False
self.value_modified_enable = False
self.value_unmodified_enable = False
self.value_default_enable = False
self.root_family = root_family
def header(self):
raise NotImplementedError()
def display_errors(
self,
errors,
) -> None:
tree = self.error_header()
for error in errors:
self.parse_error(tree, error)
self.out.append(tree)
def parse_error(self, tree, error):
if isinstance(error, list):
for err in error:
self.parse_error(tree, err)
return tree
elif isinstance(error, dict):
for key, value in error.items():
if key is None:
# it's variables, no more families
self.parse_error(tree, value)
else:
sub_tree = self.parse_error(tree, key)
self.parse_error(sub_tree, value)
else:
return self.display_error(tree, error)
def add_family(
self,
family,
) -> 'OutputFamily':
properties = family.property.get()
if "hidden" in properties:
self.root_family.variable_hidden_enable = True
color = self.variable_hidden_color
else:
self.root_family.variable_default_enable = True
color = None
family_output = self.colorize(
[
{
"value": family.description(),
"color": color,
"loaded_from": None,
}
]
)
return self.__class__(
family_output,
self.get_tree(),
self.root,
self._yaml,
self.out,
root_family = self.root_family,
)
def add_variable(
self, option, value: Any = undefined, leader_index: Optional[int] = None
):
values = []
properties = option.property.get()
if not option.owner.isdefault() and option.information.get(
"default_value_makes_sense", True
):
self.get_modified_value(option, value, values)
if "force_store_value" not in properties or not values:
self.get_default_values(option, values, leader_index)
#
if "hidden" in properties:
self.root_family.variable_hidden_enable = True
variable_color = self.variable_hidden_color
else:
self.root_family.variable_default_enable = True
variable_color = self.variable_normal_color
key = self.colorize(
[
{
"value": option.description(),
"color": variable_color,
"loaded_from": None,
}
]
)
value = self.colorize(
values,
option,
)
return key, value
def get_modified_value(self, option: "Option", value: Any, values: list) -> None:
self.root_family.value_modified_enable = True
follower_index = option.index()
if follower_index is not None:
loaded_from = option.information.get(
f"loaded_from_{follower_index}", None
)
else:
loaded_from = option.information.get("loaded_from", None)
if value is undefined:
value = option.value.get()
values.append(
{
"value": value,
"color": self.value_modified_color,
"loaded_from": loaded_from,
}
)
def get_default_values(self, option: "Option", values: list, leader_index: Optional[int]) -> None:
meta_config = self.root.config
meta_option = option
index = option.index()
while True:
default_value = meta_option.value.default()
if leader_index is not None:
if len(default_value) > leader_index:
default_value = default_value[leader_index]
else:
default_value = None
is_root_metaconfig = False
if (
meta_config is None
or not meta_config.path()
or "." not in meta_config.path()
):
is_root_metaconfig = True
if (
(values and default_value is None) or default_value == []
) and is_root_metaconfig:
break
if not values:
self.root_family.value_unmodified_enable = True
color = self.value_unmodified_color
else:
self.root_family.value_default_enable = True
color = self.value_default_color
meta_config = self.get_subconfig_with_default_value(meta_option)
meta_option = meta_config.option(option.path(), index)
if is_root_metaconfig:
loaded_from = None
else:
if index is not None:
key = f"loaded_from_{index}"
else:
key = "loaded_from"
loaded_from = meta_option.information.get(key, None)
values.append(
{
"value": default_value,
"color": color,
"loaded_from": loaded_from,
}
)
if is_root_metaconfig:
break
#
# def get_default_value(self, option: "Option", values: list, leader_index: Optional[int]) -> None:
# follower_index = option.index()
## if leader_index is None and follower_index is not None:
## if not option.isfollower() or not option.issubmulti():
## default_value = None
## else:
## default_value = []
## else:
## default_value = None
# if not values:
# self.root_family.value_unmodified_enable = True
# color = self.value_unmodified_color
# else:
# self.root_family.value_default_enable = True
# color = self.value_default_color
# if follower_index is not None:
# loaded_from = option.information.get(
# f"loaded_from_{follower_index}", None
# )
# else:
# loaded_from = option.information.get("loaded_from", None)
# values.append(
# {
# "value": default_value,
# "color": color,
# "loaded_from": loaded_from,
# }
# )
def get_subconfig_with_default_value(self, config):
default_owner = config.owner.default()
if default_owner == owners.default:
return self.root.config
if not self.root.config_owner_is_path:
meta_config = self.root.config
while True:
meta_config = meta_config.parent()
if not meta_config.owner.isdefault():
break
else:
meta_config = self.root.metaconfig
for child in default_owner.split(".")[1:]:
meta_config = meta_config.config(child)
return meta_config
def convert_value(
self,
option,
value: Any,
) -> str:
"""Dump variable, means transform bool, ... to yaml string"""
if (
value is not None
and not self.root.show_secrets
and option.type() == "password"
):
return "*" * 10
if isinstance(value, str):
return value
with BytesIO() as ymlfh:
self._yaml.dump(value, ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip()
if ret.endswith("..."):
ret = ret[:-3].strip()
return ret

View file

@ -0,0 +1,3 @@
🛑 ERRORS
┗━━ The following variables are inaccessible but are empty and mandatory:
 ┗━━ please set a value

View file

@ -0,0 +1,5 @@
🛑 ERRORS
┗━━ The following variables are inaccessible but are empty and mandatory:
 ┗━━ family1
  ┗━━ family2
   ┗━━ please set a value

View file

@ -0,0 +1,12 @@
%YAML 1.2
---
version: 1.1
family1:
hidden: true
family2:
mandatory_variable:
description: please set a value
...

View file

@ -0,0 +1,5 @@
🛑 ERRORS
┗━━ The following variables are mandatory but have no value:
 ┗━━ family1
  ┗━━ family2
   ┗━━ please set a value

View file

@ -0,0 +1,11 @@
%YAML 1.2
---
version: 1.1
family1:
family2:
mandatory_variable:
description: please set a value
...

View file

@ -0,0 +1,5 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,5 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 empty: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,10 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test (⏳ no)
┗━━ 📓 a second variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ string1)
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,13 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ no)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ yes)
┃ ┗━━ string3 ◀ loaded from rougail-test (⏳ maybe)
┗━━ 📓 a second variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ string1)
 ┣━━ string2 ◀ loaded from rougail-test (⏳ string2)
 ┗━━ string3 ◀ loaded from rougail-test (⏳ string3)

View file

@ -0,0 +1,11 @@
╭───────────────────── Caption ─────────────────────╮
│ Variable Default value │
Unmodifiable variable Modified value │
(⏳ Original default value)
╰───────────────────────────────────────────────────╯
Variables:
┣━━ 📂 leadership
┃ ┗━━ 📂 a first variable
┃  ┣━━ 📓 a first variable: a_value
┃  ┗━━ 📓 a first variable: a_value
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test (⏳ a_value)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable:
┃ ┣━━ domain1.lan ◀ loaded from rougail-test
┃ ┗━━ domain2.lan ◀ loaded from rougail-test
┗━━ 📓 a second variable:
 ┣━━ domain1.lan ◀ loaded from rougail-test (⏳ domain1.lan)
 ┗━━ domain2.lan ◀ loaded from rougail-test (⏳ domain2.lan)

View file

@ -0,0 +1,7 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test (⏳ string1)

View file

@ -0,0 +1,8 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test
┣━━ 📓 a second variable: string1 ◀ loaded from rougail-test (⏳ string1)
┗━━ 📓 a new variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable:
┃ ┣━━ domain1.lan ◀ loaded from rougail-test
┃ ┗━━ domain2.lan ◀ loaded from rougail-test
┗━━ 📓 a second variable:
 ┣━━ domain1.lan ◀ loaded from rougail-test (⏳ domain1.lan)
 ┗━━ domain2.lan ◀ loaded from rougail-test (⏳ domain2.lan)

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 a variable: string1 ◀ loaded from rougail-test
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ non)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: true ◀ loaded from rougail-test (true)
┣━━ 📓 the second variable: true ◀ loaded from rougail-test (true)
┣━━ 📓 the third variable: true ◀ loaded from rougail-test (true)
┣━━ 📓 the forth variable: true ◀ loaded from rougail-test (false)
┣━━ 📓 the fifth variable: true ◀ loaded from rougail-test (false)
┗━━ 📓 the sixth variable: true ◀ loaded from rougail-test (false)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: true ◀ loaded from rougail-test (true)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: a ◀ loaded from rougail-test
┣━━ 📓 the second variable: a ◀ loaded from rougail-test
┣━━ 📓 the third variable: a ◀ loaded from rougail-test
┣━━ 📓 the forth variable: null ◀ loaded from rougail-test
┣━━ 📓 the fifth variable: a ◀ loaded from rougail-test (⏳ a)
┗━━ 📓 the sixth variable: 1 ◀ loaded from rougail-test (⏳ 1)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: 0 ◀ loaded from rougail-test (⏳ 9)

View file

@ -0,0 +1,7 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: a ◀ loaded from rougail-test
┗━━ 📓 the second variable: a ◀ loaded from rougail-test (⏳ a)

View file

@ -0,0 +1,10 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a second variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ a)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ b)
┃ ┗━━ string3 ◀ loaded from rougail-test (⏳ c)
┗━━ 📓 a first variable: string1 ◀ loaded from rougail-test (⏳ a)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a second variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ a)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ b)
┃ ┗━━ string3 ◀ loaded from rougail-test (⏳ c)
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test (⏳ a)
┗━━ 📓 a third variable: string1 ◀ loaded from rougail-test (⏳ string1)

View file

@ -0,0 +1,12 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a second variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ a)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ b)
┃ ┗━━ string3 ◀ loaded from rougail-test (⏳ c)
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test (⏳ a)
┗━━ 📂 family
 ┗━━ 📓 a third variable: string1 ◀ loaded from rougail-test (⏳ string1)

View file

@ -0,0 +1,7 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 the seconf variable: string1 ◀ loaded from rougail-test (⏳ value)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a domain name variable: domain1.lan ◀ loaded from rougail-test (⏳ my.domain.name)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a domain name variable: domain1.lan ◀ loaded from rougail-test (⏳ my.domain.name)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┣━━ 📓 the second variable: 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┣━━ 📓 the third variable: 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┣━━ 📓 the forth variable: 1.1 ◀ loaded from rougail-test (⏳ 10.1)
┣━━ 📓 the fifth variable: 1.1 ◀ loaded from rougail-test (⏳ 10.1)
┗━━ 📓 the sixth variable: 1.1 ◀ loaded from rougail-test (⏳ 10.1)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: 1 ◀ loaded from rougail-test (⏳ 0)
┣━━ 📓 the second variable: 1 ◀ loaded from rougail-test (⏳ 0)
┣━━ 📓 the third variable: 1 ◀ loaded from rougail-test (⏳ 0)
┣━━ 📓 this forth variable: 1 ◀ loaded from rougail-test (⏳ 10)
┣━━ 📓 the fifth variable: 1 ◀ loaded from rougail-test (⏳ 10)
┗━━ 📓 the sixth variable: 1 ◀ loaded from rougail-test (⏳ 10)

View file

@ -0,0 +1,8 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 an IP: 192.168.1.6 ◀ loaded from rougail-test (⏳ 1.1.1.1)
┣━━ 📓 an IP in CIDR format: 192.168.1.6/24 ◀ loaded from rougail-test (⏳ 1.1.1.1/24)
┗━━ 📓 an IP in CIDR format with obsolete CIDR type: 192.168.1.6/24 ◀ loaded from rougail-test (⏳ 1.1.1.1/24)

View file

@ -0,0 +1,8 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 an network: 192.168.1.0 ◀ loaded from rougail-test (⏳ 1.1.1.0)
┣━━ 📓 an network in CIDR format: 192.168.1.6/32 ◀ loaded from rougail-test (⏳ 1.1.1.0/24)
┗━━ 📓 an network in CIDR format with obsolete CIDR type: 192.168.1.6/32 ◀ loaded from rougail-test (⏳ 1.1.1.0/24)

View file

@ -0,0 +1,11 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: 1 ◀ loaded from rougail-test (⏳ 0)
┣━━ 📓 the second variable: 1 ◀ loaded from rougail-test (⏳ 0)
┣━━ 📓 the third variable: 1 ◀ loaded from rougail-test (⏳ 0)
┣━━ 📓 this forth variable: 1 ◀ loaded from rougail-test (⏳ 10)
┣━━ 📓 the fifth variable: 1 ◀ loaded from rougail-test (⏳ 10)
┗━━ 📓 the sixth variable: 1 ◀ loaded from rougail-test (⏳ 10)

View file

@ -0,0 +1,8 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a port variable: 80 ◀ loaded from rougail-test
┣━━ 📓 a port variable with default value: 80 ◀ loaded from rougail-test (⏳ 8080)
┗━━ 📓 a port variable with integer default value: 80 ◀ loaded from rougail-test (⏳ 8080)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a first variable: #b1b1b1 ◀ loaded from rougail-test (#a1a1a1)

View file

@ -0,0 +1,7 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable: #b1b1b1 ◀ loaded from rougail-test (#a1a1a1)
┗━━ 📓 a second variable: #b2b1b1 ◀ loaded from rougail-test (#b1b1b1)

View file

@ -0,0 +1,7 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: onE7vaLues_len1 ◀ loaded from rougail-test
┗━━ 📓 the second variable: onE7vaLues_len1 ◀ loaded from rougail-test (⏳ value)

View file

@ -0,0 +1,8 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: onE7vaLues_len1 ◀ loaded from rougail-test
┣━━ 📓 the second variable: onE7vaLues ◀ loaded from rougail-test (⏳ value)
┗━━ 📓 the third variable: onE7vaLues ◀ loaded from rougail-test (⏳ value)

View file

@ -0,0 +1,13 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: string1 ◀ loaded from rougail-test
┣━━ 📓 the second variable: string1 ◀ loaded from rougail-test
┣━━ 📓 the third variable: string1 ◀ loaded from rougail-test
┣━━ 📓 the forth variable: string1 ◀ loaded from rougail-test (⏳ value)
┣━━ 📓 the fifth variable: string1 ◀ loaded from rougail-test (⏳ value)
┣━━ 📓 the sixth variable: string1 ◀ loaded from rougail-test (⏳ value)
┣━━ 📓 the seventh variable: string1 ◀ loaded from rougail-test (⏳ 8080)
┗━━ 📓 the height variable: string1 ◀ loaded from rougail-test (true)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 A choice: quote' ◀ loaded from rougail-test (⏳ quote')

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 the first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 the second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 the first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 the second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 the first <variable>: string1 ◀ loaded from rougail-test
┗━━ 📓 the second <variable>: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ quote")

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ quote'")

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ quote\"\')

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ quote')

View file

@ -0,0 +1,5 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,13 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable: test ◀ loaded from rougail-test
┣━━ 📓 the second variable: test ◀ loaded from rougail-test (⏳ value)
┣━━ 📓 the third variable: test1 ◀ loaded from rougail-test
┣━━ 📓 the forth variable: null ◀ loaded from rougail-test
┣━━ 📓 the fifth variable: false ◀ loaded from rougail-test (true)
┗━━ 📓 the sixth variable:
 ┣━━ test1 ◀ loaded from rougail-test
 ┗━━ test2 ◀ loaded from rougail-test

View file

@ -0,0 +1,10 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 a first variable:
┃ ┣━━ val1 ◀ loaded from rougail-test
┃ ┗━━ val2 ◀ loaded from rougail-test
┗━━ 📓 a second variable:
 ┣━━ val1 ◀ loaded from rougail-test
 ┗━━ val2 ◀ loaded from rougail-test

View file

@ -0,0 +1,8 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first source variable: string1 ◀ loaded from rougail-test (⏳ val1)
┣━━ 📓 the second source variable: string1 ◀ loaded from rougail-test (⏳ val2)
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ val1)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test (⏳ string_1_True_)

View file

@ -0,0 +1,5 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 a variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,10 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 my_variable: string1 ◀ loaded from rougail-test (⏳ val1)
┗━━ 📓 my_calculated_variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ string1)
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,10 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 my_variable: string1 ◀ loaded from rougail-test (⏳ val1)
┗━━ 📓 my_calculated_variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ string1)
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,10 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 my_variable: string1 ◀ loaded from rougail-test (⏳ val1)
┗━━ 📓 my_calculated_variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ string1)
 ┣━━ string2 ◀ loaded from rougail-test (⏳ value)
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,8 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 my_calculated_variable:
 ┣━━ string1 ◀ loaded from rougail-test
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,13 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 my_variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ val1)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ val2)
┃ ┗━━ string3 ◀ loaded from rougail-test
┗━━ 📓 my_calculated_variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ string1)
 ┣━━ string2 ◀ loaded from rougail-test (⏳ string2)
 ┗━━ string3 ◀ loaded from rougail-test (⏳ string3)

View file

@ -0,0 +1,7 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test (⏳ string1)
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test (⏳ no)

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 a first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: 0 ◀ loaded from rougail-test (⏳ 9)

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: 0 ◀ loaded from rougail-test (⏳ 9)

View file

@ -0,0 +1,21 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable:
┃ ┗━━ true ◀ loaded from rougail-test (true)
┣━━ 📓 the second variable:
┃ ┗━━ true ◀ loaded from rougail-test (true)
┣━━ 📓 the third variable:
┃ ┗━━ true ◀ loaded from rougail-test (true)
┣━━ 📓 the forth variable:
┃ ┗━━ true ◀ loaded from rougail-test (false)
┣━━ 📓 the fifth variable:
┃ ┗━━ true ◀ loaded from rougail-test (false)
┣━━ 📓 the sixth variable:
┃ ┗━━ true ◀ loaded from rougail-test (false)
┣━━ 📓 the seventh variable:
┃ ┗━━ true ◀ loaded from rougail-test (true)
┗━━ 📓 the eighth variable:
 ┗━━ true ◀ loaded from rougail-test (true)

View file

@ -0,0 +1,13 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first custom variable:
┃ ┣━━ string1 ◀ loaded from rougail-test
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┗━━ 📓 a second custom variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,37 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┣━━ 📓 the second variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┣━━ 📓 the third variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┣━━ 📓 the forth variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 10.1)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┣━━ 📓 the fifth variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 10.1)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┣━━ 📓 the sixth variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 10.1)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┣━━ 📓 the seventh variable:
┃ ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 0.0)
┃ ┣━━ 2.2 ◀ loaded from rougail-test
┃ ┗━━ 3.3 ◀ loaded from rougail-test
┗━━ 📓 the eighth variable:
 ┣━━ 1.1 ◀ loaded from rougail-test (⏳ 0.0)
 ┣━━ 2.2 ◀ loaded from rougail-test
 ┗━━ 3.3 ◀ loaded from rougail-test

View file

@ -0,0 +1,37 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 0)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┣━━ 📓 the second variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 0)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┣━━ 📓 the third variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 0)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┣━━ 📓 the forth variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 10)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┣━━ 📓 the fifth variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 10)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┣━━ 📓 the sixth variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 10)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┣━━ 📓 the seventh variable:
┃ ┣━━ 1 ◀ loaded from rougail-test (⏳ 0)
┃ ┣━━ 2 ◀ loaded from rougail-test
┃ ┗━━ 3 ◀ loaded from rougail-test
┗━━ 📓 the eighth variable:
 ┣━━ 1 ◀ loaded from rougail-test (⏳ 0)
 ┣━━ 2 ◀ loaded from rougail-test
 ┗━━ 3 ◀ loaded from rougail-test

View file

@ -0,0 +1,8 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 the first variable:
 ┣━━ 1 ◀ loaded from rougail-test
 ┣━━ 2 ◀ loaded from rougail-test
 ┗━━ 3 ◀ loaded from rougail-test

View file

@ -0,0 +1,9 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 the second variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
 ┣━━ string2 ◀ loaded from rougail-test (⏳ null)
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,37 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the first variable:
┃ ┣━━ string1 ◀ loaded from rougail-test
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┣━━ 📓 the second variable:
┃ ┣━━ string1 ◀ loaded from rougail-test
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┣━━ 📓 the third variable:
┃ ┣━━ string1 ◀ loaded from rougail-test
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┣━━ 📓 the forth variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┣━━ 📓 the fifth variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┣━━ 📓 the sixth variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┣━━ 📓 the seventh variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
┃ ┣━━ string2 ◀ loaded from rougail-test
┃ ┗━━ string3 ◀ loaded from rougail-test
┗━━ 📓 the eighth variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ value)
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,13 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 the variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ val1)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ val2)
┃ ┗━━ string3 ◀ loaded from rougail-test (⏳ val3)
┗━━ 📓 the variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ val4)
 ┣━━ string2 ◀ loaded from rougail-test (⏳ val5)
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,9 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ quote")
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,9 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ quote'")
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,9 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable:
 ┣━━ string1 ◀ loaded from rougail-test (⏳ quote')
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,8 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┗━━ 📓 a variable:
 ┣━━ string1 ◀ loaded from rougail-test
 ┣━━ string2 ◀ loaded from rougail-test
 ┗━━ string3 ◀ loaded from rougail-test

View file

@ -0,0 +1,10 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┣━━ 📓 a first variable:
┃ ┣━━ string1 ◀ loaded from rougail-test (⏳ a)
┃ ┣━━ string2 ◀ loaded from rougail-test (⏳ b)
┃ ┗━━ string3 ◀ loaded from rougail-test (⏳ c)
┗━━ 📓 a second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 a variable: a ◀ loaded from rougail-test (⏳ c)

View file

@ -0,0 +1,6 @@
╭──────── Caption ────────╮
│ Variable Modified value │
╰─────────────────────────╯
Variables:
┣━━ 📓 the first variable: string1 ◀ loaded from rougail-test
┗━━ 📓 the second variable: string1 ◀ loaded from rougail-test

View file

@ -0,0 +1,6 @@
╭────────────── Caption ───────────────╮
│ Variable Modified value │
(⏳ Original default value)
╰──────────────────────────────────────╯
Variables:
┗━━ 📓 A limited number: 1 ◀ loaded from rougail-test (⏳ 10)

Some files were not shown because too many files have changed in this diff Show more