102 lines
3.7 KiB
Python
102 lines
3.7 KiB
Python
import os
|
|
from services.runner import run_cmd
|
|
|
|
|
|
def detect_pkg_manager() -> str | None:
|
|
if os.path.exists("/usr/bin/apt"):
|
|
return "apt"
|
|
if os.path.exists("/usr/bin/dnf"):
|
|
return "dnf"
|
|
if os.path.exists("/usr/bin/yum"):
|
|
return "yum"
|
|
if os.path.exists("/usr/bin/pacman"):
|
|
return "pacman"
|
|
return None
|
|
|
|
|
|
async def list_updates() -> tuple[str, list[str]]:
|
|
pm = detect_pkg_manager()
|
|
if not pm:
|
|
return "⚠️ Updates", ["No supported package manager found"]
|
|
|
|
if pm == "apt":
|
|
await run_cmd(["sudo", "apt", "update"], timeout=300)
|
|
rc, out = await run_cmd(["apt", "list", "--upgradable"], timeout=120)
|
|
if rc != 0:
|
|
return "❌ Updates (apt)", [f"apt list failed: {out}"]
|
|
|
|
lines = []
|
|
for line in out.splitlines():
|
|
if not line or line.startswith("Listing..."):
|
|
continue
|
|
# Format: name/repo new_ver arch [upgradable from: old]
|
|
parts = line.split()
|
|
if len(parts) < 2:
|
|
continue
|
|
name_repo = parts[0]
|
|
new_ver = parts[1]
|
|
if "/" not in name_repo:
|
|
name = name_repo
|
|
else:
|
|
name = name_repo.split("/", 1)[0]
|
|
old_ver = None
|
|
marker = "upgradable from: "
|
|
if marker in line:
|
|
old_ver = line.split(marker, 1)[1].rstrip("]").strip()
|
|
if old_ver:
|
|
lines.append(f"{name}: {old_ver} -> {new_ver}")
|
|
else:
|
|
lines.append(f"{name}: -> {new_ver}")
|
|
|
|
if not lines:
|
|
lines = ["No updates"]
|
|
return "📦 Updates (apt)", lines
|
|
|
|
if pm == "dnf":
|
|
rc, out = await run_cmd(["sudo", "dnf", "check-update"], timeout=300)
|
|
if rc in (0, 100):
|
|
lines = out.splitlines() or ["No updates"]
|
|
return "📦 Updates (dnf)", lines
|
|
return "❌ Updates (dnf)", [f"dnf check-update failed: {out}"]
|
|
|
|
if pm == "yum":
|
|
rc, out = await run_cmd(["sudo", "yum", "check-update"], timeout=300)
|
|
if rc in (0, 100):
|
|
lines = out.splitlines() or ["No updates"]
|
|
return "📦 Updates (yum)", lines
|
|
return "❌ Updates (yum)", [f"yum check-update failed: {out}"]
|
|
|
|
if pm == "pacman":
|
|
rc, out = await run_cmd(["pacman", "-Qu"], timeout=120)
|
|
if rc == 0:
|
|
lines = out.splitlines() or ["No updates"]
|
|
return "📦 Updates (pacman)", lines
|
|
return "❌ Updates (pacman)", [f"pacman -Qu failed: {out}"]
|
|
|
|
return "⚠️ Updates", ["Unsupported package manager"]
|
|
|
|
|
|
async def apply_updates() -> str:
|
|
pm = detect_pkg_manager()
|
|
if not pm:
|
|
return "⚠️ No supported package manager found"
|
|
|
|
if pm == "apt":
|
|
await run_cmd(["sudo", "apt", "update"], timeout=300)
|
|
rc, out = await run_cmd(["sudo", "apt-get", "-y", "upgrade"], timeout=1800)
|
|
return f"⬆️ Upgrade (apt)\n```{out}```" if rc == 0 else f"❌ apt upgrade failed\n```{out}```"
|
|
|
|
if pm == "dnf":
|
|
rc, out = await run_cmd(["sudo", "dnf", "-y", "upgrade"], timeout=1800)
|
|
return f"⬆️ Upgrade (dnf)\n```{out}```" if rc == 0 else f"❌ dnf upgrade failed\n```{out}```"
|
|
|
|
if pm == "yum":
|
|
rc, out = await run_cmd(["sudo", "yum", "-y", "update"], timeout=1800)
|
|
return f"⬆️ Upgrade (yum)\n```{out}```" if rc == 0 else f"❌ yum update failed\n```{out}```"
|
|
|
|
if pm == "pacman":
|
|
rc, out = await run_cmd(["sudo", "pacman", "-Syu", "--noconfirm"], timeout=1800)
|
|
return f"⬆️ Upgrade (pacman)\n```{out}```" if rc == 0 else f"❌ pacman -Syu failed\n```{out}```"
|
|
|
|
return "⚠️ Unsupported package manager"
|