tuxbot-bot/tuxbot/setup.py

348 lines
8.6 KiB
Python
Raw Normal View History

2020-06-03 18:24:38 +02:00
import json
import logging
import re
import sys
from pathlib import Path
2020-08-26 17:15:38 +02:00
from typing import NoReturn, Union, List
2020-06-03 18:24:38 +02:00
2020-08-26 17:15:38 +02:00
from rich.prompt import Prompt, IntPrompt
from rich.console import Console
from rich.rule import Rule
2020-08-28 01:06:57 +02:00
from rich.traceback import install
2020-06-03 18:24:38 +02:00
2020-06-03 19:41:30 +02:00
from tuxbot.core.data_manager import config_dir, app_dir
2020-09-02 00:08:06 +02:00
from tuxbot.core import config
2020-06-03 18:24:38 +02:00
2020-08-26 17:15:38 +02:00
console = Console()
console.clear()
2020-08-28 01:06:57 +02:00
install(console=console)
2020-06-03 18:24:38 +02:00
try:
config_dir.mkdir(parents=True, exist_ok=True)
except PermissionError:
2020-09-02 00:08:06 +02:00
console.print(f"mkdir: cannot create directory '{config_dir}': Permission denied")
2020-06-03 18:24:38 +02:00
sys.exit(1)
2020-09-02 00:08:06 +02:00
app_config = config.ConfigFile(config_dir / "config.yaml", config.AppConfig)
2020-06-03 18:24:38 +02:00
2020-09-02 00:08:06 +02:00
if not app_config.config.instances:
2020-06-03 18:24:38 +02:00
instances_list = []
else:
2020-09-02 00:08:06 +02:00
instances_list = list(app_config.config.instances.keys())
2020-06-03 18:24:38 +02:00
def get_name() -> str:
2020-06-04 00:46:53 +02:00
"""Get instance name via input.
Returns
-------
str
The instance name choose by user.
"""
2020-06-03 18:24:38 +02:00
name = ""
while not name:
2020-08-26 17:15:38 +02:00
name = Prompt.ask(
2020-06-03 18:24:38 +02:00
"What name do you want to give this instance?\n"
2020-08-26 17:15:38 +02:00
"[i](valid characters: A-Z, a-z, 0-9, _, -)[/i]\n",
default="prod",
console=console
2020-06-03 18:24:38 +02:00
)
if re.fullmatch(r"[a-zA-Z0-9_\-]*", name) is None:
2020-09-02 00:08:06 +02:00
console.print()
console.print("[prompt.invalid]ERROR: Invalid characters provided")
2020-06-03 18:24:38 +02:00
name = ""
return name
def get_data_dir(instance_name: str) -> Path:
2020-06-04 00:46:53 +02:00
"""Returning data path.
Parameters
----------
instance_name:str
Instance name.
Returns
-------
Path
The data config path corresponding to the instance.
"""
2020-06-03 18:24:38 +02:00
data_path = Path(app_dir.user_data_dir) / "data" / instance_name
data_path_input = ""
2020-09-02 00:08:06 +02:00
console.print()
2020-06-03 18:24:38 +02:00
def make_data_dir(path: Path) -> Union[Path, str]:
try:
path.mkdir(parents=True, exist_ok=True)
except OSError:
2020-09-02 00:08:06 +02:00
console.print()
console.print(
2020-08-26 17:15:38 +02:00
f"mkdir: cannot create directory '{path}': Permission denied"
2020-06-03 18:24:38 +02:00
)
path = ""
return path
while not data_path_input:
2020-08-26 17:15:38 +02:00
data_path_input = Path(
Prompt.ask(
"where do you want to save the configurations?",
default=str(data_path),
console=console
)
2020-06-03 18:24:38 +02:00
)
2020-08-26 17:15:38 +02:00
try:
exists = data_path_input.exists()
except OSError:
2020-09-02 00:08:06 +02:00
console.print()
console.print(
2020-08-26 17:15:38 +02:00
"[prompt.invalid]"
"Impossible to verify the validity of the path,"
" make sure it does not contain any invalid characters."
)
data_path_input = ""
exists = False
if data_path_input and not exists:
data_path_input = make_data_dir(data_path_input)
2020-06-03 18:24:38 +02:00
2020-09-02 00:08:06 +02:00
console.print()
console.print(
2020-06-03 18:24:38 +02:00
f"You have chosen {data_path_input} to be your config directory for "
f"`{instance_name}` instance"
)
2020-08-26 17:15:38 +02:00
if Prompt.ask(
"Please confirm",
choices=["y", "n"], default="y",
console=console
) != "y":
2020-09-02 00:08:06 +02:00
console.print("Rerun the process to redo this configuration.")
2020-06-03 18:24:38 +02:00
sys.exit(0)
2020-06-06 18:51:47 +02:00
(data_path_input / "core").mkdir(parents=True, exist_ok=True)
(data_path_input / "cogs").mkdir(parents=True, exist_ok=True)
(data_path_input / "logs").mkdir(parents=True, exist_ok=True)
2020-06-03 18:24:38 +02:00
return data_path_input
def get_token() -> str:
2020-06-04 00:46:53 +02:00
"""Get token via input.
Returns
-------
str
The token choose by user.
"""
2020-06-03 18:24:38 +02:00
token = ""
while not token:
2020-08-26 17:15:38 +02:00
token = Prompt.ask(
"Please enter the bot token "
"(you can find it at https://discord.com/developers/applications)",
console=console
2020-06-03 18:24:38 +02:00
)
2020-08-26 17:15:38 +02:00
if re.fullmatch(
r"([a-zA-Z0-9]{24}\.[a-zA-Z0-9_]{6}\.[a-zA-Z0-9_\-]{27}"
r"|mfa\.[a-zA-Z0-9_\-]{84})",
token) \
is None:
2020-09-02 00:08:06 +02:00
console.print("[prompt.invalid]ERROR: Invalid token provided")
2020-06-03 18:24:38 +02:00
token = ""
return token
2020-06-06 18:51:47 +02:00
def get_multiple(
2020-08-26 17:15:38 +02:00
question: str, confirmation: str, value_type: type
2020-06-06 18:51:47 +02:00
) -> List[Union[str, int]]:
2020-06-04 00:46:53 +02:00
"""Give possibility to user to fill multiple value.
Parameters
----------
question:str
First question.
confirmation:str
Asking text if user want to add another.
value_type:type
The type of values inside the list.
Returns
-------
List[Union[str, int]]
List containing user filled values.
"""
2020-08-26 17:15:38 +02:00
prompt = IntPrompt if value_type is int else Prompt
user_input = prompt.ask(question, console=console)
if not user_input:
return []
values = [user_input]
2020-06-03 18:24:38 +02:00
2020-08-26 17:15:38 +02:00
while Prompt.ask(
confirmation,
choices=["y", "n"], default="y",
console=console
) != "n":
new = prompt.ask("Other")
if new not in values:
values.append(new)
else:
2020-09-02 00:08:06 +02:00
console.print(
2020-08-26 17:15:38 +02:00
f"[prompt.invalid]"
f"ERROR: `{new}` is already present, [i]ignored[/i]"
)
2020-06-03 18:24:38 +02:00
return values
2020-06-03 18:24:38 +02:00
def additional_config() -> dict:
2020-06-04 00:46:53 +02:00
"""Asking for additional configs in cogs.
Returns
-------
dict:
Dict with cog name as key and configs as value.
"""
2020-09-02 00:08:06 +02:00
p = Path("tuxbot/cogs").glob("**/config.py")
2020-08-26 17:15:38 +02:00
data = {}
2020-06-03 18:24:38 +02:00
for file in p:
2020-09-02 00:08:06 +02:00
console.print("\n" * 4)
2020-06-06 18:51:47 +02:00
cog_name = str(file.parent).split("/")[-1]
2020-08-26 17:15:38 +02:00
data[cog_name] = {}
2020-06-03 18:24:38 +02:00
2020-06-06 18:51:47 +02:00
with file.open("r") as f:
2020-06-03 18:24:38 +02:00
data = json.load(f)
2020-09-02 00:08:06 +02:00
console.print(Rule(f"\nConfiguration for `{cog_name}` module"))
2020-06-03 18:24:38 +02:00
for key, value in data.items():
2020-09-02 00:08:06 +02:00
console.print()
2020-08-26 17:15:38 +02:00
data[cog_name][key] = Prompt.ask(value["description"])
2020-06-03 18:24:38 +02:00
2020-08-26 17:15:38 +02:00
return data
2020-06-03 18:24:38 +02:00
def finish_setup(data_dir: Path) -> NoReturn:
2020-06-04 00:46:53 +02:00
"""Configs who directly refer to the bot.
Parameters
----------
data_dir:Path
Where to save configs.
"""
2020-09-02 00:08:06 +02:00
console.print(
2020-08-26 17:15:38 +02:00
Rule(
"Now, it's time to finish this setup by giving bot information"
)
)
2020-09-02 00:08:06 +02:00
console.print()
2020-06-03 18:24:38 +02:00
token = get_token()
2020-08-26 17:15:38 +02:00
2020-09-02 00:08:06 +02:00
console.print()
2020-06-03 19:41:30 +02:00
prefixes = get_multiple(
2020-08-26 17:15:38 +02:00
"Choice a (or multiple) prefix for the bot", "Add another prefix ?",
str
2020-06-03 19:41:30 +02:00
)
2020-09-02 00:08:06 +02:00
console.print()
2020-08-26 17:15:38 +02:00
mentionable = Prompt.ask(
"Does the bot answer if it's mentioned?",
choices=["y", "n"],
default="y"
) == "y"
2020-09-02 00:08:06 +02:00
console.print()
2020-06-03 19:41:30 +02:00
owners_id = get_multiple(
2020-06-06 18:51:47 +02:00
"Give the owner id of this bot", "Add another owner ?", int
2020-06-03 19:41:30 +02:00
)
2020-06-03 18:24:38 +02:00
2020-09-02 00:08:06 +02:00
# cogs_config = additional_config()
2020-06-03 18:24:38 +02:00
2020-09-02 00:08:06 +02:00
instance_config = config.ConfigFile(
str(data_dir / "config.yaml"), config.Config
)
2020-06-03 18:24:38 +02:00
2020-09-02 00:08:06 +02:00
instance_config.config.Core.owners_id = owners_id
instance_config.config.Core.prefixes = prefixes
instance_config.config.Core.token = token
instance_config.config.Core.mentionable = mentionable
instance_config.config.Core.locale = "en-US"
2020-06-03 18:24:38 +02:00
def basic_setup() -> NoReturn:
2020-06-04 00:46:53 +02:00
"""Configs who refer to instances.
"""
2020-09-02 00:08:06 +02:00
console.print(
2020-08-26 17:15:38 +02:00
Rule(
"Hi ! it's time for you to give me information about you instance"
)
)
2020-09-02 00:08:06 +02:00
console.print()
2020-06-03 18:24:38 +02:00
name = get_name()
data_dir = get_data_dir(name)
if name in instances_list:
2020-09-02 00:08:06 +02:00
console.print()
2020-08-26 17:15:38 +02:00
console.print(
f"WARNING: An instance named `{name}` already exists "
f"Continuing will overwrite this instance configs.", style="red"
2020-06-03 18:24:38 +02:00
)
2020-08-26 17:15:38 +02:00
if Prompt.ask(
"Are you sure you want to continue?",
choices=["y", "n"], default="n"
) == "n":
2020-09-02 00:08:06 +02:00
console.print("Abandon...")
2020-06-03 18:24:38 +02:00
sys.exit(0)
2020-09-02 00:08:06 +02:00
instance = config.Instance()
instance.path = str(data_dir.resolve())
instance.active = False
app_config.config.instances[name] = instance
2020-06-03 18:24:38 +02:00
2020-09-02 00:08:06 +02:00
console.print("\n" * 4)
2020-06-03 18:24:38 +02:00
finish_setup(data_dir)
2020-09-02 00:08:06 +02:00
console.print()
console.print(
2020-06-03 18:24:38 +02:00
f"Instance successfully created! "
f"You can now run `tuxbot {name}` to launch this instance"
)
2020-06-04 00:46:53 +02:00
def setup() -> NoReturn:
2020-06-03 18:24:38 +02:00
try:
"""Create a new instance."""
level = logging.DEBUG
2020-06-03 19:41:30 +02:00
base_logger = logging.getLogger("tuxbot")
2020-06-03 18:24:38 +02:00
base_logger.setLevel(level)
formatter = logging.Formatter(
"[{asctime}] [{levelname}] {name}: {message}",
2020-06-06 18:51:47 +02:00
datefmt="%Y-%m-%d %H:%M:%S",
style="{",
2020-06-03 18:24:38 +02:00
)
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setFormatter(formatter)
base_logger.addHandler(stdout_handler)
basic_setup()
except KeyboardInterrupt:
2020-09-02 00:08:06 +02:00
console.print("Exiting...")
except Exception:
2020-08-28 01:06:57 +02:00
console.print_exception()
2020-06-03 18:24:38 +02:00
if __name__ == "__main__":
setup()