|
|
|
#!/usr/bin/env python
|
|
|
|
# import os
|
|
|
|
import toml
|
|
|
|
from rich import pretty
|
|
|
|
from rich.console import Console
|
|
|
|
import re
|
|
|
|
|
|
|
|
# from utils.console import handle_input
|
|
|
|
from console import handle_input
|
|
|
|
|
|
|
|
|
|
|
|
console = Console()
|
|
|
|
|
|
|
|
|
|
|
|
printed = False
|
|
|
|
|
|
|
|
|
|
|
|
def crawl(obj: dict, func=lambda x, y: print(x, y, end="\n"), path: list = []):
|
|
|
|
for key in obj.keys():
|
|
|
|
if type(obj[key]) is dict:
|
|
|
|
crawl(obj[key], func, path + [key])
|
|
|
|
continue
|
|
|
|
func(path + [key], obj[key])
|
|
|
|
|
|
|
|
|
|
|
|
def check(value, checks, name):
|
|
|
|
global printed
|
|
|
|
if printed is False:
|
|
|
|
console.print(
|
|
|
|
"""\
|
|
|
|
[blue bold]###############################
|
|
|
|
# #
|
|
|
|
# Checking TOML configuration #
|
|
|
|
# #
|
|
|
|
###############################
|
|
|
|
If you see any prompts, that means that you have unset/incorrectly set variables, please input the correct values.\
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
printed = True
|
|
|
|
if "type" in checks:
|
|
|
|
try:
|
|
|
|
value = eval(checks["type"])(value)
|
|
|
|
except:
|
|
|
|
value = handle_input(
|
|
|
|
message=(
|
|
|
|
(
|
|
|
|
("[blue]Example: " + str(checks["example"]) + "\n")
|
|
|
|
if "example" in checks
|
|
|
|
else ""
|
|
|
|
)
|
|
|
|
+ "[red]"
|
|
|
|
+ ("Non-optional ", "Optional ")[
|
|
|
|
"optional" in checks and checks["optional"] is True
|
|
|
|
]
|
|
|
|
)
|
|
|
|
+ " [#C0CAF5 bold]"
|
|
|
|
+ str(name)
|
|
|
|
+ "[#F7768E bold]=",
|
|
|
|
check_type=eval(checks["type"]),
|
|
|
|
extra_info=checks["explanation"] if "explanation" in checks else "",
|
|
|
|
default=checks["default"] if "default" in checks else NotImplemented,
|
|
|
|
match=checks["regex"] if "regex" in checks else "",
|
|
|
|
err_message=checks["input_error"] if "input_error" in checks else "Incorrect input",
|
|
|
|
nmin=checks["nmin"] if "nmin" in checks else None,
|
|
|
|
nmax=checks["nmax"] if "nmax" in checks else None,
|
|
|
|
oob_error=checks["oob_error"]
|
|
|
|
if "oob_error" in checks
|
|
|
|
else "Input out of bounds(Value too high/low/long/short)",
|
|
|
|
)
|
|
|
|
|
|
|
|
if (
|
|
|
|
"options" in checks and value not in checks["options"]
|
|
|
|
): # FAILSTATE Value is not one of the options
|
|
|
|
value = handle_input(
|
|
|
|
message=(
|
|
|
|
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "")
|
|
|
|
+ "[red]"
|
|
|
|
+ ("Non-optional ", "Optional ")[
|
|
|
|
"optional" in checks and checks["optional"] is True
|
|
|
|
]
|
|
|
|
)
|
|
|
|
+ "[#C0CAF5 bold]"
|
|
|
|
+ str(name)
|
|
|
|
+ "[#F7768E bold]=",
|
|
|
|
extra_info=checks["explanation"] if "explanation" in checks else "",
|
|
|
|
err_message=checks["input_error"] if "input_error" in checks else "Incorrect input",
|
|
|
|
default=checks["default"] if "default" in checks else NotImplemented,
|
|
|
|
options=checks["options"],
|
|
|
|
)
|
|
|
|
if "regex" in checks and (
|
|
|
|
(isinstance(value, str) and re.match(checks["regex"], value) is None)
|
|
|
|
or not isinstance(value, str)
|
|
|
|
): # FAILSTATE Value doesn't match regex, or has regex but is not a string.
|
|
|
|
value = handle_input(
|
|
|
|
message=(
|
|
|
|
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "")
|
|
|
|
+ "[red]"
|
|
|
|
+ ("Non-optional ", "Optional ")[
|
|
|
|
"optional" in checks and checks["optional"] is True
|
|
|
|
]
|
|
|
|
)
|
|
|
|
+ "[#C0CAF5 bold]"
|
|
|
|
+ str(name)
|
|
|
|
+ "[#F7768E bold]=",
|
|
|
|
extra_info=checks["explanation"] if "explanation" in checks else "",
|
|
|
|
match=checks["regex"],
|
|
|
|
err_message=checks["input_error"] if "input_error" in checks else "Incorrect input",
|
|
|
|
default=checks["default"] if "default" in checks else NotImplemented,
|
|
|
|
nmin=checks["nmin"] if "nmin" in checks else None,
|
|
|
|
nmax=checks["nmax"] if "nmax" in checks else None,
|
|
|
|
oob_error=checks["oob_error"]
|
|
|
|
if "oob_error" in checks
|
|
|
|
else "Input out of bounds(Value too high/low/long/short)",
|
|
|
|
)
|
|
|
|
|
|
|
|
if not hasattr(value, "__iter__") and (
|
|
|
|
("nmin" in checks and checks["nmin"] is not None and value < checks["nmin"])
|
|
|
|
or ("nmax" in checks and checks["nmax"] is not None and value > checks["nmax"])
|
|
|
|
):
|
|
|
|
value = handle_input(
|
|
|
|
message=(
|
|
|
|
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "")
|
|
|
|
+ "[red]"
|
|
|
|
+ ("Non-optional ", "Optional ")[
|
|
|
|
"optional" in checks and checks["optional"] is True
|
|
|
|
]
|
|
|
|
)
|
|
|
|
+ "[#C0CAF5 bold]"
|
|
|
|
+ str(name)
|
|
|
|
+ "[#F7768E bold]=",
|
|
|
|
extra_info=checks["explanation"] if "explanation" in checks else "",
|
|
|
|
default=checks["default"] if "default" in checks else NotImplemented,
|
|
|
|
match=checks["regex"] if "regex" in checks else "",
|
|
|
|
err_message=checks["input_error"] if "input_error" in checks else "Incorrect input",
|
|
|
|
nmin=checks["nmin"] if "nmin" in checks else None,
|
|
|
|
nmax=checks["nmax"] if "nmax" in checks else None,
|
|
|
|
oob_error=checks["oob_error"]
|
|
|
|
if "oob_error" in checks
|
|
|
|
else "Input out of bounds(Value too high/low/long/short)",
|
|
|
|
)
|
|
|
|
if hasattr(value, "__iter__") and (
|
|
|
|
("nmin" in checks and checks["nmin"] is not None and len(value) < checks["nmin"])
|
|
|
|
or ("nmax" in checks and checks["nmax"] is not None and len(value) > checks["nmax"])
|
|
|
|
):
|
|
|
|
value = handle_input(
|
|
|
|
message=(
|
|
|
|
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "")
|
|
|
|
+ "[red]"
|
|
|
|
+ ("Non-optional ", "Optional ")[
|
|
|
|
"optional" in checks and checks["optional"] is True
|
|
|
|
]
|
|
|
|
)
|
|
|
|
+ "[#C0CAF5 bold]"
|
|
|
|
+ str(name)
|
|
|
|
+ "[#F7768E bold]=",
|
|
|
|
extra_info=checks["explanation"] if "explanation" in checks else "",
|
|
|
|
default=checks["default"] if "default" in checks else NotImplemented,
|
|
|
|
match=checks["regex"] if "regex" in checks else "",
|
|
|
|
err_message=checks["input_error"] if "input_error" in checks else "Incorrect input",
|
|
|
|
nmin=checks["nmin"] if "nmin" in checks else None,
|
|
|
|
nmax=checks["nmax"] if "nmax" in checks else None,
|
|
|
|
oob_error=checks["oob_error"]
|
|
|
|
if "oob_error" in checks
|
|
|
|
else "Input out of bounds(Value too high/low/long/short)",
|
|
|
|
)
|
|
|
|
if value == {}:
|
|
|
|
handle_input(
|
|
|
|
message=(
|
|
|
|
(("[blue]Example: " + str(checks["example"]) + "\n") if "example" in checks else "")
|
|
|
|
+ "[red]"
|
|
|
|
+ ("Non-optional ", "Optional ")[
|
|
|
|
"optional" in checks and checks["optional"] is True
|
|
|
|
]
|
|
|
|
)
|
|
|
|
+ "[#C0CAF5 bold]"
|
|
|
|
+ str(name)
|
|
|
|
+ "[#F7768E bold]=",
|
|
|
|
extra_info=checks["explanation"] if "explanation" in checks else "",
|
|
|
|
default=checks["default"] if "default" in checks else NotImplemented,
|
|
|
|
match=checks["regex"] if "regex" in checks else "",
|
|
|
|
err_message=checks["input_error"] if "input_error" in checks else "Incorrect input",
|
|
|
|
nmin=checks["nmin"] if "nmin" in checks else None,
|
|
|
|
nmax=checks["nmax"] if "nmax" in checks else None,
|
|
|
|
oob_error=checks["oob_error"]
|
|
|
|
if "oob_error" in checks
|
|
|
|
else "Input out of bounds(Value too high/low/long/short)",
|
|
|
|
)
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
def crawl_and_check(obj: dict, path: list, checks: dict = {}, name=""):
|
|
|
|
if len(path) == 0:
|
|
|
|
return check(obj, checks, name)
|
|
|
|
if path[0] not in obj.keys():
|
|
|
|
obj[path[0]] = {}
|
|
|
|
obj[path[0]] = crawl_and_check(obj[path[0]], path[1:], checks, path[0])
|
|
|
|
return obj
|
|
|
|
|
|
|
|
|
|
|
|
def check_vars(path, checks):
|
|
|
|
global config
|
|
|
|
crawl_and_check(config, path, checks)
|
|
|
|
|
|
|
|
|
|
|
|
def check_toml(template_file, config_file) -> bool:
|
|
|
|
try:
|
|
|
|
template = toml.load(template_file)
|
|
|
|
except Exception as error:
|
|
|
|
console.print(
|
|
|
|
f"[red bold]Encountered error when trying to to load {template_file}: {error}"
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
try:
|
|
|
|
global config
|
|
|
|
config = toml.load(config_file)
|
|
|
|
except (toml.TomlDecodeError):
|
|
|
|
console.print(
|
|
|
|
f"""[blue]Couldn't read {config_file}.
|
|
|
|
Overwrite it?(y/n)"""
|
|
|
|
)
|
|
|
|
if not input().startswith("y"):
|
|
|
|
print("Unable to read config, and not allowed to overwrite it. Giving up.")
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
with open(config_file, "w") as f:
|
|
|
|
f.write("")
|
|
|
|
except:
|
|
|
|
console.print(
|
|
|
|
f"[red bold]Failed to overwrite {config_file}. Giving up.\nSuggestion: check {config_file} permissions for the user."
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
except (FileNotFoundError):
|
|
|
|
console.print(
|
|
|
|
f"""[blue]Couldn't find {config_file}
|
|
|
|
Creating it now."""
|
|
|
|
)
|
|
|
|
try:
|
|
|
|
with open(config_file, "x") as f:
|
|
|
|
f.write("")
|
|
|
|
config = {}
|
|
|
|
except:
|
|
|
|
console.print(
|
|
|
|
f"[red bold]Failed to write to {config_file}. Giving up.\nSuggestion: check the folder's permissions for the user."
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
crawl(template, check_vars)
|
|
|
|
# pretty.pprint(config)
|
|
|
|
with open(config_file, "w") as f:
|
|
|
|
toml.dump(config, f)
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
check_toml(".config.template.toml", "config.toml")
|