From b5ca338d6cbe0d04a706fa68cbedad296731dee3 Mon Sep 17 00:00:00 2001 From: Romain J Date: Tue, 16 Feb 2021 19:28:30 +0100 Subject: [PATCH] fix(commands|Custom>alias): close TUXBOT-BOT-1A, close TUXBOT-BOT-1H, close TUXBOT-BOT-1J --- .gitignore | 5 +- Makefile | 68 ++++++--- README.rst | 4 +- compose/local/tuxbot/Dockerfile | 3 +- compose/production/tuxbot/Dockerfile | 8 +- compose/production/tuxbot/entrypoint | 25 ++-- local.yml | 1 + production.yml | 30 ++++ setup.cfg | 5 +- setup.py | 2 +- tuxbot/__run__.py | 65 +-------- tuxbot/cogs/Custom/custom.py | 14 +- tuxbot/cogs/Dev/config.py | 11 +- tuxbot/cogs/Logs/logs.py | 17 ++- tuxbot/cogs/Network/network.py | 5 +- tuxbot/core/bot.py | 34 +---- tuxbot/core/config.py | 24 +--- tuxbot/core/utils/data_manager.py | 39 ++--- tuxbot/setup.py | 203 +++++---------------------- 19 files changed, 198 insertions(+), 365 deletions(-) create mode 100644 production.yml diff --git a/.gitignore b/.gitignore index 19c4380..26437f8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,7 @@ build .ipython/ .env .envs/* -!.envs/.local/ \ No newline at end of file +!.envs/.local/ + + +data/settings/ \ No newline at end of file diff --git a/Makefile b/Makefile index 7d29761..f184cef 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,74 @@ -PYTHON = python -VENV = venv +ifeq ($(ISPROD), 1) + DOCKER_LOCAL := docker-compose -f production.yml +else + DOCKER_LOCAL := docker-compose -f local.yml +endif -XGETTEXT_FLAGS = --no-wrap --language='python' --keyword=_ --from-code='UTF-8' --msgid-bugs-address='rick@gnous.eu' --width=79 --package-name='Tuxbot-bot' +INSTANCE := preprod + +DOCKER_TUXBOT := $(DOCKER_LOCAL) run --rm tuxbot +VIRTUAL_ENV := venv +PYTHON_PATH := $(VIRTUAL_ENV)/bin/python + +XGETTEXT_FLAGS := --no-wrap --language='python' --keyword=_ --from-code='UTF-8' --msgid-bugs-address='rick@gnous.eu' --width=79 --package-name='Tuxbot-bot' # Init +.PHONY: main main: - $(PYTHON) -m venv --clear $(VENV) - $(VENV)/bin/pip install -U pip setuptools -install: - $(VENV)/bin/pip install . -install-dev: - $(VENV)/bin/pip install -r dev.requirements.txt -update: - $(VENV)/bin/pip install --upgrade --force-reinstall . -update_soft: - $(VENV)/bin/pip install --upgrade . + $(PYTHON_PATH) -m venv --clear $(VENV) + $(VIRTUAL_ENV)/bin/pip install -U pip setuptools + +.PHONY: install +install: + $(VIRTUAL_ENV)/bin/pip install . + +.PHONY: install-dev +install-dev: + $(VIRTUAL_ENV)/bin/pip install -r dev.requirements.txt + +.PHONY: update +update: + $(VIRTUAL_ENV)/bin/pip install --upgrade . + +.PHONY: update-all +update-all: + $(VIRTUAL_ENV)/bin/pip install --upgrade --force-reinstall . + +.PHONY: dev +dev: black update + tuxbot + +# Docker +.PHONY: docker +docker: + $(DOCKER_LOCAL) build + $(DOCKER_LOCAL) up -d + +.PHONY: docker-start +docker-start: + $(DOCKER_TUXBOT) tuxbot -dev: black update_soft - tuxbot dev # Blackify code +.PHONY: black black: - $(PYTHON) -m black `git ls-files "*.py"` --line-length=79 && $(PYTHON) -m pylint tuxbot + $(PYTHON_PATH) -m black `git ls-files "*.py"` --line-length=79 && $(PYTHON_PATH) -m pylint tuxbot # Translations +.PHONY: xgettext xgettext: for cog in tuxbot/cogs/*/; do \ xgettext `find $$cog -type f -name '*.py'` --output=$$cog/locales/messages.pot $(XGETTEXT_FLAGS); \ done + +.PHONY: msginit msginit: for cog in tuxbot/cogs/*/; do \ msginit --input=$$cog/locales/messages.pot --output=$$cog/locales/fr-FR.po --locale=fr_FR.UTF-8 --no-translator; \ msginit --input=$$cog/locales/messages.pot --output=$$cog/locales/en-US.po --locale=en_US.UTF-8 --no-translator; \ done + +.PHONY: msgmerge msgmerge: for cog in tuxbot/cogs/*/; do \ msgmerge --update $$cog/locales/fr-FR.po $$cog/locales/messages.pot; \ diff --git a/README.rst b/README.rst index 3e3d359..3947930 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ Installing the pre-requirements - The pre-requirements are: - - Python 3.8 or greater + - Python 3.9 or greater - Pip - Git @@ -134,7 +134,7 @@ To update the whole bot after a :bash:`git pull`, just execute $ make update -.. |image0| image:: https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10-%23007ec6 +.. |image0| image:: https://img.shields.io/badge/python-3.9%20%7C%203.10-%23007ec6 .. |image1| image:: https://img.shields.io/github/issues/Rom1-J/tuxbot-bot .. |image2| image:: https://img.shields.io/badge/code%20style-black-000000.svg .. |image3| image:: https://wakatime.com/badge/github/Rom1-J/tuxbot-bot.svg diff --git a/compose/local/tuxbot/Dockerfile b/compose/local/tuxbot/Dockerfile index 8fe7748..2782aea 100644 --- a/compose/local/tuxbot/Dockerfile +++ b/compose/local/tuxbot/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8-slim-buster +FROM python:3.9-slim-buster ENV PYTHONUNBUFFERED 1 ENV PYTHONDONTWRITEBYTECODE 1 @@ -19,6 +19,7 @@ RUN apt-get update \ # Requirements are installed here to ensure they will be cached. COPY ./dev.requirements.txt /app/dev.requirements.txt COPY ./tuxbot /app/tuxbot +COPY ./data /app/data COPY ./setup.cfg /app/setup.cfg COPY ./setup.py /app/setup.py RUN pip install -r /app/dev.requirements.txt diff --git a/compose/production/tuxbot/Dockerfile b/compose/production/tuxbot/Dockerfile index 2937348..1a17f8b 100644 --- a/compose/production/tuxbot/Dockerfile +++ b/compose/production/tuxbot/Dockerfile @@ -1,13 +1,9 @@ FROM node:10-stretch-slim as client-builder WORKDIR /app -COPY ./package.json /app -RUN npm install && npm cache clean --force -COPY . /app -RUN npm run build # Python build stage -FROM python:3.8-slim-buster +FROM python:3.9-slim-buster ENV PYTHONUNBUFFERED 1 @@ -26,8 +22,6 @@ RUN addgroup --system tuxbot \ && adduser --system --ingroup tuxbot tuxbot # Requirements are installed here to ensure they will be cached. -RUN pip install --no-cache-dir psycopg2==2.8.6 - COPY --chown=tuxbot:tuxbot ./compose/production/tuxbot/entrypoint /entrypoint RUN sed -i 's/\r$//g' /entrypoint RUN chmod +x /entrypoint diff --git a/compose/production/tuxbot/entrypoint b/compose/production/tuxbot/entrypoint index 2c5bec8..370e9f8 100644 --- a/compose/production/tuxbot/entrypoint +++ b/compose/production/tuxbot/entrypoint @@ -13,23 +13,24 @@ if [ -z "${POSTGRES_USER}" ]; then fi export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}" +echo "psql at: ${DATABASE_URL}" + postgres_ready() { python << END import sys -import psycopg2 +import asyncpg +import asyncio -try: - psycopg2.connect( - dbname="${POSTGRES_DB}", - user="${POSTGRES_USER}", - password="${POSTGRES_PASSWORD}", - host="${POSTGRES_HOST}", - port="${POSTGRES_PORT}", - ) -except psycopg2.OperationalError: - sys.exit(-1) -sys.exit(0) +async def main(): + try: + conn = await asyncpg.connect('postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}') + except Exception: + sys.exit(-1) + await conn.close() + sys.exit(0) + +asyncio.get_event_loop().run_until_complete(main()) END } diff --git a/local.yml b/local.yml index 88b6a94..c963680 100644 --- a/local.yml +++ b/local.yml @@ -9,6 +9,7 @@ services: build: context: . dockerfile: ./compose/local/tuxbot/Dockerfile + restart: always image: tuxbot_bot_local_tuxbot container_name: tuxbot depends_on: diff --git a/production.yml b/production.yml new file mode 100644 index 0000000..70e1ca5 --- /dev/null +++ b/production.yml @@ -0,0 +1,30 @@ +version: '3' + +volumes: + production_postgres_data: {} + production_postgres_data_backups: {} + production_traefik: {} + +services: + tuxbot: + build: + context: . + dockerfile: ./compose/production/tuxbot/Dockerfile + image: tuxbot_bot_production_tuxbot + depends_on: + - postgres + env_file: + - ./.envs/.production/.tuxbot + - ./.envs/.production/.postgres + command: /start + + postgres: + build: + context: . + dockerfile: ./compose/production/postgres/Dockerfile + image: tuxbot_bot_production_postgres + volumes: + - production_postgres_data:/var/lib/postgresql/data:Z + - production_postgres_data_backups:/backups:z + env_file: + - ./.envs/.production/.postgres diff --git a/setup.cfg b/setup.cfg index 19b5b6e..0a7cf8f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,9 +13,8 @@ platforms = linux [options] packages = find_namespace: -python_requires = >=3.8 +python_requires = >=3.9 install_requires = - appdirs==1.4.4 asyncpg==0.21.0 Babel==2.8.0 discord.py @ git+https://github.com/Rapptz/discord.py @@ -26,7 +25,7 @@ install_requires = psutil==5.7.2 pydig==0.3.0 rich==9.10.0 - sentry_sdk==0.20.0 + sentry_sdk>=0.20.2 structured_config==4.12 tortoise-orm==0.16.17 diff --git a/setup.py b/setup.py index 4b57aa4..f511dab 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ from setuptools import setup setup( - python_requires=">=3.8", + python_requires=">=3.9", ) diff --git a/tuxbot/__run__.py b/tuxbot/__run__.py index 5e58b04..f015cfc 100644 --- a/tuxbot/__run__.py +++ b/tuxbot/__run__.py @@ -5,20 +5,16 @@ import signal import sys import os from argparse import Namespace -from datetime import datetime import discord -import humanize import pip from rich.columns import Columns from rich.panel import Panel from rich.table import Table, box -from rich.text import Text from rich import print as rprint import tuxbot.logging from tuxbot.core.bot import Tux -from tuxbot.core import config from tuxbot.core.utils import data_manager from tuxbot.core.utils.console import console from . import __version__, version_info, ExitCodes @@ -28,41 +24,6 @@ log = logging.getLogger("tuxbot.main") BORDER_STYLE = "not dim" -def list_instances() -> None: - """List all available instances""" - app_config = config.ConfigFile( - data_manager.config_dir / "config.yaml", config.AppConfig - ).config - - console.print( - Panel("[bold green]Instances", style="green"), justify="center" - ) - console.print() - - columns = Columns(expand=True, padding=2, align="center") - for instance, details in app_config.Instances.items(): - active = details["active"] - last_run = ( - humanize.naturaltime( - datetime.now() - datetime.fromtimestamp(details["last_run"]) - ) - or "[i]unknown" - ) - - table = Table( - style="dim", border_style=BORDER_STYLE, box=box.HEAVY_HEAD - ) - table.add_column("Name") - table.add_column(("Running since" if active else "Last run")) - table.add_row(instance, last_run) - table.title = Text(instance, style="green" if active else "red") - columns.add_renderable(table) - console.print(columns) - console.print() - - sys.exit(os.EX_OK) - - def debug_info() -> None: """Show debug info relatives to the bot""" python_version = sys.version.replace("\n", "") @@ -134,7 +95,7 @@ def parse_cli_flags(args: list) -> Namespace: """ parser = argparse.ArgumentParser( description="Tuxbot - OpenSource bot", - usage="tuxbot [arguments]", + usage="tuxbot [arguments]", ) parser.add_argument( "--version", @@ -145,20 +106,9 @@ def parse_cli_flags(args: list) -> Namespace: parser.add_argument( "--debug", action="store_true", help="Show debug information." ) - parser.add_argument( - "--list-instances", - "-L", - action="store_true", - help="List all instance names", - ) parser.add_argument( "--token", "-T", type=str, help="Run Tuxbot with passed token" ) - parser.add_argument( - "instance_name", - nargs="?", - help="Name of the bot instance created during `tuxbot-setup`.", - ) args = parser.parse_args(args) @@ -206,7 +156,7 @@ async def run_bot(tux: Tux, cli_flags: Namespace) -> None: None When exiting, this function return None. """ - data_path = data_manager.data_path(tux.instance_name) + data_path = data_manager.data_path tuxbot.logging.init_logging(10, location=data_path / "logs") @@ -245,9 +195,7 @@ def run() -> None: tux = None cli_flags = parse_cli_flags(sys.argv[1:]) - if cli_flags.list_instances: - list_instances() - elif cli_flags.debug: + if cli_flags.debug: debug_info() elif cli_flags.version: rprint(f"Tuxbot V{version_info.major}") @@ -259,13 +207,6 @@ def run() -> None: asyncio.set_event_loop(loop) try: - if not cli_flags.instance_name: - console.print( - "[red]No instance provided ! " - "You can use 'tuxbot -L' to list all available instances" - ) - sys.exit(ExitCodes.CRITICAL) - tux = Tux( cli_flags=cli_flags, description="Tuxbot, made from and for OpenSource", diff --git a/tuxbot/cogs/Custom/custom.py b/tuxbot/cogs/Custom/custom.py index 21fe59e..fef9037 100644 --- a/tuxbot/cogs/Custom/custom.py +++ b/tuxbot/cogs/Custom/custom.py @@ -5,7 +5,7 @@ from discord.ext import commands from tuxbot.cogs.Custom.functions.converters import AliasConvertor from tuxbot.core.bot import Tux -from tuxbot.core.config import set_for_key, search_for +from tuxbot.core.config import set_for_key, search_for, set_if_none from tuxbot.core.config import Config from tuxbot.core.i18n import ( Translator, @@ -33,14 +33,14 @@ class Custom(commands.Cog, name="Custom"): # ========================================================================= # ========================================================================= + async def _get_aliases(self, ctx: ContextPlus) -> dict: + return search_for(self.bot.config.Users, ctx.author.id, "aliases") + async def _save_lang(self, ctx: ContextPlus, lang: str) -> None: set_for_key( self.bot.config.Users, ctx.author.id, Config.User, locale=lang ) - async def _get_aliases(self, ctx: ContextPlus) -> dict: - return search_for(self.bot.config.Users, ctx.author.id, "aliases") - async def _save_alias(self, ctx: ContextPlus, alias: dict) -> None: set_for_key( self.bot.config.Users, ctx.author.id, Config.User, alias=alias @@ -76,13 +76,17 @@ class Custom(commands.Cog, name="Custom"): @_custom.command(name="alias", aliases=["aliases"]) async def _custom_alias(self, ctx: ContextPlus, *, alias: AliasConvertor): - args = alias.split(" | ") + args = str(alias).split(" | ") command = args[0] alias = args[1] user_aliases = await self._get_aliases(ctx) + if not user_aliases: + set_if_none(self.bot.config.Users, ctx.author.id, Config.User) + user_aliases = await self._get_aliases(ctx) + if alias in user_aliases.keys(): return await ctx.send( _( diff --git a/tuxbot/cogs/Dev/config.py b/tuxbot/cogs/Dev/config.py index ac2ba2b..b6d2bcc 100644 --- a/tuxbot/cogs/Dev/config.py +++ b/tuxbot/cogs/Dev/config.py @@ -1,15 +1,10 @@ -from structured_config import Structure, StrField +from structured_config import Structure HAS_MODELS = False class DevConfig(Structure): - sentryKey: str = StrField("") + pass -extra = { - "sentryKey": { - "type": str, - "description": "Sentry KEY for error logging (https://sentry.io/)", - }, -} +extra = {} diff --git a/tuxbot/cogs/Logs/logs.py b/tuxbot/cogs/Logs/logs.py index 096c009..b39da3f 100644 --- a/tuxbot/cogs/Logs/logs.py +++ b/tuxbot/cogs/Logs/logs.py @@ -56,9 +56,7 @@ class Logs(commands.Cog, name="Logs"): self.gateway_worker.start() # pylint: disable=no-member self.__config: LogsConfig = ConfigFile( - str( - cogs_data_path(self.bot.instance_name, "Logs") / "config.yaml" - ), + str(cogs_data_path("Logs") / "config.yaml"), LogsConfig, ).config @@ -266,6 +264,19 @@ class Logs(commands.Cog, name="Logs"): e.timestamp = datetime.datetime.utcnow() await self.webhook("errors").send(embed=e) + e.description = _( + "```An error occurred, the bot owner has been advertised...```", + ctx, + self.bot.config, + ) + e.remove_field(0) + e.remove_field(1) + e.remove_field(1) + + e.set_footer(text=sentry_sdk.last_event_id()) + + await ctx.send(embed=e) + @commands.Cog.listener() async def on_socket_raw_send(self, data): if '"op":2' not in data and '"op":6' not in data: diff --git a/tuxbot/cogs/Network/network.py b/tuxbot/cogs/Network/network.py index 388ebfe..3dbbb6b 100644 --- a/tuxbot/cogs/Network/network.py +++ b/tuxbot/cogs/Network/network.py @@ -54,10 +54,7 @@ class Network(commands.Cog, name="Network"): def __init__(self, bot: Tux): self.bot = bot self.__config: NetworkConfig = ConfigFile( - str( - cogs_data_path(self.bot.instance_name, "Network") - / "config.yaml" - ), + str(cogs_data_path("Network") / "config.yaml"), NetworkConfig, ).config diff --git a/tuxbot/core/bot.py b/tuxbot/core/bot.py index d0d1c35..f6fad32 100644 --- a/tuxbot/core/bot.py +++ b/tuxbot/core/bot.py @@ -18,8 +18,7 @@ from tortoise import Tortoise from tuxbot import version_info from tuxbot.core.utils.data_manager import ( logs_data_path, - data_path, - config_dir, + config_file, ) from tuxbot.core.utils.functions.extra import ContextPlus from tuxbot.core.utils.functions.prefix import get_prefixes @@ -28,8 +27,6 @@ from tuxbot.core.config import ( Config, ConfigFile, search_for, - AppConfig, - set_for_key, ) from . import __version__, ExitCodes from . import exceptions @@ -57,17 +54,15 @@ class Tux(commands.AutoShardedBot): # it's a crash self.shutdown_code = ExitCodes.CRITICAL self.cli_flags = cli_flags - self.instance_name = self.cli_flags.instance_name self.last_exception = None - self.logs = logs_data_path(self.instance_name) + self.logs = logs_data_path() self.console = console self.stats = {"commands": Counter(), "socket": Counter()} - self.config: Config = ConfigFile( - str(data_path(self.instance_name) / "config.yaml"), Config - ).config + self.config: Config = ConfigFile(config_file, Config).config + self.instance_name = self.config.Core.instance_name async def _prefixes(bot, message) -> List[str]: prefixes = self.config.Core.prefixes @@ -157,14 +152,6 @@ class Tux(commands.AutoShardedBot): self.uptime = datetime.datetime.now() self.last_on_ready = self.uptime - app_config = ConfigFile(config_dir / "config.yaml", AppConfig).config - set_for_key( - app_config.Instances, - self.instance_name, - AppConfig.Instance, - active=True, - last_run=datetime.datetime.timestamp(self.uptime), - ) with self._progress["main"] as progress: progress.stop_task(self._progress["tasks"]["discord_connecting"]) @@ -189,6 +176,7 @@ class Tux(commands.AutoShardedBot): table.add_row(f"Language: {self.config.Core.locale}") table.add_row(f"Tuxbot Version: {__version__}") table.add_row(f"Discord.py Version: {discord.__version__}") + table.add_row(f"Instance name: {self.instance_name}") table.add_row(f"Shards: {self.shard_count}") table.add_row(f"Servers: {len(self.guilds)}") table.add_row(f"Users: {len(self.users)}") @@ -315,8 +303,8 @@ class Tux(commands.AutoShardedBot): task_id = self._progress["tasks"][ "discord_connecting" ] = progress.add_task( - "discord_connecting", - task_name="Connecting to Discord...", + "Connecting to Discord...", + task_name="discord_connecting", start=False, ) progress.update(task_id) @@ -327,14 +315,6 @@ class Tux(commands.AutoShardedBot): Todo: add postgresql logout here """ - app_config = ConfigFile(config_dir / "config.yaml", AppConfig).config - set_for_key( - app_config.Instances, - self.instance_name, - AppConfig.Instance, - active=False, - ) - with self._progress["main"] as progress: for task in self._progress["tasks"]: progress.log("Shutting down", task) diff --git a/tuxbot/core/config.py b/tuxbot/core/config.py index 465cc99..2afc11a 100644 --- a/tuxbot/core/config.py +++ b/tuxbot/core/config.py @@ -11,7 +11,6 @@ from structured_config import ( __all__ = [ "Config", "ConfigFile", - "AppConfig", "search_for", "set_for_key", "set_for", @@ -60,20 +59,7 @@ class Config(Structure): mentionable: bool = BoolField("") locale: str = StrField("") disabled_command: List[str] = [] - - -# ============================================================================= -# Configuration of Tuxbot Application (not the bot) -# ============================================================================= - - -class AppConfig(Structure): - class Instance(Structure): - path: str = StrField("") - active: bool = BoolField(False) - last_run: int = IntField(0) - - Instances: Dict[str, Instance] = {} + instance_name: str = StrField("") # ============================================================================= @@ -87,6 +73,11 @@ def search_for(config, key, value, default=False) -> Any: return default +def set_if_none(config, key, ctype) -> None: + if key not in config: + config[key] = ctype() + + def set_for_key(config, key, ctype, **values) -> None: # pylint: disable=anomalous-backslash-in-string """ @@ -105,8 +96,7 @@ def set_for_key(config, key, ctype, **values) -> None: rip roxy .*' / .*' ; .*`- +' `*' 201?-2020 :,( `*-* `*-* `*-*' """ - if key not in config: - config[key] = ctype() + set_if_none(config, key, ctype) for k, v in values.items(): setattr(config[key], k, v) diff --git a/tuxbot/core/utils/data_manager.py b/tuxbot/core/utils/data_manager.py index ad8eafd..e9dc858 100644 --- a/tuxbot/core/utils/data_manager.py +++ b/tuxbot/core/utils/data_manager.py @@ -1,51 +1,32 @@ import logging from pathlib import Path - -import appdirs +import os log = logging.getLogger("tuxbot.core.data_manager") -app_dir = appdirs.AppDirs("Tuxbot-bot") -config_dir = Path(app_dir.user_config_dir) -config_file = config_dir / "config.yaml" +core_path = Path(os.getcwd()) + +data_path = core_path / "data" +config_path = data_path / "settings" +config_file = config_path / "config.yaml" -def data_path(instance_name: str) -> Path: - """Return Path for data configs. - - Parameters - ---------- - instance_name:str - - Returns - ------- - Path - Generated path for data configs. - """ - return Path(app_dir.user_data_dir) / "data" / instance_name - - -def logs_data_path(instance_name: str) -> Path: +def logs_data_path() -> Path: """Return Path for Logs. - Parameters - ---------- - instance_name:str - Returns ------- Path Generated path for Logs files. """ - return data_path(instance_name) / "logs" + return data_path / "logs" -def cogs_data_path(instance_name: str, cog_name: str = "") -> Path: +def cogs_data_path(cog_name: str = "") -> Path: """Return Path for cogs. Parameters ---------- - instance_name:str cog_name:str Returns @@ -53,4 +34,4 @@ def cogs_data_path(instance_name: str, cog_name: str = "") -> Path: Path Generated path for cogs configs. """ - return data_path(instance_name) / "cogs" / cog_name + return data_path / "settings" / "cogs" / cog_name diff --git a/tuxbot/setup.py b/tuxbot/setup.py index 231a85c..bff52ff 100644 --- a/tuxbot/setup.py +++ b/tuxbot/setup.py @@ -17,31 +17,26 @@ from rich.style import Style from rich.traceback import install from tuxbot import version_info -from tuxbot.core.config import set_for, set_for_key +from tuxbot.core.config import set_for from tuxbot.logging import formatter -from tuxbot.core.utils.data_manager import config_dir, app_dir, cogs_data_path +from tuxbot.core.utils.data_manager import ( + config_path, + config_file, + cogs_data_path, +) from tuxbot.core import config console = Console() -install(console=console) +install(console=console, show_locals=True) try: - config_dir.mkdir(parents=True, exist_ok=True) + config_path.mkdir(parents=True, exist_ok=True) except PermissionError: console.print( - f"mkdir: cannot create directory '{config_dir}': Permission denied" + f"mkdir: cannot create directory '{config_path}': Permission denied" ) sys.exit(1) -app_config = config.ConfigFile( - config_dir / "config.yaml", config.AppConfig -).config - -if not app_config.Instances: - instances_list = [] -else: - instances_list = list(app_config.Instances.keys()) - def get_name() -> str: """Get instance name via input. @@ -66,80 +61,6 @@ def get_name() -> str: return name -def get_data_dir(instance_name: str) -> Path: - """Returning data path. - - Parameters - ---------- - instance_name:str - Instance name. - - Returns - ------- - Path - The data config path corresponding to the instance. - - """ - data_path = Path(app_dir.user_data_dir) / "data" / instance_name - data_path_input = "" - console.print() - - def make_data_dir(path: Path) -> Union[Path, str]: - try: - path.mkdir(parents=True, exist_ok=True) - except OSError: - console.print() - console.print( - f"mkdir: cannot create directory '{path}': Permission denied" - ) - path = "" - - return path - - while not data_path_input: - data_path_input = Path( - Prompt.ask( - "where do you want to save the configurations?", - default=str(data_path), - console=console, - ) - ) - - try: - exists = data_path_input.exists() - except OSError: - console.print() - console.print( - "[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) - - console.print() - console.print( - f"You have chosen {data_path_input} to be your config directory for " - f"`{instance_name}` instance" - ) - - if ( - Prompt.ask( - "Please confirm", choices=["y", "n"], default="y", console=console - ) - != "y" - ): - console.print("Rerun the process to redo this configuration.") - sys.exit(0) - - (data_path_input / "Logs").mkdir(parents=True, exist_ok=True) - - return data_path_input - - def get_token() -> str: """Get token via input. @@ -250,7 +171,7 @@ def get_extra(question: str, value_type: type) -> Union[str, int]: return prompt.ask(question, console=console) -def additional_config(instance: str, cogs: str = "**"): +def additional_config(cogs: str = "**"): """Asking for additional configs in cogs. Returns @@ -277,7 +198,7 @@ def additional_config(instance: str, cogs: str = "**"): mod_extra = mod.extra mod_config = config.ConfigFile( - str(cogs_data_path(instance, cog_name) / "config.yaml"), + str(cogs_data_path(cog_name) / "config.yaml"), mod_config_type, ).config @@ -296,14 +217,10 @@ def additional_config(instance: str, cogs: str = "**"): ) -def finish_setup(data_dir: Path) -> None: - """Configs who directly refer to the bot. +def finish_setup() -> None: + """Configs who directly refer to the bot.""" + name = get_name() - Parameters - ---------- - data_dir:Path - Where to save configs. - """ console.print( Rule("Now, it's time to finish this setup by giving bot information") ) @@ -363,22 +280,21 @@ def finish_setup(data_dir: Path) -> None: ), } - instance_config = config.ConfigFile( - str(data_dir / "config.yaml"), config.Config - ) + _config_file = config.ConfigFile(str(config_file), config.Config) - instance_config.config.Core.owners_id = owners_id - instance_config.config.Core.prefixes = prefixes - instance_config.config.Core.token = token - instance_config.config.Core.ip = ip - instance_config.config.Core.mentionable = mentionable - instance_config.config.Core.locale = "en-US" + _config_file.config.Core.owners_id = owners_id + _config_file.config.Core.prefixes = prefixes + _config_file.config.Core.token = token + _config_file.config.Core.ip = ip + _config_file.config.Core.mentionable = mentionable + _config_file.config.Core.locale = "en-US" + _config_file.config.Core.instance_name = name - instance_config.config.Core.Database.username = database["username"] - instance_config.config.Core.Database.password = database["password"] - instance_config.config.Core.Database.domain = database["domain"] - instance_config.config.Core.Database.port = database["port"] - instance_config.config.Core.Database.db_name = database["db_name"] + _config_file.config.Core.Database.username = database["username"] + _config_file.config.Core.Database.password = database["password"] + _config_file.config.Core.Database.domain = database["domain"] + _config_file.config.Core.Database.port = database["port"] + _config_file.config.Core.Database.db_name = database["db_name"] def basic_setup() -> None: @@ -388,47 +304,15 @@ def basic_setup() -> None: "Hi ! it's time for you to give me information about you instance" ) ) - console.print() - name = get_name() - data_dir = get_data_dir(name) - - if name in instances_list: - console.print() - console.print( - f"WARNING: An instance named `{name}` already exists " - f"Continuing will overwrite this instance configs.", - style="red", - ) - if ( - Prompt.ask( - "Are you sure you want to continue?", - choices=["y", "n"], - default="n", - ) - == "n" - ): - console.print("Abandon...") - sys.exit(0) - - set_for_key( - app_config.Instances, - name, - config.AppConfig.Instance, - path=str(data_dir.resolve()), - active=False, - ) - - console.print("\n" * 4) - - finish_setup(data_dir) + finish_setup() console.print() console.print( - f"Instance successfully created! " - f"You can now run `tuxbot {name}` to launch this instance now or " - f"setup the additional configs by running " - f"`tuxbot-setup {name} --additional-config=all`" + "Instance successfully created! " + "You can now run `tuxbot` to launch it now or " + "setup the additional configs by running " + "`tuxbot-setup --additional-config=all`" ) @@ -440,10 +324,7 @@ def update() -> None: ) if response.get("sha")[:6] == version_info.build: - print( - "Nothing to update, you can run `tuxbot [instance_name]` " - "to start the bot" - ) + print("Nothing to update, you can run `tuxbot` " "to start the bot") else: print(f"Updating to {response.get('sha')[:6]}...") @@ -465,12 +346,7 @@ def parse_cli_flags(args: list) -> Namespace: """ parser = argparse.ArgumentParser( description="Tuxbot Setup - OpenSource bot", - usage="tuxbot-setup [instance] [arguments]", - ) - parser.add_argument( - "instance_name", - nargs="?", - help="Name of the bot instance to edit.", + usage="tuxbot-setup [arguments]", ) parser.add_argument( "-a", @@ -507,15 +383,8 @@ def setup() -> None: stdout_handler.setFormatter(formatter) base_logger.addHandler(stdout_handler) - if cli_flags.additional_config and not cli_flags.instance_name: - console.print( - "[red]No instance to modify provided ! " - "You can use 'tuxbot -L' to list all available instances" - ) - elif cli_flags.instance_name: - additional_config( - cli_flags.instance_name, cli_flags.additional_config - ) + if cli_flags.additional_config: + additional_config(cli_flags.additional_config) else: console.clear() basic_setup()