Compare commits
3 commits
1f88499d44
...
331599eb38
Author | SHA1 | Date | |
---|---|---|---|
Romain J | 331599eb38 | ||
Romain J | 9a0786af7c | ||
Romain J | c1e253689d |
2
.github/issue_template.md
vendored
2
.github/issue_template.md
vendored
|
@ -25,4 +25,4 @@ If applicable, add screenshots to help explain your problem.
|
||||||
- Python Version [e.g. 3.7.4]
|
- Python Version [e.g. 3.7.4]
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
<-- Add any other context about the problem here. -->
|
|
@ -1,16 +1,22 @@
|
||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="romain">
|
<dictionary name="romain">
|
||||||
<words>
|
<words>
|
||||||
|
<w>asctime</w>
|
||||||
<w>commandstats</w>
|
<w>commandstats</w>
|
||||||
<w>francais</w>
|
<w>francais</w>
|
||||||
<w>ipinfo</w>
|
<w>ipinfo</w>
|
||||||
<w>iplocalise</w>
|
<w>iplocalise</w>
|
||||||
|
<w>jishaku</w>
|
||||||
|
<w>levelname</w>
|
||||||
<w>localiseip</w>
|
<w>localiseip</w>
|
||||||
<w>postgresql</w>
|
<w>postgresql</w>
|
||||||
|
<w>releaselevel</w>
|
||||||
<w>socketstats</w>
|
<w>socketstats</w>
|
||||||
<w>splt</w>
|
<w>splt</w>
|
||||||
<w>systemd</w>
|
<w>systemd</w>
|
||||||
<w>tutux</w>
|
<w>tutux</w>
|
||||||
|
<w>tuxbot</w>
|
||||||
|
<w>tuxbot's</w>
|
||||||
<w>tuxvenv</w>
|
<w>tuxvenv</w>
|
||||||
<w>webhooks</w>
|
<w>webhooks</w>
|
||||||
</words>
|
</words>
|
||||||
|
|
|
@ -39,12 +39,12 @@ Continue to [create the venv](#creating-the-virtual-environnement).
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
*go to hell*
|
*not for now and not for the future*
|
||||||
|
|
||||||
|
|
||||||
## Creating the Virtual Environnement
|
## Creating the Virtual Environment
|
||||||
|
|
||||||
To set up the virtual environnement and install the bot, simply run this two commands:
|
To set up the virtual environment and install the bot, simply run this two commands:
|
||||||
|
|
||||||
```shell script
|
```shell script
|
||||||
make
|
make
|
||||||
|
|
|
@ -24,11 +24,11 @@ install_requires =
|
||||||
certifi==2020.4.5.1
|
certifi==2020.4.5.1
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
ciso8601==2.1.3
|
ciso8601==2.1.3
|
||||||
click==7.1.2
|
|
||||||
colorama==0.4.3
|
colorama==0.4.3
|
||||||
discord-flags==2.1.1
|
discord-flags==2.1.1
|
||||||
discord.py==1.3.3
|
discord.py==1.3.4
|
||||||
dnspython==1.16.0
|
dnspython==1.16.0
|
||||||
|
flatten-dict==0.3.0
|
||||||
humanize==2.4.0
|
humanize==2.4.0
|
||||||
idna==2.9
|
idna==2.9
|
||||||
import-expression==1.1.3
|
import-expression==1.1.3
|
||||||
|
@ -43,13 +43,13 @@ install_requires =
|
||||||
pytz==2020.1
|
pytz==2020.1
|
||||||
regex==2020.6.7
|
regex==2020.6.7
|
||||||
requests==2.23.0
|
requests==2.23.0
|
||||||
|
rich==6.0.0
|
||||||
six==1.15.0
|
six==1.15.0
|
||||||
toml>=0.9.4
|
toml>=0.9.4
|
||||||
tortoise-orm==0.16.13
|
tortoise-orm==0.16.13
|
||||||
typed-ast>=1.4.0
|
typed-ast>=1.4.0
|
||||||
typing-extensions==3.7.4.2
|
typing-extensions==3.7.4.2
|
||||||
urllib3==1.25.9
|
urllib3==1.25.9
|
||||||
websockets==8.1
|
|
||||||
wheel==0.34.2
|
wheel==0.34.2
|
||||||
yarl==1.4.2
|
yarl==1.4.2
|
||||||
|
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -1,3 +1,5 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(python_requires=">=3.7")
|
setup(
|
||||||
|
python_requires=">=3.7",
|
||||||
|
)
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import subprocess
|
import os
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
build = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).decode()
|
build = os.popen('git rev-parse --short HEAD').read().strip()
|
||||||
|
info = os.popen('git log -n 1 -s --format="%s"').read().strip()
|
||||||
|
|
||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro releaselevel build")
|
VersionInfo = namedtuple(
|
||||||
version_info = VersionInfo(major=3, minor=0, micro=0, releaselevel="alpha", build=build)
|
"VersionInfo", "major minor micro releaselevel build, info"
|
||||||
|
)
|
||||||
|
version_info = VersionInfo(
|
||||||
|
major=3, minor=0, micro=0,
|
||||||
|
releaselevel="alpha", build=build, info=info
|
||||||
|
)
|
||||||
|
|
||||||
__version__ = "v{}.{}.{}-{}.{}".format(
|
__version__ = "v{}.{}.{}-{}.{}".format(
|
||||||
version_info.major,
|
version_info.major,
|
||||||
|
@ -13,3 +19,9 @@ __version__ = "v{}.{}.{}-{}.{}".format(
|
||||||
version_info.releaselevel,
|
version_info.releaselevel,
|
||||||
version_info.build,
|
version_info.build,
|
||||||
).replace("\n", "")
|
).replace("\n", "")
|
||||||
|
|
||||||
|
|
||||||
|
class ExitCodes:
|
||||||
|
CRITICAL = 1
|
||||||
|
SHUTDOWN = 0
|
||||||
|
RESTART = 42
|
||||||
|
|
|
@ -1,27 +1,34 @@
|
||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import getpass
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import platform
|
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import pip
|
import pip
|
||||||
from colorama import Fore, init, Style
|
import tracemalloc
|
||||||
from pip._vendor import distro
|
from rich.columns import Columns
|
||||||
|
from rich.console import Console
|
||||||
|
from rich.panel import Panel
|
||||||
|
from rich.traceback import install
|
||||||
|
from rich.table import Table, box
|
||||||
|
from rich.text import Text
|
||||||
|
from rich import print
|
||||||
|
|
||||||
import tuxbot.logging
|
import tuxbot.logging
|
||||||
from tuxbot.core import data_manager
|
from tuxbot.core import data_manager
|
||||||
from tuxbot.core.bot import Tux, ExitCodes
|
from tuxbot.core.bot import Tux
|
||||||
from tuxbot.core.utils.functions.cli import bordered
|
from . import __version__, version_info, ExitCodes
|
||||||
from . import __version__
|
|
||||||
|
|
||||||
log = logging.getLogger("tuxbot.main")
|
log = logging.getLogger("tuxbot.main")
|
||||||
init()
|
|
||||||
|
console = Console()
|
||||||
|
install(console=console)
|
||||||
|
tracemalloc.start()
|
||||||
|
|
||||||
|
|
||||||
def list_instances() -> NoReturn:
|
def list_instances() -> NoReturn:
|
||||||
|
@ -29,21 +36,38 @@ def list_instances() -> NoReturn:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with data_manager.config_file.open() as fs:
|
with data_manager.config_file.open() as fs:
|
||||||
datas = json.load(fs)
|
data = json.load(fs)
|
||||||
|
|
||||||
info = {"title": "Instances", "rows": []}
|
console.print(
|
||||||
|
Panel("[bold green]Instances", style="green"),
|
||||||
|
justify="center"
|
||||||
|
)
|
||||||
|
console.print()
|
||||||
|
|
||||||
for instance, details in datas.items():
|
columns = Columns(expand=True, padding=2, align="center")
|
||||||
info["rows"].append(
|
for instance, details in data.items():
|
||||||
f"-> {instance} " f"{'up' if details.get('IS_RUNNING') else 'down'}"
|
is_running = details.get('IS_RUNNING')
|
||||||
|
|
||||||
|
table = Table(
|
||||||
|
style="dim", border_style="not dim",
|
||||||
|
box=box.HEAVY_HEAD
|
||||||
)
|
)
|
||||||
|
table.add_column("Name")
|
||||||
|
table.add_column(("Running" if is_running else "Down") + " since")
|
||||||
|
table.add_row(instance, "42")
|
||||||
|
table.title = Text(
|
||||||
|
instance,
|
||||||
|
style="green" if is_running else "red"
|
||||||
|
)
|
||||||
|
columns.add_renderable(table)
|
||||||
|
console.print(columns)
|
||||||
|
console.print()
|
||||||
|
|
||||||
print(bordered(info))
|
sys.exit(os.EX_OK)
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
def debug_info() -> NoReturn:
|
def debug_info() -> NoReturn:
|
||||||
"""Show debug infos relatives to the bot
|
"""Show debug info relatives to the bot
|
||||||
|
|
||||||
"""
|
"""
|
||||||
python_version = sys.version.replace("\n", "")
|
python_version = sys.version.replace("\n", "")
|
||||||
|
@ -51,29 +75,65 @@ def debug_info() -> NoReturn:
|
||||||
tuxbot_version = __version__
|
tuxbot_version = __version__
|
||||||
dpy_version = discord.__version__
|
dpy_version = discord.__version__
|
||||||
|
|
||||||
os_info = distro.linux_distribution()
|
uptime = os.popen('uptime').read().strip().split()
|
||||||
os_info = f"{os_info[0]} {os_info[1]}"
|
|
||||||
|
|
||||||
runner = getpass.getuser()
|
console.print(
|
||||||
|
Panel("[bold blue]Debug Info", style="blue"),
|
||||||
|
justify="center"
|
||||||
|
)
|
||||||
|
console.print()
|
||||||
|
|
||||||
info = {
|
columns = Columns(expand=True, padding=2, align="center")
|
||||||
"title": "Debug Info",
|
|
||||||
"rows": [
|
|
||||||
f"Tuxbot version: {tuxbot_version}",
|
|
||||||
"",
|
|
||||||
f"Python version: {python_version}",
|
|
||||||
f"Python executable path: {sys.executable}",
|
|
||||||
f"Pip version: {pip_version}",
|
|
||||||
f"Discord.py version: {dpy_version}",
|
|
||||||
"",
|
|
||||||
f"OS info: {os_info}",
|
|
||||||
f"System arch: {platform.machine()}",
|
|
||||||
f"User: {runner}",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
print(bordered(info))
|
table = Table(
|
||||||
sys.exit(0)
|
style="dim", border_style="not dim",
|
||||||
|
box=box.HEAVY_HEAD
|
||||||
|
)
|
||||||
|
table.add_column(
|
||||||
|
"Bot Info",
|
||||||
|
)
|
||||||
|
table.add_row(f"[u]Tuxbot version:[/u] {tuxbot_version}")
|
||||||
|
table.add_row(f"[u]Major:[/u] {version_info.major}")
|
||||||
|
table.add_row(f"[u]Minor:[/u] {version_info.minor}")
|
||||||
|
table.add_row(f"[u]Micro:[/u] {version_info.micro}")
|
||||||
|
table.add_row(f"[u]Level:[/u] {version_info.releaselevel}")
|
||||||
|
table.add_row(f"[u]Last change:[/u] {version_info.info}")
|
||||||
|
columns.add_renderable(table)
|
||||||
|
|
||||||
|
table = Table(
|
||||||
|
style="dim", border_style="not dim",
|
||||||
|
box=box.HEAVY_HEAD
|
||||||
|
)
|
||||||
|
table.add_column(
|
||||||
|
"Python Info",
|
||||||
|
)
|
||||||
|
table.add_row(f"[u]Python version:[/u] {python_version}")
|
||||||
|
table.add_row(f"[u]Python executable path:[/u] {sys.executable}")
|
||||||
|
table.add_row(f"[u]Pip version:[/u] {pip_version}")
|
||||||
|
table.add_row(f"[u]Discord.py version:[/u] {dpy_version}")
|
||||||
|
columns.add_renderable(table)
|
||||||
|
|
||||||
|
table = Table(
|
||||||
|
style="dim", border_style="not dim",
|
||||||
|
box=box.HEAVY_HEAD
|
||||||
|
)
|
||||||
|
table.add_column(
|
||||||
|
"Server Info",
|
||||||
|
)
|
||||||
|
table.add_row(f"[u]System:[/u] {os.uname().sysname}")
|
||||||
|
table.add_row(f"[u]System arch:[/u] {os.uname().machine}")
|
||||||
|
table.add_row(f"[u]Kernel:[/u] {os.uname().release}")
|
||||||
|
table.add_row(f"[u]User:[/u] {os.getlogin()}")
|
||||||
|
table.add_row(f"[u]Uptime:[/u] {uptime[2]}")
|
||||||
|
table.add_row(
|
||||||
|
f"[u]Load Average:[/u] {' '.join(map(str, os.getloadavg()))}"
|
||||||
|
)
|
||||||
|
columns.add_renderable(table)
|
||||||
|
|
||||||
|
console.print(columns)
|
||||||
|
console.print()
|
||||||
|
|
||||||
|
sys.exit(os.EX_OK)
|
||||||
|
|
||||||
|
|
||||||
def parse_cli_flags(args: list) -> Namespace:
|
def parse_cli_flags(args: list) -> Namespace:
|
||||||
|
@ -92,13 +152,19 @@ def parse_cli_flags(args: list) -> Namespace:
|
||||||
usage="tuxbot <instance_name> [arguments]",
|
usage="tuxbot <instance_name> [arguments]",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--version", "-V", action="store_true", help="Show tuxbot's used version"
|
"--version", "-V", action="store_true",
|
||||||
|
help="Show tuxbot's used version"
|
||||||
)
|
)
|
||||||
parser.add_argument("--debug", action="store_true", help="Show debug information.")
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--list-instances", "-L", action="store_true", help="List all instance names"
|
"--debug", action="store_true",
|
||||||
|
help="Show debug information."
|
||||||
)
|
)
|
||||||
parser.add_argument("--token", "-T", type=str, help="Run Tuxbot with passed token")
|
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(
|
parser.add_argument(
|
||||||
"instance_name",
|
"instance_name",
|
||||||
nargs="?",
|
nargs="?",
|
||||||
|
@ -126,7 +192,6 @@ async def shutdown_handler(tux: Tux, signal_type, exit_code=None) -> NoReturn:
|
||||||
"""
|
"""
|
||||||
if signal_type:
|
if signal_type:
|
||||||
log.info("%s received. Quitting...", signal_type)
|
log.info("%s received. Quitting...", signal_type)
|
||||||
sys.exit(ExitCodes.SHUTDOWN)
|
|
||||||
elif exit_code is None:
|
elif exit_code is None:
|
||||||
log.info("Shutting down from unhandled exception")
|
log.info("Shutting down from unhandled exception")
|
||||||
tux.shutdown_code = ExitCodes.CRITICAL
|
tux.shutdown_code = ExitCodes.CRITICAL
|
||||||
|
@ -134,15 +199,7 @@ async def shutdown_handler(tux: Tux, signal_type, exit_code=None) -> NoReturn:
|
||||||
if exit_code is not None:
|
if exit_code is not None:
|
||||||
tux.shutdown_code = exit_code
|
tux.shutdown_code = exit_code
|
||||||
|
|
||||||
try:
|
await tux.shutdown()
|
||||||
await tux.logout()
|
|
||||||
finally:
|
|
||||||
pending = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
|
|
||||||
|
|
||||||
for task in pending:
|
|
||||||
task.cancel()
|
|
||||||
|
|
||||||
await asyncio.gather(*pending, return_exceptions=True)
|
|
||||||
|
|
||||||
|
|
||||||
async def run_bot(tux: Tux, cli_flags: Namespace) -> None:
|
async def run_bot(tux: Tux, cli_flags: Namespace) -> None:
|
||||||
|
@ -178,10 +235,17 @@ async def run_bot(tux: Tux, cli_flags: Namespace) -> None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await tux.load_packages()
|
await tux.load_packages()
|
||||||
await tux.start(token, bot=True)
|
console.print()
|
||||||
|
await tux.start(token=token, bot=True)
|
||||||
except discord.LoginFailure:
|
except discord.LoginFailure:
|
||||||
log.critical("This token appears to be valid.")
|
log.critical("This token appears to be valid.")
|
||||||
|
console.print()
|
||||||
|
console.print(
|
||||||
|
"[prompt.invalid]This token appears to be valid. [i]exiting...[/i]"
|
||||||
|
)
|
||||||
sys.exit(ExitCodes.CRITICAL)
|
sys.exit(ExitCodes.CRITICAL)
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -198,19 +262,19 @@ def main() -> NoReturn:
|
||||||
elif cli_flags.debug:
|
elif cli_flags.debug:
|
||||||
debug_info()
|
debug_info()
|
||||||
elif cli_flags.version:
|
elif cli_flags.version:
|
||||||
print("Tuxbot V3")
|
print(f"Tuxbot V{version_info.major}")
|
||||||
print(f"Complete Version: {__version__}")
|
print(f"Complete Version: {__version__}")
|
||||||
sys.exit(0)
|
|
||||||
|
sys.exit(os.EX_OK)
|
||||||
|
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not cli_flags.instance_name:
|
if not cli_flags.instance_name:
|
||||||
print(
|
console.print(
|
||||||
Fore.RED + "No instance provided ! "
|
"[red]No instance provided ! "
|
||||||
"You can use 'tuxbot -L' to list all available instances"
|
"You can use 'tuxbot -L' to list all available instances"
|
||||||
+ Style.RESET_ALL
|
|
||||||
)
|
)
|
||||||
sys.exit(ExitCodes.CRITICAL)
|
sys.exit(ExitCodes.CRITICAL)
|
||||||
|
|
||||||
|
@ -222,13 +286,12 @@ def main() -> NoReturn:
|
||||||
|
|
||||||
loop.run_until_complete(run_bot(tux, cli_flags))
|
loop.run_until_complete(run_bot(tux, cli_flags))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print(
|
console.print(
|
||||||
Fore.RED
|
" [red]Please use <prefix>quit instead of Ctrl+C to Shutdown!"
|
||||||
+ "Please use <prefix>quit instead of Ctrl+C to Shutdown!"
|
|
||||||
+ Style.RESET_ALL
|
|
||||||
)
|
)
|
||||||
log.warning("Please use <prefix>quit instead of Ctrl+C to Shutdown!")
|
log.warning("Please use <prefix>quit instead of Ctrl+C to Shutdown!")
|
||||||
log.error("Received KeyboardInterrupt")
|
log.error("Received KeyboardInterrupt")
|
||||||
|
console.print("[i]Trying to shutdown...")
|
||||||
if tux is not None:
|
if tux is not None:
|
||||||
loop.run_until_complete(shutdown_handler(tux, signal.SIGINT))
|
loop.run_until_complete(shutdown_handler(tux, signal.SIGINT))
|
||||||
except SystemExit as exc:
|
except SystemExit as exc:
|
||||||
|
@ -236,6 +299,7 @@ def main() -> NoReturn:
|
||||||
if tux is not None:
|
if tux is not None:
|
||||||
loop.run_until_complete(shutdown_handler(tux, None, exc.code))
|
loop.run_until_complete(shutdown_handler(tux, None, exc.code))
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
console.print_exception()
|
||||||
log.exception("Unexpected exception (%s): ", type(exc), exc_info=exc)
|
log.exception("Unexpected exception (%s): ", type(exc), exc_info=exc)
|
||||||
if tux is not None:
|
if tux is not None:
|
||||||
loop.run_until_complete(shutdown_handler(tux, None, 1))
|
loop.run_until_complete(shutdown_handler(tux, None, 1))
|
||||||
|
@ -247,8 +311,12 @@ def main() -> NoReturn:
|
||||||
loop.stop()
|
loop.stop()
|
||||||
loop.close()
|
loop.close()
|
||||||
exit_code = ExitCodes.CRITICAL if tux is None else tux.shutdown_code
|
exit_code = ExitCodes.CRITICAL if tux is None else tux.shutdown_code
|
||||||
|
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
try:
|
||||||
|
main()
|
||||||
|
except Exception:
|
||||||
|
console.print_exception()
|
||||||
|
|
|
@ -3,14 +3,14 @@ from collections import namedtuple
|
||||||
from .admin import Admin
|
from .admin import Admin
|
||||||
from ...core.bot import Tux
|
from ...core.bot import Tux
|
||||||
|
|
||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro releaselevel")
|
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")
|
||||||
version_info = VersionInfo(major=2, minor=0, micro=0, releaselevel="alpha")
|
version_info = VersionInfo(major=2, minor=0, micro=0, release_level="alpha")
|
||||||
|
|
||||||
__version__ = "v{}.{}.{}-{}".format(
|
__version__ = "v{}.{}.{}-{}".format(
|
||||||
version_info.major,
|
version_info.major,
|
||||||
version_info.minor,
|
version_info.minor,
|
||||||
version_info.micro,
|
version_info.micro,
|
||||||
version_info.releaselevel,
|
version_info.release_level,
|
||||||
).replace("\n", "")
|
).replace("\n", "")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ class Admin(commands.Cog, name="Admin"):
|
||||||
@checks.is_admin()
|
@checks.is_admin()
|
||||||
async def _lang(self, ctx: ContextPlus):
|
async def _lang(self, ctx: ContextPlus):
|
||||||
"""Manage lang settings."""
|
"""Manage lang settings."""
|
||||||
|
pass
|
||||||
|
|
||||||
@_lang.command(name="set", aliases=["define", "choice"])
|
@_lang.command(name="set", aliases=["define", "choice"])
|
||||||
async def _lang_set(self, ctx: ContextPlus, lang: str):
|
async def _lang_set(self, ctx: ContextPlus, lang: str):
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Warnings(commands.Cog, name="Warnings"):
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@checks.is_mod()
|
@checks.is_mod()
|
||||||
async def _warn(self, ctx: commands.Context):
|
async def _warn(self, ctx: commands.Context):
|
||||||
pass
|
division_by_zero = 1 / 0
|
||||||
|
|
||||||
@_warn.command(name="add")
|
@_warn.command(name="add")
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from colorama import init
|
from .. import __version__, version_info, VersionInfo, ExitCodes
|
||||||
|
|
||||||
from .. import __version__, version_info, VersionInfo
|
|
||||||
from .config import Config
|
from .config import Config
|
||||||
|
|
||||||
__all__ = ["Config", "__version__", "version_info", "VersionInfo"]
|
__all__ = [
|
||||||
|
"Config",
|
||||||
init()
|
"__version__",
|
||||||
|
"version_info",
|
||||||
|
"VersionInfo",
|
||||||
|
"ExitCodes",
|
||||||
|
]
|
||||||
|
|
|
@ -5,18 +5,25 @@ import sys
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from colorama import Fore, Style, init
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
from rich import box
|
||||||
|
from rich.columns import Columns
|
||||||
|
from rich.console import Console
|
||||||
|
from rich.panel import Panel
|
||||||
|
from rich.progress import Progress, TextColumn, BarColumn
|
||||||
|
from rich.table import Table
|
||||||
|
from rich.traceback import install
|
||||||
|
from tuxbot import version_info
|
||||||
|
|
||||||
from . import Config
|
from . import Config
|
||||||
from .data_manager import logs_data_path
|
from .data_manager import logs_data_path
|
||||||
|
|
||||||
from .utils.functions.cli import bordered
|
from . import __version__, ExitCodes
|
||||||
|
|
||||||
from . import __version__
|
|
||||||
from .utils.functions.extra import ContextPlus
|
from .utils.functions.extra import ContextPlus
|
||||||
|
|
||||||
log = logging.getLogger("tuxbot")
|
log = logging.getLogger("tuxbot")
|
||||||
init()
|
console = Console()
|
||||||
|
install(console=console)
|
||||||
|
|
||||||
NAME = r"""
|
NAME = r"""
|
||||||
_____ _ _ _ _
|
_____ _ _ _ _
|
||||||
|
@ -31,6 +38,13 @@ packages: List[str] = ["jishaku", "tuxbot.cogs.warnings", "tuxbot.cogs.admin"]
|
||||||
|
|
||||||
class Tux(commands.AutoShardedBot):
|
class Tux(commands.AutoShardedBot):
|
||||||
_loading: asyncio.Task
|
_loading: asyncio.Task
|
||||||
|
_progress = {
|
||||||
|
'main': Progress(
|
||||||
|
TextColumn("[bold blue]{task.fields[task_name]}", justify="right"),
|
||||||
|
BarColumn()
|
||||||
|
),
|
||||||
|
'tasks': {}
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, *args, cli_flags=None, **kwargs):
|
def __init__(self, *args, cli_flags=None, **kwargs):
|
||||||
# by default, if the bot shutdown without any intervention,
|
# by default, if the bot shutdown without any intervention,
|
||||||
|
@ -71,52 +85,86 @@ class Tux(commands.AutoShardedBot):
|
||||||
|
|
||||||
async def load_packages(self):
|
async def load_packages(self):
|
||||||
if packages:
|
if packages:
|
||||||
print("Loading packages...")
|
with Progress() as progress:
|
||||||
for package in packages:
|
task = progress.add_task(
|
||||||
try:
|
"Loading packages...",
|
||||||
self.load_extension(package)
|
total=len(packages)
|
||||||
except Exception as e:
|
)
|
||||||
print(
|
|
||||||
Fore.RED
|
|
||||||
+ f"Failed to load package {package}"
|
|
||||||
+ Style.RESET_ALL
|
|
||||||
+ f" check "
|
|
||||||
f"{str((self.logs / 'tuxbot.log').resolve())} "
|
|
||||||
f"for more details"
|
|
||||||
)
|
|
||||||
|
|
||||||
log.exception(f"Failed to load package {package}", exc_info=e)
|
for package in packages:
|
||||||
|
try:
|
||||||
|
self.load_extension(package)
|
||||||
|
progress.console.print(f"{package} loaded")
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(
|
||||||
|
f"Failed to load package {package}",
|
||||||
|
exc_info=e
|
||||||
|
)
|
||||||
|
progress.console.print(
|
||||||
|
f"[red]Failed to load package {package} "
|
||||||
|
f"[i](see "
|
||||||
|
f"{str((self.logs / 'tuxbot.log').resolve())} "
|
||||||
|
f"for more details)[/i]"
|
||||||
|
)
|
||||||
|
|
||||||
|
progress.advance(task)
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
self.uptime = datetime.datetime.now()
|
self.uptime = datetime.datetime.now()
|
||||||
INFO = {
|
self._progress.get("main").stop_task(
|
||||||
"title": "INFO",
|
self._progress.get("tasks")["connecting"]
|
||||||
"rows": [
|
)
|
||||||
str(self.user),
|
self._progress.get("main").remove_task(
|
||||||
f"Prefixes: {', '.join(self.config('core').get('prefixes'))}",
|
self._progress.get("tasks")["connecting"]
|
||||||
f"Language: {self.config('core').get('locale')}",
|
)
|
||||||
f"Tuxbot Version: {__version__}",
|
console.clear()
|
||||||
f"Discord.py Version: {discord.__version__}",
|
|
||||||
"Python Version: " + sys.version.replace("\n", ""),
|
|
||||||
f"Shards: {self.shard_count}",
|
|
||||||
f"Servers: {len(self.guilds)}",
|
|
||||||
f"Users: {len(self.users)}",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
COGS = {"title": "COGS", "rows": []}
|
console.print(
|
||||||
|
Panel(f"[bold blue]Tuxbot V{version_info.major}", style="blue"),
|
||||||
|
justify="center"
|
||||||
|
)
|
||||||
|
console.print()
|
||||||
|
|
||||||
|
columns = Columns(expand=True, padding=2, align="center")
|
||||||
|
|
||||||
|
table = Table(
|
||||||
|
style="dim", border_style="not dim",
|
||||||
|
box=box.HEAVY_HEAD
|
||||||
|
)
|
||||||
|
table.add_column(
|
||||||
|
"INFO",
|
||||||
|
)
|
||||||
|
table.add_row(str(self.user))
|
||||||
|
table.add_row(f"Prefixes: {', '.join(self.config('core').get('prefixes'))}")
|
||||||
|
table.add_row(f"Language: {self.config('core').get('locale')}")
|
||||||
|
table.add_row(f"Tuxbot Version: {__version__}")
|
||||||
|
table.add_row(f"Discord.py Version: {discord.__version__}")
|
||||||
|
table.add_row(f"Shards: {self.shard_count}")
|
||||||
|
table.add_row(f"Servers: {len(self.guilds)}")
|
||||||
|
table.add_row(f"Users: {len(self.users)}")
|
||||||
|
columns.add_renderable(table)
|
||||||
|
|
||||||
|
table = Table(
|
||||||
|
style="dim", border_style="not dim",
|
||||||
|
box=box.HEAVY_HEAD
|
||||||
|
)
|
||||||
|
table.add_column(
|
||||||
|
"COGS",
|
||||||
|
)
|
||||||
for extension in packages:
|
for extension in packages:
|
||||||
COGS["rows"].append(
|
if extension in self.extensions:
|
||||||
f"[{'X' if extension in self.extensions else ' '}] {extension}"
|
status = f"[green]:heavy_check_mark: {extension} "
|
||||||
)
|
else:
|
||||||
|
status = f"[red]:cross_mark: {extension} "
|
||||||
|
|
||||||
print(Fore.LIGHTBLUE_EX + NAME)
|
table.add_row(status)
|
||||||
print(Style.RESET_ALL)
|
columns.add_renderable(table)
|
||||||
print(bordered(INFO, COGS))
|
|
||||||
|
|
||||||
print(f"\n{'=' * 118}\n\n")
|
console.print(columns)
|
||||||
|
console.print()
|
||||||
|
|
||||||
async def is_owner(self, user: Union[discord.User, discord.Member]) -> bool:
|
async def is_owner(self,
|
||||||
|
user: Union[discord.User, discord.Member]) -> bool:
|
||||||
"""Determines if the user is a bot owner.
|
"""Determines if the user is a bot owner.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -152,9 +200,9 @@ class Tux(commands.AutoShardedBot):
|
||||||
return
|
return
|
||||||
|
|
||||||
if (
|
if (
|
||||||
message.guild.id in self.config.get_blacklist("guild")
|
message.guild.id in self.config.get_blacklist("guild")
|
||||||
or message.channel.id in self.config.get_blacklist("channel")
|
or message.channel.id in self.config.get_blacklist("channel")
|
||||||
or message.author.id in self.config.get_blacklist("user")
|
or message.author.id in self.config.get_blacklist("user")
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -168,11 +216,45 @@ class Tux(commands.AutoShardedBot):
|
||||||
async def on_message(self, message: discord.Message):
|
async def on_message(self, message: discord.Message):
|
||||||
await self.process_commands(message)
|
await self.process_commands(message)
|
||||||
|
|
||||||
|
async def start(self, token, bot):
|
||||||
|
"""Connect to Discord and start all connections.
|
||||||
|
|
||||||
|
Todo: add postgresql connect here
|
||||||
|
"""
|
||||||
|
with self._progress.get("main") as pg:
|
||||||
|
task_id = self._progress.get("tasks")["connecting"] = pg.add_task(
|
||||||
|
"connecting",
|
||||||
|
task_name="Connecting to Discord...", start=False
|
||||||
|
)
|
||||||
|
pg.update(task_id)
|
||||||
|
await super().start(token, bot=bot)
|
||||||
|
|
||||||
async def logout(self):
|
async def logout(self):
|
||||||
"""Disconnect from Discord and closes all actives connections.
|
"""Disconnect from Discord and closes all actives connections.
|
||||||
|
|
||||||
Todo: add postgresql logout here
|
Todo: add postgresql logout here
|
||||||
"""
|
"""
|
||||||
|
for task in self._progress.get("tasks").keys():
|
||||||
|
self._progress.get("main").log("Shutting down", task)
|
||||||
|
|
||||||
|
self._progress.get("main").stop_task(
|
||||||
|
self._progress.get("tasks")[task]
|
||||||
|
)
|
||||||
|
self._progress.get("main").remove_task(
|
||||||
|
self._progress.get("tasks")["connecting"]
|
||||||
|
)
|
||||||
|
self._progress.get("main").stop()
|
||||||
|
|
||||||
|
pending = [
|
||||||
|
t for t in asyncio.all_tasks() if
|
||||||
|
t is not asyncio.current_task()
|
||||||
|
]
|
||||||
|
|
||||||
|
for task in pending:
|
||||||
|
console.log("Canceling", task.get_name(), f"({task.get_coro()})")
|
||||||
|
task.cancel()
|
||||||
|
await asyncio.gather(*pending, return_exceptions=True)
|
||||||
|
|
||||||
await super().logout()
|
await super().logout()
|
||||||
|
|
||||||
async def shutdown(self, *, restart: bool = False):
|
async def shutdown(self, *, restart: bool = False):
|
||||||
|
@ -192,9 +274,3 @@ class Tux(commands.AutoShardedBot):
|
||||||
|
|
||||||
await self.logout()
|
await self.logout()
|
||||||
sys.exit(self.shutdown_code)
|
sys.exit(self.shutdown_code)
|
||||||
|
|
||||||
|
|
||||||
class ExitCodes:
|
|
||||||
CRITICAL = 1
|
|
||||||
SHUTDOWN = 0
|
|
||||||
RESTART = 42
|
|
||||||
|
|
|
@ -33,10 +33,12 @@ def init_logging(level: int, location: pathlib.Path) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
dpy_handler = logging.handlers.RotatingFileHandler(
|
dpy_handler = logging.handlers.RotatingFileHandler(
|
||||||
str(dpy_logger_file.resolve()), maxBytes=MAX_BYTES, backupCount=MAX_OLD_LOGS
|
str(dpy_logger_file.resolve()),
|
||||||
|
maxBytes=MAX_BYTES, backupCount=MAX_OLD_LOGS
|
||||||
)
|
)
|
||||||
base_handler = logging.handlers.RotatingFileHandler(
|
base_handler = logging.handlers.RotatingFileHandler(
|
||||||
str(base_logger_file.resolve()), maxBytes=MAX_BYTES, backupCount=MAX_OLD_LOGS
|
str(base_logger_file.resolve()),
|
||||||
|
maxBytes=MAX_BYTES, backupCount=MAX_OLD_LOGS
|
||||||
)
|
)
|
||||||
|
|
||||||
stdout_handler = logging.StreamHandler(sys.stdout)
|
stdout_handler = logging.StreamHandler(sys.stdout)
|
||||||
|
|
174
tuxbot/setup.py
174
tuxbot/setup.py
|
@ -3,14 +3,19 @@ import logging
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import NoReturn, Union, List, Set
|
from typing import NoReturn, Union, List
|
||||||
|
|
||||||
import click
|
from rich.prompt import Prompt, IntPrompt
|
||||||
from colorama import Fore, Style, init
|
from rich.console import Console
|
||||||
|
from rich.rule import Rule
|
||||||
|
from rich.traceback import install
|
||||||
|
from rich import print
|
||||||
|
|
||||||
from tuxbot.core.data_manager import config_dir, app_dir
|
from tuxbot.core.data_manager import config_dir, app_dir
|
||||||
|
|
||||||
init()
|
console = Console()
|
||||||
|
console.clear()
|
||||||
|
install(console=console)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config_dir.mkdir(parents=True, exist_ok=True)
|
config_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
@ -77,14 +82,15 @@ def get_name() -> str:
|
||||||
"""
|
"""
|
||||||
name = ""
|
name = ""
|
||||||
while not name:
|
while not name:
|
||||||
print(
|
name = Prompt.ask(
|
||||||
"What name do you want to give this instance?\n"
|
"What name do you want to give this instance?\n"
|
||||||
"(valid characters: A-Z, a-z, 0-9, _, -)"
|
"[i](valid characters: A-Z, a-z, 0-9, _, -)[/i]\n",
|
||||||
|
default="prod",
|
||||||
|
console=console
|
||||||
)
|
)
|
||||||
name = input("> ")
|
|
||||||
if re.fullmatch(r"[a-zA-Z0-9_\-]*", name) is None:
|
if re.fullmatch(r"[a-zA-Z0-9_\-]*", name) is None:
|
||||||
print()
|
print()
|
||||||
print(Fore.RED + "ERROR: Invalid characters provided" + Style.RESET_ALL)
|
print("[prompt.invalid]ERROR: Invalid characters provided")
|
||||||
name = ""
|
name = ""
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
@ -113,42 +119,35 @@ def get_data_dir(instance_name: str) -> Path:
|
||||||
except OSError:
|
except OSError:
|
||||||
print()
|
print()
|
||||||
print(
|
print(
|
||||||
Fore.RED + f"mkdir: cannot create directory '{path}':"
|
f"mkdir: cannot create directory '{path}': Permission denied"
|
||||||
f" Permission denied" + Style.RESET_ALL
|
|
||||||
)
|
)
|
||||||
path = ""
|
path = ""
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
while not data_path_input:
|
while not data_path_input:
|
||||||
print(
|
data_path_input = Path(
|
||||||
"where do you want to save the configurations?\n"
|
Prompt.ask(
|
||||||
"Press [enter] to keep the default path"
|
"where do you want to save the configurations?",
|
||||||
|
default=str(data_path),
|
||||||
|
console=console
|
||||||
|
)
|
||||||
)
|
)
|
||||||
print()
|
|
||||||
print(f"Default: {data_path}")
|
|
||||||
|
|
||||||
data_path_input = input("> ")
|
try:
|
||||||
|
exists = data_path_input.exists()
|
||||||
|
except OSError:
|
||||||
|
print()
|
||||||
|
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 != "":
|
if data_path_input and not exists:
|
||||||
data_path_input = Path(data_path_input)
|
data_path_input = make_data_dir(data_path_input)
|
||||||
|
|
||||||
try:
|
|
||||||
exists = data_path_input.exists()
|
|
||||||
except OSError:
|
|
||||||
print()
|
|
||||||
print(
|
|
||||||
Fore.RED + "Impossible to verify the validity of the path, "
|
|
||||||
"make sure it does not contain any invalid characters."
|
|
||||||
+ Style.RESET_ALL
|
|
||||||
)
|
|
||||||
data_path_input = ""
|
|
||||||
exists = False
|
|
||||||
|
|
||||||
if data_path_input and not exists:
|
|
||||||
data_path_input = make_data_dir(data_path_input)
|
|
||||||
else:
|
|
||||||
data_path_input = make_data_dir(data_path)
|
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print(
|
print(
|
||||||
|
@ -156,7 +155,11 @@ def get_data_dir(instance_name: str) -> Path:
|
||||||
f"`{instance_name}` instance"
|
f"`{instance_name}` instance"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not click.confirm("Please confirm", default=True):
|
if Prompt.ask(
|
||||||
|
"Please confirm",
|
||||||
|
choices=["y", "n"], default="y",
|
||||||
|
console=console
|
||||||
|
) != "y":
|
||||||
print("Rerun the process to redo this configuration.")
|
print("Rerun the process to redo this configuration.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@ -178,25 +181,23 @@ def get_token() -> str:
|
||||||
token = ""
|
token = ""
|
||||||
|
|
||||||
while not token:
|
while not token:
|
||||||
print(
|
token = Prompt.ask(
|
||||||
"Please enter the bot token\n"
|
"Please enter the bot token "
|
||||||
"(you can find it at https://discord.com/developers/applications)"
|
"(you can find it at https://discord.com/developers/applications)",
|
||||||
|
console=console
|
||||||
)
|
)
|
||||||
token = input("> ")
|
if re.fullmatch(
|
||||||
if (
|
r"([a-zA-Z0-9]{24}\.[a-zA-Z0-9_]{6}\.[a-zA-Z0-9_\-]{27}"
|
||||||
re.fullmatch(
|
r"|mfa\.[a-zA-Z0-9_\-]{84})",
|
||||||
r"([a-zA-Z0-9]{24}\.[a-zA-Z0-9_]{6}\.[a-zA-Z0-9_\-]{27}|mfa\.[a-zA-Z0-9_\-]{84})",
|
token) \
|
||||||
token,
|
is None:
|
||||||
)
|
print("[prompt.invalid]ERROR: Invalid token provided")
|
||||||
is None
|
|
||||||
):
|
|
||||||
print(Fore.RED + "ERROR: Invalid token provided" + Style.RESET_ALL)
|
|
||||||
token = ""
|
token = ""
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
def get_multiple(
|
def get_multiple(
|
||||||
question: str, confirmation: str, value_type: type
|
question: str, confirmation: str, value_type: type
|
||||||
) -> List[Union[str, int]]:
|
) -> List[Union[str, int]]:
|
||||||
"""Give possibility to user to fill multiple value.
|
"""Give possibility to user to fill multiple value.
|
||||||
|
|
||||||
|
@ -214,15 +215,29 @@ def get_multiple(
|
||||||
List[Union[str, int]]
|
List[Union[str, int]]
|
||||||
List containing user filled values.
|
List containing user filled values.
|
||||||
"""
|
"""
|
||||||
print(question)
|
prompt = IntPrompt if value_type is int else Prompt
|
||||||
user_input = input("> ")
|
|
||||||
|
user_input = prompt.ask(question, console=console)
|
||||||
|
|
||||||
if not user_input:
|
if not user_input:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
values = [user_input]
|
values = [user_input]
|
||||||
|
|
||||||
while click.confirm(confirmation, default=False):
|
while Prompt.ask(
|
||||||
values.append(value_type(input("> ")))
|
confirmation,
|
||||||
|
choices=["y", "n"], default="y",
|
||||||
|
console=console
|
||||||
|
) != "n":
|
||||||
|
new = prompt.ask("Other")
|
||||||
|
|
||||||
|
if new not in values:
|
||||||
|
values.append(new)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"[prompt.invalid]"
|
||||||
|
f"ERROR: `{new}` is already present, [i]ignored[/i]"
|
||||||
|
)
|
||||||
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
@ -236,24 +251,23 @@ def additional_config() -> dict:
|
||||||
Dict with cog name as key and configs as value.
|
Dict with cog name as key and configs as value.
|
||||||
"""
|
"""
|
||||||
p = Path(r"tuxbot/cogs").glob("**/additional_config.json")
|
p = Path(r"tuxbot/cogs").glob("**/additional_config.json")
|
||||||
datas = {}
|
data = {}
|
||||||
|
|
||||||
for file in p:
|
for file in p:
|
||||||
print()
|
print("\n" * 4)
|
||||||
cog_name = str(file.parent).split("/")[-1]
|
cog_name = str(file.parent).split("/")[-1]
|
||||||
datas[cog_name] = {}
|
data[cog_name] = {}
|
||||||
|
|
||||||
with file.open("r") as f:
|
with file.open("r") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
|
||||||
print(f"\n==Configuration for `{cog_name}` module==")
|
print(Rule(f"\nConfiguration for `{cog_name}` module"))
|
||||||
|
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
print()
|
print()
|
||||||
print(value["description"])
|
data[cog_name][key] = Prompt.ask(value["description"])
|
||||||
datas[cog_name][key] = input("> ")
|
|
||||||
|
|
||||||
return datas
|
return data
|
||||||
|
|
||||||
|
|
||||||
def finish_setup(data_dir: Path) -> NoReturn:
|
def finish_setup(data_dir: Path) -> NoReturn:
|
||||||
|
@ -264,15 +278,29 @@ def finish_setup(data_dir: Path) -> NoReturn:
|
||||||
data_dir:Path
|
data_dir:Path
|
||||||
Where to save configs.
|
Where to save configs.
|
||||||
"""
|
"""
|
||||||
print("Now, it's time to finish this setup by giving bot informations\n")
|
print(
|
||||||
|
Rule(
|
||||||
|
"Now, it's time to finish this setup by giving bot information"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print()
|
||||||
|
|
||||||
token = get_token()
|
token = get_token()
|
||||||
|
|
||||||
print()
|
print()
|
||||||
prefixes = get_multiple(
|
prefixes = get_multiple(
|
||||||
"Choice a (or multiple) prefix for the bot", "Add another prefix ?", str
|
"Choice a (or multiple) prefix for the bot", "Add another prefix ?",
|
||||||
|
str
|
||||||
)
|
)
|
||||||
mentionable = click.confirm("Does the bot answer if it's mentioned?", default=True)
|
|
||||||
|
|
||||||
|
print()
|
||||||
|
mentionable = Prompt.ask(
|
||||||
|
"Does the bot answer if it's mentioned?",
|
||||||
|
choices=["y", "n"],
|
||||||
|
default="y"
|
||||||
|
) == "y"
|
||||||
|
|
||||||
|
print()
|
||||||
owners_id = get_multiple(
|
owners_id = get_multiple(
|
||||||
"Give the owner id of this bot", "Add another owner ?", int
|
"Give the owner id of this bot", "Add another owner ?", int
|
||||||
)
|
)
|
||||||
|
@ -305,7 +333,12 @@ def basic_setup() -> NoReturn:
|
||||||
"""Configs who refer to instances.
|
"""Configs who refer to instances.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
print("Hi ! it's time for you to give me informations about you instance")
|
print(
|
||||||
|
Rule(
|
||||||
|
"Hi ! it's time for you to give me information about you instance"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print()
|
||||||
name = get_name()
|
name = get_name()
|
||||||
|
|
||||||
data_dir = get_data_dir(name)
|
data_dir = get_data_dir(name)
|
||||||
|
@ -318,11 +351,14 @@ def basic_setup() -> NoReturn:
|
||||||
|
|
||||||
if name in instances_list:
|
if name in instances_list:
|
||||||
print()
|
print()
|
||||||
print(
|
console.print(
|
||||||
Fore.RED + f"WARNING: An instance named `{name}` already exists "
|
f"WARNING: An instance named `{name}` already exists "
|
||||||
f"Continuing will overwrite this instance configs." + Style.RESET_ALL
|
f"Continuing will overwrite this instance configs.", style="red"
|
||||||
)
|
)
|
||||||
if not click.confirm("Are you sure you want to continue?", default=False):
|
if Prompt.ask(
|
||||||
|
"Are you sure you want to continue?",
|
||||||
|
choices=["y", "n"], default="n"
|
||||||
|
) == "n":
|
||||||
print("Abandon...")
|
print("Abandon...")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@ -357,6 +393,8 @@ def setup() -> NoReturn:
|
||||||
basic_setup()
|
basic_setup()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("Exiting...")
|
print("Exiting...")
|
||||||
|
except:
|
||||||
|
console.print_exception()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Reference in a new issue