cli-interface

This commit is contained in:
Vladless
2025-04-06 21:15:59 +03:00
parent 10afee1194
commit 305c3576e3
16 changed files with 201 additions and 112646 deletions
+198
View File
@@ -0,0 +1,198 @@
import os
import sys
import subprocess
import requests
from rich.console import Console
from rich.prompt import Prompt, Confirm
from rich.table import Table
from rich.text import Text
from config import SERVICE_NAME
try:
sys.stdin.reconfigure(encoding='utf-8')
sys.stdout.reconfigure(encoding='utf-8')
except Exception:
pass
if not os.environ.get("LC_ALL", "").endswith("UTF-8"):
os.environ["LC_ALL"] = "en_US.UTF-8"
os.environ["LANG"] = "en_US.UTF-8"
BACK_DIR = os.path.expanduser("~/.solobot_backup")
TEMP_DIR = os.path.expanduser("~/.solobot_tmp")
PROJECT_DIR = os.path.abspath(os.path.dirname(__file__))
GITHUB_REPO = "https://github.com/Vladless/Solo_bot"
console = Console()
def print_logo():
logo = Text("""
███████╗ ██████╗ ██╗ ██████╗ ██████╗ ██████╗ ████████╗
██╔════╝██╔═══██╗██║ ██╔═══██╗██╔══██╗██╔═══██╗╚══██╔══╝
███████╗██║ ██║██║ ██║ ██║██████╔╝██║ ██║ ██║
╚════██║██║ ██║██║ ██║ ██║██╔══██╗██║ ██║ ██║
███████║╚██████╔╝███████╗╚██████╔╝██████╔╝╚██████╔╝ ██║
╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝
""", style="bold cyan")
console.print(logo)
def backup_project():
console.print("[yellow]Создаётся резервная копия проекта...[/yellow]")
subprocess.run(["rm", "-rf", BACK_DIR])
subprocess.run(["cp", "-r", PROJECT_DIR, BACK_DIR])
console.print(f"[green]✅ Бэкап сохранён в: {BACK_DIR}[/green]")
def install_git_if_needed():
if subprocess.run(["which", "git"], capture_output=True).returncode != 0:
console.print("[blue]Установка Git...[/blue]")
os.system("sudo apt update && sudo apt install -y git")
def install_dependencies():
console.print("[blue]🔧 Установка зависимостей...[/blue]")
os.system("source venv/bin/activate && pip install -r requirements.txt")
def restart_service():
console.print("[blue]🚀 Перезапуск службы...[/blue]")
os.system(f"sudo systemctl restart {SERVICE_NAME}")
def update_from_beta():
if not Confirm.ask("[yellow]🔁 Подтвердите обновление Solobot с ветки BETA[/yellow]"):
return
backup_project()
install_git_if_needed()
os.chdir(PROJECT_DIR)
git_dir = os.path.join(PROJECT_DIR, ".git")
if os.path.isdir(git_dir):
console.print("[cyan]🔄 Найден .git. Выполняется git pull...[/cyan]")
os.system("git reset --hard")
os.system("git pull")
else:
console.print("[cyan]📥 .git не найден. Клонируем репозиторий заново...[/cyan]")
subprocess.run(["rm", "-rf", TEMP_DIR])
if os.system(f"git clone {GITHUB_REPO} {TEMP_DIR}") != 0:
console.print("[red]❌ Ошибка при клонировании. Обновление отменено.[/red]")
return
subprocess.run(["cp", "-r", f"{TEMP_DIR}/.", PROJECT_DIR])
subprocess.run(["rm", "-rf", TEMP_DIR])
install_dependencies()
restart_service()
console.print("[green]✅ Обновление с ветки BETA завершено.[/green]")
def update_from_release():
if not Confirm.ask("[yellow]🔁 Подтвердите обновление Solobot до последнего релиза[/yellow]"):
return
backup_project()
install_git_if_needed()
try:
response = requests.get(
"https://api.github.com/repos/Vladless/Solo_bot/releases/latest", timeout=10
)
tag_name = response.json().get("tag_name")
if not tag_name:
raise ValueError("Не удалось получить тег релиза")
console.print(f"[cyan]📥 Клонируем релиз {tag_name} во временную папку...[/cyan]")
subprocess.run(["rm", "-rf", TEMP_DIR])
if os.system(f"git clone --depth 1 --branch {tag_name} {GITHUB_REPO} {TEMP_DIR}") != 0:
console.print("[red]❌ Ошибка при клонировании релиза. Обновление отменено.[/red]")
return
subprocess.run(["cp", "-r", f"{TEMP_DIR}/.", PROJECT_DIR])
subprocess.run(["rm", "-rf", TEMP_DIR])
install_dependencies()
restart_service()
console.print(f"[green]✅ Обновление до релиза {tag_name} завершено.[/green]")
except Exception as e:
console.print(f"[red]❌ Ошибка при обновлении: {e}[/red]")
def show_update_menu():
table = Table(title="Выберите способ обновления", title_style="bold green")
table.add_column("", justify="center", style="cyan", no_wrap=True)
table.add_column("Источник", style="white")
table.add_row("1", "Обновить с BETA (git pull или clone)")
table.add_row("2", "Обновить с последнего релиза (GitHub Release)")
table.add_row("3", "Назад в меню")
console.print(table)
choice = Prompt.ask("[bold blue]Введите номер[/bold blue]", choices=["1", "2", "3"])
if choice == "1":
update_from_beta()
elif choice == "2":
update_from_release()
def show_menu():
table = Table(title="Solobot CLI", title_style="bold magenta", header_style="bold blue")
table.add_column("", justify="center", style="cyan", no_wrap=True)
table.add_column("Операция", style="white")
table.add_row("1", "Запустить бота (systemd)")
table.add_row("2", "Запустить напрямую: venv/bin/python main.py")
table.add_row("3", "Перезапустить бота (systemd)")
table.add_row("4", "Остановить бота (systemd)")
table.add_row("5", "Показать логи (50 строк)")
table.add_row("6", "Показать статус")
table.add_row("7", "Обновить Solobot")
table.add_row("8", "Выход")
console.print(table)
def main():
if os.geteuid() != 0:
console.print("[bold red]⛔ Требуется запуск от имени root или через sudo.[/bold red]")
sys.exit(1)
os.chdir(PROJECT_DIR)
print_logo()
while True:
show_menu()
choice = Prompt.ask("[bold blue]Введите номер действия[/bold blue]", choices=[str(i) for i in range(1, 9)])
if choice == "1":
os.system(f"sudo systemctl start {SERVICE_NAME}")
elif choice == "2":
if Confirm.ask("[green]Вы действительно хотите запустить main.py вручную?[/green]"):
os.system("sudo venv/bin/python main.py")
elif choice == "3":
if Confirm.ask("[yellow]Вы действительно хотите перезапустить бота?[/yellow]"):
os.system(f"sudo systemctl restart {SERVICE_NAME}")
elif choice == "4":
if Confirm.ask("[red]Вы уверены, что хотите остановить бота?[/red]"):
os.system(f"sudo systemctl stop {SERVICE_NAME}")
elif choice == "5":
os.system(f"sudo journalctl -u {SERVICE_NAME} -n 50 --no-pager")
elif choice == "6":
os.system(f"sudo systemctl status {SERVICE_NAME}")
elif choice == "7":
show_update_menu()
elif choice == "8":
console.print("[bold cyan]👋 Выход из CLI. Удачного дня![/bold cyan]")
break
if __name__ == "__main__":
main()