136 lines
3.7 KiB
Python
136 lines
3.7 KiB
Python
import json
|
|
import os
|
|
import shlex
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import threading
|
|
import urllib.request
|
|
import stat
|
|
|
|
API_URL = "https://api.github.com/repos/srinivasr/nirimod/commits/main"
|
|
INSTALL_DIR = os.path.expanduser("~/.local/share/nirimod")
|
|
FALLBACK_TERMINALS = [
|
|
"xdg-terminal-exec",
|
|
"gnome-terminal",
|
|
"kgx", # GNOME Console
|
|
"kitty",
|
|
"ghostty",
|
|
"alacritty",
|
|
"konsole",
|
|
"foot",
|
|
"xterm",
|
|
]
|
|
|
|
|
|
def check_for_updates(callback):
|
|
|
|
def _do_check():
|
|
try:
|
|
from gi.repository import GLib
|
|
|
|
if not os.path.isdir(os.path.join(INSTALL_DIR, ".git")):
|
|
GLib.idle_add(callback, None, None)
|
|
return
|
|
|
|
local_hash = subprocess.check_output(
|
|
["git", "rev-parse", "HEAD"],
|
|
cwd=INSTALL_DIR,
|
|
text=True,
|
|
).strip()
|
|
|
|
req = urllib.request.Request(
|
|
API_URL, headers={"User-Agent": "NiriMod-Updater"}
|
|
)
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
data = json.loads(resp.read().decode("utf-8"))
|
|
remote_hash = data.get("sha")
|
|
commit_msg = data.get("commit", {}).get(
|
|
"message", "New update available"
|
|
)
|
|
|
|
if _update_available(local_hash, remote_hash, INSTALL_DIR):
|
|
GLib.idle_add(callback, remote_hash, commit_msg)
|
|
else:
|
|
GLib.idle_add(callback, None, None)
|
|
|
|
except Exception as e:
|
|
print(f"Update check failed: {e}")
|
|
GLib.idle_add(callback, None, None)
|
|
|
|
threading.Thread(target=_do_check, daemon=True).start()
|
|
|
|
|
|
def _commit_is_ancestor(commit_hash: str, install_dir: str) -> bool:
|
|
result = subprocess.run(
|
|
["git", "merge-base", "--is-ancestor", commit_hash, "HEAD"],
|
|
cwd=install_dir,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
check=False,
|
|
)
|
|
return result.returncode == 0
|
|
|
|
|
|
def _update_available(
|
|
local_hash: str, remote_hash: str | None, install_dir: str = INSTALL_DIR
|
|
) -> bool:
|
|
if not remote_hash or remote_hash == local_hash:
|
|
return False
|
|
if _commit_is_ancestor(remote_hash, install_dir):
|
|
return False
|
|
return True
|
|
|
|
|
|
def _terminal_candidates():
|
|
terminal = os.environ.get("TERMINAL", "").strip()
|
|
if terminal:
|
|
yield terminal
|
|
yield from FALLBACK_TERMINALS
|
|
|
|
|
|
def _build_terminal_command(terminal: str, script_path: str) -> list[str] | None:
|
|
try:
|
|
parts = shlex.split(terminal)
|
|
except ValueError:
|
|
return None
|
|
|
|
if not parts:
|
|
return None
|
|
|
|
if os.path.basename(parts[0]) == "xdg-terminal-exec":
|
|
return [*parts, script_path]
|
|
|
|
if parts[-1] in {"-e", "--execute", "-x"}:
|
|
return [*parts, script_path]
|
|
|
|
return [*parts, "-e", script_path]
|
|
|
|
|
|
def launch_updater_in_terminal():
|
|
|
|
script_content = """#!/usr/bin/env bash
|
|
echo "Starting NiriMod update..."
|
|
curl -sSL https://raw.githubusercontent.com/srinivasr/nirimod/main/install.sh | bash -s -- --install
|
|
echo ""
|
|
echo "Update complete! Press Enter to close this window."
|
|
read
|
|
"""
|
|
script_path = os.path.join(tempfile.gettempdir(), "nirimod_update.sh")
|
|
with open(script_path, "w") as f:
|
|
f.write(script_content)
|
|
os.chmod(script_path, stat.S_IRWXU)
|
|
|
|
for term in _terminal_candidates():
|
|
command = _build_terminal_command(term, script_path)
|
|
if command is None or shutil.which(command[0]) is None:
|
|
continue
|
|
|
|
try:
|
|
subprocess.Popen(command)
|
|
return
|
|
except Exception:
|
|
continue
|
|
|
|
print("Could not find a suitable terminal to launch the update.")
|