FIx Maj exe
This commit is contained in:
Binary file not shown.
@@ -2,6 +2,9 @@
|
||||
; Les chemins (path) sont relatifs a l'emplacement de l'exe
|
||||
; Ajouter autant de sections [repo:NomDuRepo] que necessaire
|
||||
|
||||
[self-update]
|
||||
url = http://192.168.1.235:3125/zogzog/Lanceur-geco
|
||||
exe_name = GitUpdateChecker.exe
|
||||
|
||||
[repo:Scripts]
|
||||
url = http://192.168.1.235:3125/zogzog/Scripts
|
||||
|
||||
183
git_updater.py
183
git_updater.py
@@ -17,6 +17,8 @@ import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
# Forcer UTF-8 sur Windows
|
||||
if sys.platform == "win32":
|
||||
@@ -97,120 +99,135 @@ def run_git(args, cwd=None):
|
||||
|
||||
# ── Auto-update du programme ─────────────────────────────────────────────────
|
||||
|
||||
def _version_tuple(v):
|
||||
"""Convertit '0.4' en (0, 4) pour comparaison."""
|
||||
try:
|
||||
return tuple(int(x) for x in v.strip().split("."))
|
||||
except (ValueError, AttributeError):
|
||||
return (0,)
|
||||
|
||||
|
||||
def _get_self_update_config():
|
||||
"""Lit la config [self-update] depuis config.ini. Retourne (url, exe_name) ou (None, None)."""
|
||||
config_path = get_config_path()
|
||||
if not config_path.exists():
|
||||
return None, None
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_path, encoding="utf-8")
|
||||
if not config.has_section("self-update"):
|
||||
return None, None
|
||||
url = config.get("self-update", "url", fallback="").strip().rstrip("/")
|
||||
exe_name = config.get("self-update", "exe_name", fallback="GitUpdateChecker.exe").strip()
|
||||
if not url:
|
||||
return None, None
|
||||
return url, exe_name
|
||||
|
||||
|
||||
def check_self_update():
|
||||
"""
|
||||
Vérifie si le dossier de l'exe est un dépôt git avec des MAJ disponibles.
|
||||
Vérifie si une nouvelle version est disponible sur le serveur Gitea.
|
||||
Télécharge version.txt via HTTP et compare avec VERSION locale.
|
||||
Retourne (needs_update: bool, info: str).
|
||||
"""
|
||||
exe_dir = str(get_exe_dir())
|
||||
|
||||
if not os.path.isdir(os.path.join(exe_dir, ".git")):
|
||||
log.info("Auto-update: pas de .git dans le dossier de l'exe, skip")
|
||||
repo_url, _ = _get_self_update_config()
|
||||
if not repo_url:
|
||||
log.info("Auto-update: pas de section [self-update] dans config.ini, skip")
|
||||
return False, ""
|
||||
|
||||
log.info("Auto-update: verification...")
|
||||
log.info("Auto-update: verification via HTTP...")
|
||||
|
||||
code, branch, _ = run_git(["rev-parse", "--abbrev-ref", "HEAD"], cwd=exe_dir)
|
||||
if code != 0:
|
||||
return False, "Impossible de lire la branche"
|
||||
version_url = f"{repo_url}/raw/branch/master/version.txt"
|
||||
try:
|
||||
req = urllib.request.Request(version_url, headers={"User-Agent": "GitUpdateChecker"})
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
remote_version = resp.read().decode("utf-8").strip()
|
||||
except (urllib.error.URLError, OSError) as e:
|
||||
log.warning(f"Auto-update: impossible de verifier la version distante: {e}")
|
||||
return False, f"Impossible de contacter le serveur: {e}"
|
||||
|
||||
code, _, err = run_git(["fetch", "origin"], cwd=exe_dir)
|
||||
if code != 0:
|
||||
log.warning(f"Auto-update: fetch echoue: {err}")
|
||||
return False, f"Fetch echoue: {err}"
|
||||
log.info(f"Auto-update: version locale={VERSION} distante={remote_version}")
|
||||
|
||||
code, local_hash, _ = run_git(["rev-parse", "HEAD"], cwd=exe_dir)
|
||||
code2, remote_hash, _ = run_git(["rev-parse", f"origin/{branch}"], cwd=exe_dir)
|
||||
|
||||
if code != 0 or code2 != 0:
|
||||
return False, "Impossible de comparer les commits"
|
||||
|
||||
log.info(f"Auto-update: local={local_hash[:8]} remote={remote_hash[:8]} branche={branch}")
|
||||
|
||||
if local_hash == remote_hash:
|
||||
if _version_tuple(remote_version) <= _version_tuple(VERSION):
|
||||
log.info("Auto-update: programme a jour")
|
||||
return False, ""
|
||||
|
||||
# Compter les commits en retard
|
||||
code, log_out, _ = run_git(
|
||||
["log", "--oneline", f"HEAD..origin/{branch}"],
|
||||
cwd=exe_dir,
|
||||
)
|
||||
count = len(log_out.splitlines()) if code == 0 and log_out else 0
|
||||
|
||||
if count == 0:
|
||||
# Hashes differents mais aucun commit a tirer (local en avance) -> pas de MAJ
|
||||
log.info("Auto-update: hashes differents mais 0 commit a tirer, skip")
|
||||
return False, ""
|
||||
|
||||
info = f"{count} commit(s) en retard sur origin/{branch}"
|
||||
log.info(f"Auto-update: MAJ disponible - {info}")
|
||||
info = f"Version actuelle : {VERSION}\nVersion disponible : {remote_version}"
|
||||
log.info(f"Auto-update: MAJ disponible - {remote_version}")
|
||||
return True, info
|
||||
|
||||
|
||||
def do_self_update():
|
||||
"""
|
||||
Met à jour le programme lui-même.
|
||||
Sur Windows, un .exe en cours d'exécution ne peut pas être écrasé.
|
||||
Stratégie : renommer l'exe actuel en .old, puis reset hard sur origin.
|
||||
Télécharge le nouvel exe depuis le serveur Gitea.
|
||||
Stratégie : télécharger dans .new, renommer l'exe actuel en .old, placer le nouveau.
|
||||
Retourne (ok, message).
|
||||
"""
|
||||
exe_dir = str(get_exe_dir())
|
||||
repo_url, exe_name = _get_self_update_config()
|
||||
if not repo_url:
|
||||
return False, "Configuration [self-update] manquante"
|
||||
|
||||
is_frozen = getattr(sys, "frozen", False)
|
||||
if not is_frozen:
|
||||
log.warning("Auto-update: mode script, telechargement non supporte")
|
||||
return False, "Auto-update uniquement supporte en mode .exe"
|
||||
|
||||
code, branch, _ = run_git(["rev-parse", "--abbrev-ref", "HEAD"], cwd=exe_dir)
|
||||
if code != 0:
|
||||
return False, "Impossible de lire la branche"
|
||||
exe_path = Path(sys.executable)
|
||||
exe_old_path = exe_path.with_suffix(".exe.old")
|
||||
exe_new_path = exe_path.with_suffix(".exe.new")
|
||||
|
||||
# Sauvegarder config.ini avant reset (le reset va l'ecraser)
|
||||
config_path = get_exe_dir() / "config.ini"
|
||||
config_backup = None
|
||||
if config_path.exists():
|
||||
try:
|
||||
config_backup = config_path.read_text(encoding="utf-8")
|
||||
log.info("Auto-update: config.ini sauvegarde")
|
||||
except OSError:
|
||||
pass
|
||||
# Telecharger le nouvel exe
|
||||
download_url = f"{repo_url}/raw/branch/master/{exe_name}"
|
||||
log.info(f"Auto-update: telechargement de {download_url}")
|
||||
|
||||
# Si on tourne en .exe, renommer l'exe actuel pour libérer le fichier
|
||||
exe_old_path = None
|
||||
if is_frozen:
|
||||
exe_path = Path(sys.executable)
|
||||
exe_old_path = exe_path.with_suffix(".exe.old")
|
||||
try:
|
||||
# Supprimer un ancien .old s'il existe
|
||||
if exe_old_path.exists():
|
||||
exe_old_path.unlink()
|
||||
# Windows permet de renommer un exe en cours d'exécution
|
||||
exe_path.rename(exe_old_path)
|
||||
log.info(f"Auto-update: exe renomme {exe_path.name} -> {exe_old_path.name}")
|
||||
except OSError as e:
|
||||
log.error(f"Auto-update: impossible de renommer l'exe: {e}")
|
||||
return False, f"Impossible de renommer l'exe: {e}"
|
||||
try:
|
||||
req = urllib.request.Request(download_url, headers={"User-Agent": "GitUpdateChecker"})
|
||||
with urllib.request.urlopen(req, timeout=60) as resp:
|
||||
data = resp.read()
|
||||
|
||||
# Reset hard sur origin pour forcer la MAJ (methode la plus fiable)
|
||||
code, _, err = run_git(["reset", "--hard", f"origin/{branch}"], cwd=exe_dir)
|
||||
if len(data) < 1000:
|
||||
log.error(f"Auto-update: fichier telecharge trop petit ({len(data)} octets)")
|
||||
return False, "Le fichier telecharge semble invalide"
|
||||
|
||||
if code != 0:
|
||||
# Echec, restaurer l'ancien exe
|
||||
if is_frozen and exe_old_path and exe_old_path.exists():
|
||||
with open(exe_new_path, "wb") as f:
|
||||
f.write(data)
|
||||
log.info(f"Auto-update: telecharge {len(data)} octets -> {exe_new_path.name}")
|
||||
|
||||
except (urllib.error.URLError, OSError) as e:
|
||||
log.error(f"Auto-update: echec telechargement: {e}")
|
||||
if exe_new_path.exists():
|
||||
try:
|
||||
exe_old_path.rename(Path(sys.executable))
|
||||
log.info("Auto-update: exe restaure apres echec")
|
||||
exe_new_path.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
log.error(f"Auto-update: reset echoue: {err}")
|
||||
return False, f"Erreur mise a jour: {err}"
|
||||
return False, f"Erreur telechargement: {e}"
|
||||
|
||||
log.info("Auto-update: reset --hard OK")
|
||||
# Renommer : exe actuel -> .old
|
||||
try:
|
||||
if exe_old_path.exists():
|
||||
exe_old_path.unlink()
|
||||
exe_path.rename(exe_old_path)
|
||||
log.info(f"Auto-update: {exe_path.name} -> {exe_old_path.name}")
|
||||
except OSError as e:
|
||||
log.error(f"Auto-update: impossible de renommer l'exe: {e}")
|
||||
if exe_new_path.exists():
|
||||
try:
|
||||
exe_new_path.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
return False, f"Impossible de renommer l'exe: {e}"
|
||||
|
||||
# Restaurer config.ini de l'utilisateur
|
||||
if config_backup is not None:
|
||||
# Renommer : .new -> exe
|
||||
try:
|
||||
exe_new_path.rename(exe_path)
|
||||
log.info(f"Auto-update: {exe_new_path.name} -> {exe_path.name}")
|
||||
except OSError as e:
|
||||
log.error(f"Auto-update: impossible de placer le nouvel exe: {e}")
|
||||
try:
|
||||
config_path.write_text(config_backup, encoding="utf-8")
|
||||
log.info("Auto-update: config.ini restaure")
|
||||
except OSError as e:
|
||||
log.warning(f"Auto-update: impossible de restaurer config.ini: {e}")
|
||||
exe_old_path.rename(exe_path)
|
||||
log.info("Auto-update: ancien exe restaure")
|
||||
except OSError:
|
||||
pass
|
||||
return False, f"Impossible de placer le nouvel exe: {e}"
|
||||
|
||||
return True, "Mise a jour reussie !\nLe programme va redemarrer."
|
||||
|
||||
|
||||
1
version.txt
Normal file
1
version.txt
Normal file
@@ -0,0 +1 @@
|
||||
0.4
|
||||
Reference in New Issue
Block a user