From 9d856f9de09e00757d1da1debb88906106f4dd23 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 27 Oct 2025 06:50:10 +0100 Subject: [PATCH] feat: user_datas/output --- docs/index.rst | 7 ++ docs/library/extra.rst | 2 +- docs/library/output.rst | 161 ++++++++++++++++++++++++++++---- docs/library/parse.rst | 10 +- docs/library/user_datas.rst | 30 +++--- docs/user_datas/bitwarden.rst | 3 + docs/user_datas/commandline.rst | 3 + docs/user_datas/environment.rst | 3 + docs/user_datas/index.rst | 19 ++++ docs/user_datas/questionary.rst | 3 + docs/user_datas/yaml.rst | 3 + 11 files changed, 205 insertions(+), 39 deletions(-) create mode 100644 docs/user_datas/bitwarden.rst create mode 100644 docs/user_datas/commandline.rst create mode 100644 docs/user_datas/environment.rst create mode 100644 docs/user_datas/index.rst create mode 100644 docs/user_datas/questionary.rst create mode 100644 docs/user_datas/yaml.rst diff --git a/docs/index.rst b/docs/index.rst index 370e8fc62..8b9bb3c42 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -67,6 +67,13 @@ Explained differently, Rougail allows you to easily implement an integration of Value checks condition +.. toctree:: + :titlesonly: + :caption: Load values from user datas + + user_datas/index + configuration + .. toctree:: :titlesonly: :caption: The library diff --git a/docs/library/extra.rst b/docs/library/extra.rst index c48936810..8c99fb6d2 100644 --- a/docs/library/extra.rst +++ b/docs/library/extra.rst @@ -31,7 +31,7 @@ Then, let's create the :term:`Tiramisu` objects via the following :file:`script. from rougail import Rougail, RougailConfig - RougailConfig['main_structural_directories'] = ['dict'] + RougailConfig['main_structural_directories'] = ['dict/'] RougailConfig['extra_namespaces']['example'] = ['extras/'] rougail = Rougail() config = rougail.get_config() diff --git a/docs/library/output.rst b/docs/library/output.rst index 2a49d5178..b39cd0a1e 100644 --- a/docs/library/output.rst +++ b/docs/library/output.rst @@ -36,14 +36,14 @@ We can display configuration directly in the console: from rougail.output_console import RougailOutputConsole RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.output"] = "console" - rougail = Rougail(RougailConfig) + rougail = Rougail() config = rougail.run() config.property.read_only() RougailOutputConsole(config).print() -FIXME display console! +.. FIXME display console! console.key_is_description '''''''''''''''''''''''''' @@ -57,15 +57,15 @@ By default, the key is the variable description, if you prefer have only the pat from rougail.output_json import RougailOutputJson RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] - RougailConfig["step.output"] = "json" - rougail = Rougail(RougailConfig) + RougailConfig["main_structural_directories"] = ["dist/"] + RougailConfig["step.output"] = "console" + rougail = Rougail() config = rougail.run() config.property.read_only() RougailOutputJson(config).print() -FIXME display console! +.. FIXME display console! console.show_secrets '''''''''''''''''''' @@ -79,14 +79,15 @@ Secrets are remplace by "*******", to display real secrets: from rougail.output_console import RougailOutputConsole RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] + RougailConfig["step.output"] = "console" RougailConfig["console.show_secrets"] = True - rougail = Rougail(RougailConfig) + rougail = Rougail() config = rougail.run() config.property.read_only() RougailOutputConsole(config).print() -FIXME display console! +.. FIXME display console! console.mandatory ''''''''''''''''' @@ -100,14 +101,15 @@ Before display configuration, mandatories variables are check. If you don't want from rougail.output_console import RougailOutputConsole RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] + RougailConfig["step.output"] = "console" RougailConfig["console.mandatory"] = False - rougail = Rougail(RougailConfig) + rougail = Rougail() config = rougail.run() config.property.read_only() RougailOutputConsole(config).print() -FIXME display console! +.. FIXME display console! JSON ---- @@ -121,9 +123,9 @@ Your script can return a JSON object: from rougail.output_console import RougailOutputConsole RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] - RougailConfig["console.mandatory"] = False - rougail = Rougail(RougailConfig) + RougailConfig["main_structural_directories"] = ["dist/"] + RougailConfig["step.output"] = "json" + rougail = Rougail() config = rougail.run() config.property.read_only() RougailOutputConsole(config).print() @@ -132,7 +134,7 @@ Let's try this script: .. code-block:: bash - $ LC_ALL=C python script.py + $ python script.py { "my_variable": "my value", "my_boolean_variable": true, @@ -140,5 +142,128 @@ Let's try this script: "my_secret_variable": "MyVeryStrongPassword" } +ANSIBLE +------- -.. doc,ansible +It's possible to use Ansible has a output format. + +The goal is here to use Ansible has a dynamic user's inventories structure manage by Rougail. + +This output needs an extra namespace, named, by default, "hosts". This namespace define your hosts and groups. + +Let's create a single group "my_group" with one host "group1.net": + +.. code-block:: yaml + :caption: the :file:`hosts/00-hosts.yml` file content + + %YAML 1.2 + --- + version: 1.1 + + hostnames: + + my_group: + + hosts: + type: domainname + default: + - group1.net + ... + +Now we can generate Ansible inventory: + +.. code-block:: python + :caption: the :file:`script.py` file content + + #!/bin/env python + from rougail import Rougail, RougailConfig + from rougail.output_ansible import RougailOutputAnsible + + RougailConfig["main_namespace"] = "main" + RougailConfig["main_structural_directories"] = ["dist/"] + RougailConfig['extra_namespaces']['hosts'] = ['hosts/'] + RougailConfig["step.output"] = "ansible" + rougail = Rougail() + config = rougail.run() + config.property.read_only() + RougailOutputAnsible(config).print() + +We will retrieved all ours variables associate to this group with all variables inside the namespace `main`: + +.. code-block:: bash + + $ python script.py + { + "_meta": { + "hostvars": { + "group1.net": { + "ansible_host": "group1.net", + "main": { + "my_variable": "my value", + "my_boolean_variable": true, + "my_integer_variable": 1, + "my_secret_variable": "MyVeryStrongPassword" + } + } + } + }, + "my_group": { + "hosts": [ + "group1.net" + ] + } + } + +We can now use our script as an inventory source in Ansible: + +.. code-block:: bash + + $ chmod +x script.py + $ ansible-inventory -i script.py --list + { + "_meta": { + "hostvars": { + "group1.net": { + "ansible_host": "group1.net", + "main": { + "my_boolean_variable": true, + "my_integer_variable": 1, + "my_secret_variable": "MyVeryStrongPassword", + "my_variable": "my value" + } + } + } + }, + "all": { + "children": [ + "ungrouped", + "my_group" + ] + }, + "my_group": { + "hosts": [ + "group1.net" + ] + } + } + +DOC +--- + +We can generate the documentation of all the Rougail variable: + +.. code-block:: python + :caption: the :file:`script.py` file content + + from rougail import Rougail, RougailConfig + from rougail.output_doc import RougailOutputDoc + + RougailConfig["main_namespace"] = "main" + RougailConfig["main_structural_directories"] = ["dist/"] + RougailConfig["step.output"] = "doc" + rougail = Rougail() + config = rougail.run() + config.property.read_only() + RougailOutputDoc(config).print() + +.. FIXME : display diff --git a/docs/library/parse.rst b/docs/library/parse.rst index ee091b61e..6aa096951 100644 --- a/docs/library/parse.rst +++ b/docs/library/parse.rst @@ -44,7 +44,7 @@ Create our first script to walk through our config: from rougail import Rougail, RougailConfig - RougailConfig['main_structural_directories'] = ['dist'] + RougailConfig['main_structural_directories'] = ["dist/"] rougail = Rougail() config = rougail.run() @@ -85,7 +85,7 @@ Let us distinguish the variables of the families from rougail import Rougail, RougailConfig - RougailConfig['main_structural_directories'] = ['dist'] + RougailConfig['main_structural_directories'] = ["dist/"] rougail = Rougail() config = rougail.run() @@ -128,7 +128,7 @@ Or if we want more precision: from rougail import Rougail, RougailConfig - RougailConfig['main_structural_directories'] = ['dist'] + RougailConfig['main_structural_directories'] = ["dist/"] rougail = Rougail() config = rougail.run() @@ -185,7 +185,7 @@ If we want to walk to get variables and their values: from rougail import Rougail, RougailConfig - RougailConfig['main_structural_directories'] = ['dist'] + RougailConfig['main_structural_directories'] = ["dist/"] rougail = Rougail() config = rougail.run() @@ -219,7 +219,7 @@ Some variables are mandatories but hasn't value. Here we set alls values: :caption: the :file:`script.py` file content from rougail import Rougail, RougailConfig - RougailConfig['main_structural_directories'] = ['dist'] + RougailConfig['main_structural_directories'] = ["dist/"] rougail = Rougail() config = rougail.run() diff --git a/docs/library/user_datas.rst b/docs/library/user_datas.rst index 5e8d1daca..b7889d42e 100644 --- a/docs/library/user_datas.rst +++ b/docs/library/user_datas.rst @@ -1,7 +1,7 @@ Load user datas =============== -User datas are values setup but user for configuration variables. +User datas are values setup by user for configuration variables. There is differents types of user datas for differents sources types. @@ -38,7 +38,7 @@ Here is the first script which is load this file: from rougail import Rougail, RougailConfig RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] rougail = Rougail() config = rougail.run() print(config.value.get()) @@ -75,7 +75,7 @@ Here is the script which is load user data from the YAML file: from rougail.user_data_yaml import RougailUserDataYaml RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["yaml"] RougailConfig["yaml.filename"] = ["dist.yml"] rougail = Rougail() @@ -109,7 +109,7 @@ This is why the `yaml.file_with_secrets` parameter allows you to define whether from rougail.user_data_yaml import RougailUserDataYaml RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["yaml"] RougailConfig["yaml.filename"] = ["dist.yml"] RougailConfig["yaml.file_with_secrets"] = "none" @@ -151,7 +151,7 @@ Here is the script: from rougail.user_data_environment import RougailUserDataEnvironment RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["environment"] rougail = Rougail() config = rougail.run() @@ -178,7 +178,7 @@ We can redefine the prefix with `environment.default_environment_name` (prefix i from rougail.user_data_environment import RougailUserDataEnvironment RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["environment"] RougailConfig["environment.default_environment_name"] = "EX" rougail = Rougail() @@ -197,7 +197,7 @@ Let's execute `script.py`: env EX_MY_VARIABLE="a new value" EX_MY_BOOLEAN_VARIABLE="False" EX_MY_INTEGER_VARIABLE=10 EX_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py {: 'a new value', : False, : 10, : 'MyVeryStrongPassword'} -If you define a `main_namespace` or `extra_namespace`, the `environment.default_environment_name` is automaticly define with the name of the namespace in uppercase. And the separator is no more "_" but ".": +If you define a `main_namespace` or `extra_namespaces`, the `environment.default_environment_name` is automaticly define with the name of the namespace in uppercase. And the separator is no more "_" but ".": .. code-block:: python :caption: the :file:`script.py` file content @@ -206,7 +206,7 @@ If you define a `main_namespace` or `extra_namespace`, the `environment.default_ from rougail.user_data_environment import RougailUserDataEnvironment RougailConfig["main_namespace"] = "main" - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["environment"] rougail = Rougail() config = rougail.run() @@ -234,7 +234,7 @@ This is why the `environment.with_secrets` parameter allows you to reject secret from rougail.user_data_environment import RougailUserDataEnvironment RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["environment"] RougailConfig["environment.with_secrets"] = False rougail = Rougail() @@ -265,7 +265,7 @@ Value can be define directly with command line arguments: from rougail.user_data_commandline import RougailUserDataCommandline RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["commandline"] rougail = Rougail() config = rougail.run() @@ -320,7 +320,7 @@ You can combine user datas, for example if you want to load datas from environme from rougail.user_data_commandline import RougailUserDataCommandline RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["environment", "commandline"] rougail = Rougail() config = rougail.run() @@ -359,7 +359,7 @@ Recreate a script with environnement variable support which is display the retur from rougail.user_data_environment import RougailUserDataEnvironment RougailConfig["main_namespace"] = None - RougailConfig["main_structural_directories"] = ["dist"] + RougailConfig["main_structural_directories"] = ["dist/"] RougailConfig["step.user_data"] = ["environment"] RougailConfig["environment.with_secrets"] = False rougail = Rougail() @@ -373,7 +373,7 @@ Recreate a script with environnement variable support which is display the retur Try to load the value an unknown variable: .. code-block:: bash - $ LC_ALL=C env ROUGAIL_UNKNOWN_VARIABLE="a value" python script.py + $ env ROUGAIL_UNKNOWN_VARIABLE="a value" python script.py {'errors': [], 'warnings': ['variable or family "unknown_variable" does not exist, it will be ignored when loading from environment variable']} As you can see, a warnings is return. @@ -381,13 +381,13 @@ As you can see, a warnings is return. Try to load the value of an hidden variable: .. code-block:: bash - $ LC_ALL=C env ROUGAIL_MY_HIDDEN_VARIABLE="a value" python script.py + $ env ROUGAIL_MY_HIDDEN_VARIABLE="a value" python script.py {'errors': [], 'warnings': ['variable "my_hidden_variable" (My hidden variable) is hidden, it will be ignored when loading from environment variable']} Finally if a try to change the value of a secret, which is not allowed: .. code-block:: bash - $ LC_ALL=C env ROUGAIL_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py + $ env ROUGAIL_MY_SECRET_VARIABLE="MyVeryStrongPassword" python script.py {'errors': ['the variable "my_secret_variable" contains secrets and should not be defined in environment variable'], 'warnings': []} An error is generate. diff --git a/docs/user_datas/bitwarden.rst b/docs/user_datas/bitwarden.rst new file mode 100644 index 000000000..454291173 --- /dev/null +++ b/docs/user_datas/bitwarden.rst @@ -0,0 +1,3 @@ +Load user datas from Bitwarden server +===================================== + diff --git a/docs/user_datas/commandline.rst b/docs/user_datas/commandline.rst new file mode 100644 index 000000000..3eae5ccad --- /dev/null +++ b/docs/user_datas/commandline.rst @@ -0,0 +1,3 @@ +Load user datas from commandline parser +======================================= + diff --git a/docs/user_datas/environment.rst b/docs/user_datas/environment.rst new file mode 100644 index 000000000..91968b68f --- /dev/null +++ b/docs/user_datas/environment.rst @@ -0,0 +1,3 @@ +Load user datas from a environment variable +=========================================== + diff --git a/docs/user_datas/index.rst b/docs/user_datas/index.rst new file mode 100644 index 000000000..32e700212 --- /dev/null +++ b/docs/user_datas/index.rst @@ -0,0 +1,19 @@ +`Rougail`'s user datas description +================================== + +Rougail is a collections of subproject to adjust functionalities to your needs. + +User datas is one of category of subjects. The goal is to setup variable with value define by user. + +There is differents user datas types: + +.. toctree:: + :titlesonly: + :caption: Use library + + yaml + environment + commandline + ansible + bitwarden + questionary diff --git a/docs/user_datas/questionary.rst b/docs/user_datas/questionary.rst new file mode 100644 index 000000000..8fcaa8b7f --- /dev/null +++ b/docs/user_datas/questionary.rst @@ -0,0 +1,3 @@ +Load user datas from a command line interface +============================================= + diff --git a/docs/user_datas/yaml.rst b/docs/user_datas/yaml.rst new file mode 100644 index 000000000..abbea5ef0 --- /dev/null +++ b/docs/user_datas/yaml.rst @@ -0,0 +1,3 @@ +Load user datas from a YAML file +================================ +