update polish again

This commit is contained in:
esef committed 2026-07-05 20:53:22 +03:00
1 parent 10f372173f
commit f88fd7989a
1 file changed
+40 -81
+40 -81
View File
@@ -1,6 +1,5 @@
import asyncio import asyncio
import os import os
from datetime import datetime, timezone
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -14,11 +13,9 @@ SERVICE_NAME = "yuuka"
GIT_TIMEOUT = 30 GIT_TIMEOUT = 30
SYSTEMD_TIMEOUT = 15 SYSTEMD_TIMEOUT = 15
# ── colors ───────────────────────────────────────────────────────────────────
C_OK = 0x50FA7B C_OK = 0x50FA7B
C_ERR = 0xFF5555 C_ERR = 0xFF5555
C_WARN = 0xFFB86C C_WARN = 0xFFB86C
C_INFO = 0x8BE9FD
# ── subprocess helpers ──────────────────────────────────────────────────────── # ── subprocess helpers ────────────────────────────────────────────────────────
@@ -52,10 +49,7 @@ async def run_git_pull() -> tuple[int, str]:
async def run_git_log(n: int = 5) -> tuple[int, str]: async def run_git_log(n: int = 5) -> tuple[int, str]:
return await _run( return await _run("git", "log", "--oneline", f"-{n}", cwd=BOT_DIR, timeout=GIT_TIMEOUT)
"git", "log", f"--oneline", f"-{n}",
cwd=BOT_DIR, timeout=GIT_TIMEOUT,
)
async def run_sudo_systemctl(action: str) -> tuple[int, str]: async def run_sudo_systemctl(action: str) -> tuple[int, str]:
@@ -68,8 +62,7 @@ async def run_sudo_systemctl(action: str) -> tuple[int, str]:
async def run_journalctl(n: int = 50) -> tuple[int, str]: async def run_journalctl(n: int = 50) -> tuple[int, str]:
return await _run( return await _run(
"sudo", "-S", "journalctl", "-u", SERVICE_NAME, "sudo", "-S", "journalctl", "-u", SERVICE_NAME, "-n", str(n), "--no-pager",
"-n", str(n), "--no-pager",
input_data=f"{SUDO_PASSWORD}\n".encode() if SUDO_PASSWORD else None, input_data=f"{SUDO_PASSWORD}\n".encode() if SUDO_PASSWORD else None,
timeout=SYSTEMD_TIMEOUT, timeout=SYSTEMD_TIMEOUT,
) )
@@ -77,19 +70,10 @@ async def run_journalctl(n: int = 50) -> tuple[int, str]:
def truncate(text: str, limit: int = 1900) -> str: def truncate(text: str, limit: int = 1900) -> str:
if len(text) > limit: if len(text) > limit:
return text[:limit] + "\n… (truncated)" return text[:limit] + "\n... (truncated)"
return text return text
def _embed(title: str, description: str, color: int) -> discord.Embed:
return discord.Embed(
title=title,
description=description,
color=color,
timestamp=datetime.now(timezone.utc),
)
# ── cog ────────────────────────────────────────────────────────────────────── # ── cog ──────────────────────────────────────────────────────────────────────
class GitPull(commands.Cog): class GitPull(commands.Cog):
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
@@ -99,11 +83,7 @@ class GitPull(commands.Cog):
return ctx.author.id == OWNER_ID return ctx.author.id == OWNER_ID
async def _do_restart(self, ctx: commands.Context): async def _do_restart(self, ctx: commands.Context):
await ctx.reply(embed=_embed( await ctx.reply(embed=discord.Embed(description="Restarting service...", color=C_WARN))
"⟳ Restarting",
f"Restarting `{SERVICE_NAME}` — see you on the other side.",
C_WARN,
))
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
proc = await asyncio.create_subprocess_exec( proc = await asyncio.create_subprocess_exec(
"sudo", "-S", "systemctl", "restart", SERVICE_NAME, "sudo", "-S", "systemctl", "restart", SERVICE_NAME,
@@ -119,11 +99,8 @@ class GitPull(commands.Cog):
except Exception: except Exception:
pass pass
# ── !gitpull ──────────────────────────────────────────────────────────────
@commands.command(name="gitpull") @commands.command(name="gitpull")
async def gitpull(self, ctx: commands.Context): async def gitpull(self, ctx: commands.Context):
"""Pull latest changes from git without restarting."""
if not self._is_owner(ctx): if not self._is_owner(ctx):
return return
@@ -131,30 +108,27 @@ class GitPull(commands.Cog):
code, output = await run_git_pull() code, output = await run_git_pull()
if code != 0: if code != 0:
return await ctx.reply(embed=_embed( return await ctx.reply(embed=discord.Embed(
"✗ Pull Failed", title="Git Pull",
f"```\n{truncate(output)}\n```", description=f"```\n{truncate(output)}\n```",
C_ERR, color=C_ERR,
)) ))
if "Already up to date" in output: if "Already up to date" in output:
return await ctx.reply(embed=_embed( return await ctx.reply(embed=discord.Embed(
"✓ Already Up to Date", title="Git Pull",
"Nothing new to pull.", description="Already up to date.",
C_WARN, color=C_WARN,
)) ))
await ctx.reply(embed=_embed( await ctx.reply(embed=discord.Embed(
"✓ Pulled", title="Git Pull",
f"```\n{truncate(output)}\n```", description=f"```\n{truncate(output)}\n```",
C_OK, color=C_OK,
)) ))
# ── !gitlog ───────────────────────────────────────────────────────────────
@commands.command(name="gitlog") @commands.command(name="gitlog")
async def gitlog(self, ctx: commands.Context, n: int = 5): async def gitlog(self, ctx: commands.Context, n: int = 5):
"""Show the last N commits. Default: 5."""
if not self._is_owner(ctx): if not self._is_owner(ctx):
return return
n = max(1, min(n, 20)) n = max(1, min(n, 20))
@@ -162,18 +136,14 @@ class GitPull(commands.Cog):
async with ctx.typing(): async with ctx.typing():
code, output = await run_git_log(n) code, output = await run_git_log(n)
color = C_OK if code == 0 else C_ERR await ctx.reply(embed=discord.Embed(
await ctx.reply(embed=_embed( title=f"Last {n} commits",
f"📋 Last {n} Commits", description=f"```\n{truncate(output)}\n```",
f"```\n{truncate(output)}\n```", color=C_OK if code == 0 else C_ERR,
color,
)) ))
# ── !logs ─────────────────────────────────────────────────────────────────
@commands.command(name="logs") @commands.command(name="logs")
async def logs(self, ctx: commands.Context, n: int = 40): async def logs(self, ctx: commands.Context, n: int = 40):
"""Show the last N lines of the service journal. Default: 40."""
if not self._is_owner(ctx): if not self._is_owner(ctx):
return return
n = max(1, min(n, 100)) n = max(1, min(n, 100))
@@ -181,45 +151,34 @@ class GitPull(commands.Cog):
async with ctx.typing(): async with ctx.typing():
code, output = await run_journalctl(n) code, output = await run_journalctl(n)
color = C_OK if code == 0 else C_ERR await ctx.reply(embed=discord.Embed(
await ctx.reply(embed=_embed( title=f"Logs ({n} lines)",
f"📄 Logs — {SERVICE_NAME} (last {n} lines)", description=f"```\n{truncate(output)}\n```",
f"```\n{truncate(output)}\n```", color=C_OK if code == 0 else C_ERR,
color,
)) ))
# ── !status ───────────────────────────────────────────────────────────────
@commands.command(name="status") @commands.command(name="status")
async def status(self, ctx: commands.Context): async def status(self, ctx: commands.Context):
"""Show systemd service status."""
if not self._is_owner(ctx): if not self._is_owner(ctx):
return return
async with ctx.typing(): async with ctx.typing():
code, output = await run_sudo_systemctl("status") code, output = await run_sudo_systemctl("status")
color = C_OK if code == 0 else C_ERR await ctx.reply(embed=discord.Embed(
await ctx.reply(embed=_embed( title=f"Service Status: {SERVICE_NAME}",
f"{'✓' if code == 0 else '✗'} Status — {SERVICE_NAME}", description=f"```\n{truncate(output)}\n```",
f"```\n{truncate(output)}\n```", color=C_OK if code == 0 else C_ERR,
color,
)) ))
# ── !restart ──────────────────────────────────────────────────────────────
@commands.command(name="restart") @commands.command(name="restart")
async def restart(self, ctx: commands.Context): async def restart(self, ctx: commands.Context):
"""Restart the bot service."""
if not self._is_owner(ctx): if not self._is_owner(ctx):
return return
await self._do_restart(ctx) await self._do_restart(ctx)
# ── !update ───────────────────────────────────────────────────────────────
@commands.command(name="update") @commands.command(name="update")
async def update(self, ctx: commands.Context): async def update(self, ctx: commands.Context):
"""Pull latest changes and restart if anything changed."""
if not self._is_owner(ctx): if not self._is_owner(ctx):
return return
@@ -227,23 +186,23 @@ class GitPull(commands.Cog):
code, output = await run_git_pull() code, output = await run_git_pull()
if code != 0: if code != 0:
return await ctx.reply(embed=_embed( return await ctx.reply(embed=discord.Embed(
"✗ Update Failed", title="Update Failed",
f"Pull failed — restart skipped.\n```\n{truncate(output)}\n```", description=f"git pull failed, restart skipped.\n```\n{truncate(output)}\n```",
C_ERR, color=C_ERR,
)) ))
if "Already up to date" in output: if "Already up to date" in output:
return await ctx.reply(embed=_embed( return await ctx.reply(embed=discord.Embed(
"✓ Already Up to Date", title="Update",
"Nothing new to pull. Restart skipped.", description="No changes to pull. Restart skipped.",
C_WARN, color=C_WARN,
)) ))
await ctx.reply(embed=_embed( await ctx.reply(embed=discord.Embed(
"✓ Updated", title="Update",
f"```\n{truncate(output)}\n```", description=f"Pulled changes:\n```\n{truncate(output)}\n```",
C_OK, color=C_OK,
)) ))
await self._do_restart(ctx) await self._do_restart(ctx)