feat: multi rougailcli.yml files
This commit is contained in:
parent
1f537963df
commit
585313e4bc
17 changed files with 128 additions and 57 deletions
|
|
@ -27,7 +27,7 @@ from tiramisu.error import PropertiesOptionError
|
|||
from tiramisu import MetaConfig
|
||||
|
||||
from rougail import Rougail
|
||||
from rougail.user_datas import UserDatas
|
||||
from rougail.user_data import UserData
|
||||
from rougail.config import get_rougail_config
|
||||
from rougail.utils import load_modules
|
||||
from rougail.error import RougailWarning
|
||||
|
|
@ -53,7 +53,7 @@ def _main(arguments, do_not_print):
|
|||
rougailconfig = get_rougail_config(
|
||||
backward_compatibility=False, add_extra_options=False
|
||||
)
|
||||
cmd_config = load_cmd_user_datas(rougailconfig, arguments)
|
||||
cmd_config = load_cmd_user_data(rougailconfig, arguments)
|
||||
print_traceback = rougailconfig["cli.debug"]
|
||||
if rougailconfig["cli.versions"]:
|
||||
versions = display_version(cmd_config)
|
||||
|
|
@ -62,7 +62,7 @@ def _main(arguments, do_not_print):
|
|||
for version in versions:
|
||||
print(version)
|
||||
exit()
|
||||
layer_datas, metaconfig, config, err_warn = load_user_datas(rougailconfig)
|
||||
layer_datas, metaconfig, config, err_warn = load_user_data(rougailconfig)
|
||||
output = get_output(rougailconfig, metaconfig, config, err_warn, layer_datas)
|
||||
if do_not_print:
|
||||
return output.run()
|
||||
|
|
@ -71,7 +71,7 @@ def _main(arguments, do_not_print):
|
|||
exit(1)
|
||||
|
||||
|
||||
def load_cmd_user_datas(rougailconfig, arguments):
|
||||
def load_cmd_user_data(rougailconfig, arguments):
|
||||
rougailconfig.generate_config()
|
||||
cmd_config = rougailconfig.config
|
||||
origin_prop = cmd_config.property.default("read_write", "append")
|
||||
|
|
@ -79,23 +79,28 @@ def load_cmd_user_datas(rougailconfig, arguments):
|
|||
frozenset(origin_prop | {"not_for_commandline"}), "read_write", "append"
|
||||
)
|
||||
cmd_config.property.read_write()
|
||||
config_file = None
|
||||
config_files = None
|
||||
if RougailUserDataYaml:
|
||||
_config_file = os.environ.pop(f"{ENV_PREFIX}_CLI.CONFIG_FILE", None)
|
||||
if not _config_file:
|
||||
_config_file = cmd_config.forcepermissive.option("cli.config_file").value.get()
|
||||
if Path(_config_file).is_file():
|
||||
config_file = _config_file
|
||||
_config_files = os.environ.pop(f"{ENV_PREFIX}_CLI.CONFIG_FILE", None)
|
||||
if _config_files:
|
||||
_config_files = _config_files.split(',')
|
||||
else:
|
||||
_config_files = cmd_config.forcepermissive.option("cli.config_file").value.get()
|
||||
_config_files = [_config_file for _config_file in _config_files if Path(_config_file).is_file()]
|
||||
if _config_files:
|
||||
config_files = _config_files
|
||||
if RougailUserDataEnvironment:
|
||||
env_prefix = ENV_PREFIX
|
||||
else:
|
||||
env_prefix = None
|
||||
user_data = rougailconfig_load(rougailconfig, config_file, env_prefix, True, _arguments=arguments, _generate=False, _add_help=False)
|
||||
user_data = rougailconfig_load(rougailconfig, config_files, env_prefix, True, _arguments=arguments, _generate=False, _add_help=False)
|
||||
display_warnings = rougailconfig["cli.warnings"]
|
||||
manage_warnings(display_warnings)
|
||||
if not cmd_config.option("cli.versions").value.get():
|
||||
if display_warnings and user_data["warnings"]:
|
||||
for warning in user_data["warnings"]:
|
||||
if isinstance(warning, dict):
|
||||
warning = next(iter(warning))
|
||||
warn(warning)
|
||||
if manage_warnings:
|
||||
# replays to display errors if needed
|
||||
|
|
@ -157,7 +162,7 @@ def manage_warnings(warnings):
|
|||
filterwarnings("default", category=RougailWarning)
|
||||
|
||||
|
||||
def load_user_datas(rougailconfig):
|
||||
def load_user_data(rougailconfig):
|
||||
layer_datas = {}
|
||||
if not rougailconfig["cli.load_config"]:
|
||||
return None, None, None, {"errors": [], "warnings": []}
|
||||
|
|
@ -190,14 +195,15 @@ def load_user_datas(rougailconfig):
|
|||
subconfig.property.setdefault(
|
||||
frozenset(subconfig.property.default("read_only", "remove") | (read_write - read_only)), "read_only", "remove"
|
||||
)
|
||||
subconfig.property.read_write()
|
||||
if read_only:
|
||||
subconfig.property.setdefault(
|
||||
frozenset(subconfig.property.default("read_only", "append") | read_only), "read_only", "append"
|
||||
)
|
||||
if read_write or read_only:
|
||||
subconfig.property.read_write()
|
||||
except:
|
||||
pass
|
||||
subconfig.information.set("description_type", rougailconfig["cli.description_type"])
|
||||
metaconfig = subconfig
|
||||
if last_layers:
|
||||
for layer in layers[:-1]:
|
||||
|
|
@ -206,9 +212,9 @@ def load_user_datas(rougailconfig):
|
|||
metaconfig.owner.set(metaconfig.path())
|
||||
subconfig = metaconfig
|
||||
err_warn = {"errors": [], "warnings": []}
|
||||
invalid_user_datas_error = rougailconfig["cli.invalid_user_datas_error"]
|
||||
unknown_user_datas_error = rougailconfig["cli.unknown_user_datas_error"]
|
||||
interactive_user_datas = {}
|
||||
invalid_user_data_error = rougailconfig["cli.invalid_user_data_error"]
|
||||
unknown_user_data_error = rougailconfig["cli.unknown_user_data_error"]
|
||||
interactive_user_data = {}
|
||||
for idx, layer in enumerate(layers):
|
||||
if idx:
|
||||
subconfig = subconfig.config("_".join(layer))
|
||||
|
|
@ -217,7 +223,7 @@ def load_user_datas(rougailconfig):
|
|||
else:
|
||||
layer_name = None
|
||||
# data user
|
||||
user_datas = []
|
||||
user_data = []
|
||||
if has_layers:
|
||||
layer_datas[layer_name] = {}
|
||||
for user_data_name in layer:
|
||||
|
|
@ -231,30 +237,30 @@ def load_user_datas(rougailconfig):
|
|||
_('cannot find "user_data" module "{0}"').format(user_data_name)
|
||||
)
|
||||
module = load_modules("rougail.user_data_" + user_data_name, str(path))
|
||||
rougail_user_datas = module.RougailUserData
|
||||
if hasattr(rougail_user_datas, 'interactive_user_datas') and rougail_user_datas.interactive_user_datas:
|
||||
interactive_user_datas.setdefault(layer_name, {})[user_data_name] = rougail_user_datas
|
||||
rougail_user_data = module.RougailUserData
|
||||
if hasattr(rougail_user_data, 'interactive_user_data') and rougail_user_data.interactive_user_data:
|
||||
interactive_user_data.setdefault(layer_name, {})[user_data_name] = rougail_user_data
|
||||
continue
|
||||
elif interactive_user_datas:
|
||||
raise Exception(_(f'interactive user datas "{0}" is loader before uninteractive user datas "{1}"').format(list(interactive_user_datas), user_data_name))
|
||||
for user_data in rougail_user_datas(
|
||||
elif interactive_user_data:
|
||||
raise Exception(_(f'interactive user datas "{0}" is loader before uninteractive user datas "{1}"').format(list(interactive_user_data), user_data_name))
|
||||
for ud in rougail_user_data(
|
||||
subconfig,
|
||||
rougailconfig=rougailconfig,
|
||||
).run():
|
||||
if has_layers:
|
||||
layer_datas[layer_name].setdefault(user_data_name, []).append(user_data["source"])
|
||||
user_datas.append(user_data)
|
||||
if user_datas:
|
||||
new_err_warn = UserDatas(subconfig).user_datas(user_datas, invalid_user_datas_error=invalid_user_datas_error, unknown_user_datas_error=unknown_user_datas_error)
|
||||
layer_datas[layer_name].setdefault(user_data_name, []).append(ud["source"])
|
||||
user_data.append(ud)
|
||||
if user_data:
|
||||
new_err_warn = UserData(subconfig).user_data(user_data, invalid_user_data_error=invalid_user_data_error, unknown_user_data_error=unknown_user_data_error)
|
||||
for level, datas in new_err_warn.items():
|
||||
if datas:
|
||||
err_warn[level].extend(datas)
|
||||
for layer_name, interactive_user_data in interactive_user_datas.items():
|
||||
for layer, rougail_user_datas in interactive_user_data.items():
|
||||
for layer_name, interactive_user_data in interactive_user_data.items():
|
||||
for layer, rougail_user_data in interactive_user_data.items():
|
||||
if has_layers and len(layers) > 1:
|
||||
subconfig = subconfig.config("_".join(layer))
|
||||
subconfig.owner.set(subconfig.path())
|
||||
for user_data in rougail_user_datas(
|
||||
for user_data in rougail_user_data(
|
||||
subconfig,
|
||||
rougailconfig=rougailconfig,
|
||||
).run():
|
||||
|
|
@ -281,7 +287,7 @@ def get_output(rougailconfig, metaconfig, config, err_warn, layer_datas):
|
|||
user_data_errors=err_warn["errors"],
|
||||
user_data_warnings=err_warn["warnings"],
|
||||
config_owner_is_path=True,
|
||||
metaconfig=metaconfig,
|
||||
root_config=metaconfig,
|
||||
layer_datas=layer_datas,
|
||||
)
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ cli:
|
|||
commandline: false
|
||||
params:
|
||||
allow_relative: true
|
||||
default: .rougailcli.yml
|
||||
default:
|
||||
- .rougailcli.yml
|
||||
|
||||
debug: false # {_('Displays debug informations')}
|
||||
|
||||
|
|
@ -41,9 +42,9 @@ cli:
|
|||
|
||||
versions: false # {_('Displays Rougail version and all its components')}
|
||||
|
||||
invalid_user_datas_error: false # {_("Invalid value in user datas is not allowed")}
|
||||
invalid_user_data_error: false # {_("Invalid value in user datas is not allowed")}
|
||||
|
||||
unknown_user_datas_error: false # {_("Unknown variable in user datas is not allowed")}
|
||||
unknown_user_data_error: false # {_("Unknown variable in user datas is not allowed")}
|
||||
|
||||
layers:
|
||||
description: {_('Open each user datas in separate layers')}
|
||||
|
|
@ -59,6 +60,22 @@ cli:
|
|||
|
||||
read_write: false # {_('Configuration in output step is in read_write mode')}
|
||||
|
||||
description_type:
|
||||
description: {_('Type of variables description')}
|
||||
help: >-
|
||||
{_("""To identify different variables, we use the variable description. There are four types of description:
|
||||
|
||||
- name_and_description: which contains the variable name followed by its description
|
||||
- path: the variable's path
|
||||
- name: the variable name
|
||||
- description: the variable's description""")}
|
||||
choices:
|
||||
- name_and_description
|
||||
- path
|
||||
- name
|
||||
- description
|
||||
default: description
|
||||
|
||||
inaccessible_read_write_modes:
|
||||
description: {_('Modes that should not be accessible in read_write mode')}
|
||||
multi: true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ ([32m⏳ Original default value[0m) │
|
||||
│ Variable [32mModified value[0m │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
[94m┗━━ [0m📓 a description: a yaml value ◀ loaded from the YAML file "yaml/file.yml"
|
||||
[94m [0m(⏳ [32mmy_value[0m)
|
||||
[94m┗━━ [0m📓 a description: [32ma yaml value[0m ◀ loaded from the YAML file "yaml/file.yml"
|
||||
[94m [0m(⏳ my_value)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ ([32m⏳ Original default value[0m) │
|
||||
│ Variable [32mModified value[0m │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
Variables:
|
||||
[94m┗━━ [0m📓 a description: a yaml value ◀ loaded from the YAML file "yaml/file.yml"
|
||||
[94m [0m(⏳ [32mmy_value[0m)
|
||||
[94m┗━━ [0m📓 a description: [32ma yaml value[0m ◀ loaded from the YAML file "yaml/file.yml"
|
||||
[94m [0m(⏳ my_value)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
╭────────────── Caption ───────────────╮
|
||||
│ Variable Modified value │
|
||||
│ ([32m⏳ Original default value[0m) │
|
||||
│ Variable [32mModified value[0m │
|
||||
│ (⏳ Original default value) │
|
||||
╰──────────────────────────────────────╯
|
||||
╭─────────── Layers ────────────╮
|
||||
│ environment variable │
|
||||
│ the YAML file "yaml/file.yml" │
|
||||
╰───────────────────────────────╯
|
||||
Variables:
|
||||
[94m┗━━ [0m📓 a description: a yaml value ◀ loaded from the YAML file "yaml/file.yml"
|
||||
[94m [0m(⏳ [32mmy env value[0m ◀ loaded from environment variable ⏳ [32mmy env value[0m)
|
||||
[94m┗━━ [0m📓 a description: [32ma yaml value[0m ◀ loaded from the YAML file "yaml/file.yml"
|
||||
[94m [0m(⏳ my env value ◀ loaded from environment variable ⏳ my_value)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
["tiramisu", "tiramisu-cmdline-parser", "rougail", "rougail-cli", "rougail-structural-bitwarden", "rougail-user-data-ansible", "rougail-user-data-bitwarden", "rougail-user-data-commandline", "rougail-user-data-environment", "rougail-user-data-questionary", "rougail-user-data-yaml", "rougail-output-ansible", "rougail-output-console", "rougail-output-doc", "rougail-output-json"]
|
||||
["tiramisu", "tiramisu-cmdline-parser", "rougail", "rougail-cli", "rougail-structural-bitwarden", "rougail-user-data-ansible", "rougail-user-data-bitwarden", "rougail-user-data-commandline", "rougail-user-data-environment", "rougail-user-data-questionary", "rougail-user-data-yaml", "rougail-output-ansible", "rougail-output-display", "rougail-output-doc", "rougail-output-json"]
|
||||
|
|
|
|||
1
tests/rougailcli_file/choice_console.txt
Normal file
1
tests/rougailcli_file/choice_console.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
"\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Caption \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 Variable \u001b[38;5;220mDefault value\u001b[0m \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\nVariables:\n\u001b[94m\u2517\u2501\u2501 \u001b[0m\ud83d\udcd3 a description: \u001b[38;5;220mmy_value\u001b[0m\n"
|
||||
8
tests/rougailcli_file/choice_rougailcli.yml
Normal file
8
tests/rougailcli_file/choice_rougailcli.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
main_structural_directories:
|
||||
- structures
|
||||
- structures_warnings
|
||||
doc:
|
||||
output_format: console
|
||||
cli:
|
||||
warnings: false
|
||||
|
|
@ -1 +1 @@
|
|||
["family \"configuration rougail-json\" is disabled, \"test mandatories variables before display in json\" will be ignored when loading from the YAML file \"warnings.yml\""]
|
||||
["family \"configuration rougail-json\" is disabled, so cannot access to \"test mandatories variables before display in json\", it will be ignored when loading from the YAML file \"warnings.yml\""]
|
||||
|
|
@ -1 +1 @@
|
|||
["family \"configuration rougail-json\" is disabled, \"test mandatories variables before display in json\" will be ignored when loading from the YAML file \"warnings3.yml\"", "\"validators\" is a calculation for my_variable but has no description in \"structures/file.yml\" and \"structures_warnings/file.yml\""]
|
||||
["family \"configuration rougail-json\" is disabled, so cannot access to \"test mandatories variables before display in json\", it will be ignored when loading from the YAML file \"warnings3.yml\"", "\"validators\" is a calculation for my_variable but has no description in \"structures/file.yml\" and \"structures_warnings/file.yml\""]
|
||||
|
|
@ -1 +1 @@
|
|||
"{\n \"my_variable\": {\n \"type\": \"variable\",\n \"default\": {\n \"name\": \"Default\",\n \"values\": \"my_value\"\n },\n \"properties\": [\n {\n \"type\": \"type\",\n \"name\": \"string\"\n },\n {\n \"type\": \"property\",\n \"name\": \"mandatory\"\n }\n ],\n \"path\": \"my_variable\",\n \"names\": [\n \"my_variable\"\n ],\n \"description\": \"A description.\",\n \"gen_examples\": [\n \"my_value\"\n ],\n \"mandatory_without_value\": false\n }\n}"
|
||||
"{\n \"my_variable\": {\n \"type\": \"variable\",\n \"default\": {\n \"name\": \"Default\",\n \"values\": \"my_value\"\n },\n \"variable_type\": \"string\",\n \"path\": \"my_variable\",\n \"names\": [\n \"my_variable\"\n ],\n \"description\": \"A description.\",\n \"properties\": [\n {\n \"type\": \"property\",\n \"name\": \"mandatory\",\n \"ori_name\": \"mandatory\",\n \"access_control\": false\n }\n ],\n \"gen_examples\": [\n \"my_value\"\n ],\n \"mandatory_without_value\": false\n }\n}"
|
||||
5
tests/rougailcli_files/rougailcli1.yml
Normal file
5
tests/rougailcli_files/rougailcli1.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
main_structural_directories:
|
||||
- structures
|
||||
step:
|
||||
output: json
|
||||
5
tests/rougailcli_files/rougailcli2.yml
Normal file
5
tests/rougailcli_files/rougailcli2.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
step:
|
||||
output: doc
|
||||
doc:
|
||||
output_format: json
|
||||
4
tests/rougailcli_files/structures/file.yml
Normal file
4
tests/rougailcli_files/structures/file.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
version: 1.1
|
||||
|
||||
my_variable: my_value # a description
|
||||
1
tests/rougailcli_files/yaml.txt
Normal file
1
tests/rougailcli_files/yaml.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
"{\n \"my_variable\": {\n \"type\": \"variable\",\n \"default\": {\n \"name\": \"Default\",\n \"values\": \"my_value\"\n },\n \"variable_type\": \"string\",\n \"path\": \"my_variable\",\n \"names\": [\n \"my_variable\"\n ],\n \"description\": \"A description.\",\n \"properties\": [\n {\n \"type\": \"property\",\n \"name\": \"mandatory\",\n \"ori_name\": \"mandatory\",\n \"access_control\": false\n }\n ],\n \"gen_examples\": [\n \"my_value\"\n ],\n \"mandatory_without_value\": false\n }\n}"
|
||||
|
|
@ -1 +1 @@
|
|||
"{\n \"my_variable\": {\n \"type\": \"variable\",\n \"default\": {\n \"name\": \"Default\",\n \"values\": \"my_value\"\n },\n \"properties\": [\n {\n \"type\": \"type\",\n \"name\": \"string\"\n },\n {\n \"type\": \"property\",\n \"name\": \"mandatory\"\n }\n ],\n \"path\": \"my_variable\",\n \"names\": [\n \"my_variable\"\n ],\n \"description\": \"A description.\",\n \"gen_examples\": [\n \"my_value\"\n ],\n \"mandatory_without_value\": false\n }\n}"
|
||||
"{\n \"my_variable\": {\n \"type\": \"variable\",\n \"default\": {\n \"name\": \"Default\",\n \"values\": \"my_value\"\n },\n \"variable_type\": \"string\",\n \"path\": \"my_variable\",\n \"names\": [\n \"my_variable\"\n ],\n \"description\": \"A description.\",\n \"properties\": [\n {\n \"type\": \"property\",\n \"name\": \"mandatory\",\n \"ori_name\": \"mandatory\",\n \"access_control\": false\n }\n ],\n \"gen_examples\": [\n \"my_value\"\n ],\n \"mandatory_without_value\": false\n }\n}"
|
||||
|
|
@ -25,7 +25,7 @@ def test_cli():
|
|||
|
||||
def test_cli_boolean():
|
||||
with chdir(test_dir / 'cli'):
|
||||
ret = main(['--main_structural_directories', 'structures', '--console.mandatory'], do_not_print=True)
|
||||
ret = main(['--main_structural_directories', 'structures', '--display.mandatory'], do_not_print=True)
|
||||
filename = Path('result.txt')
|
||||
if not filename.is_file():
|
||||
with filename.open('w') as fh:
|
||||
|
|
@ -37,7 +37,7 @@ def test_cli_boolean():
|
|||
|
||||
def test_cli_boolean_no():
|
||||
with chdir(test_dir / 'cli'):
|
||||
ret = main(['--main_structural_directories', 'structures', '--console.no-mandatory'], do_not_print=True)
|
||||
ret = main(['--main_structural_directories', 'structures', '--display.no-mandatory'], do_not_print=True)
|
||||
filename = Path('result.txt')
|
||||
if not filename.is_file():
|
||||
with filename.open('w') as fh:
|
||||
|
|
@ -139,6 +139,19 @@ def test_cli_rougailcli():
|
|||
assert ret == (True, data), str(filename.absolute())
|
||||
|
||||
|
||||
def test_cli_rougailcli_files():
|
||||
with chdir(test_dir / 'rougailcli_files'):
|
||||
os.environ["ROUGAILCLI_CLI.CONFIG_FILE"] = 'rougailcli1.yml,rougailcli2.yml'
|
||||
ret = main([], do_not_print=True)
|
||||
filename = Path('yaml.txt')
|
||||
if not filename.is_file():
|
||||
with filename.open('w') as fh:
|
||||
fh.write(dumps(ret[1]))
|
||||
with filename.open() as fh:
|
||||
data = loads(fh.read())
|
||||
assert ret == (True, data), str(filename.absolute())
|
||||
|
||||
|
||||
def test_cli_alt_rougailcli():
|
||||
save = os.environ.copy()
|
||||
with chdir(test_dir / 'rougailcli_file'):
|
||||
|
|
@ -239,3 +252,18 @@ def test_cli_rougailcli_not_warning2():
|
|||
data = loads(fh.read())
|
||||
assert ret == data, str(filename.absolute())
|
||||
os.environ = save
|
||||
|
||||
|
||||
def test_cli_rougailcli_choice():
|
||||
save = os.environ.copy()
|
||||
with chdir(test_dir / 'rougailcli_file'):
|
||||
os.environ["ROUGAILCLI_CLI.CONFIG_FILE"] = 'choice_rougailcli.yml'
|
||||
ret = main([], do_not_print=True)
|
||||
filename = Path('choice_console.txt')
|
||||
if not filename.is_file():
|
||||
with filename.open('w') as fh:
|
||||
fh.write(dumps(ret[1]))
|
||||
with filename.open() as fh:
|
||||
data = loads(fh.read())
|
||||
assert ret == (True, data), str(filename.absolute())
|
||||
os.environ = save
|
||||
|
|
|
|||
Loading…
Reference in a new issue