FIx Maj exe

This commit is contained in:
2026-03-24 15:57:44 +01:00
parent 4cf30c6110
commit 8b5b92bb4f
4 changed files with 104 additions and 83 deletions

Binary file not shown.

View File

@@ -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

View File

@@ -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
View File

@@ -0,0 +1 @@
0.4