Compare commits
2 Commits
18bda249b5
...
ba1cf1ea25
| Author | SHA1 | Date | |
|---|---|---|---|
| ba1cf1ea25 | |||
| 3ecae321e7 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,3 +3,5 @@ dist/
|
|||||||
build/
|
build/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.spec
|
*.spec
|
||||||
|
*.exe.old
|
||||||
|
_update.bat
|
||||||
|
|||||||
BIN
GitUpdateChecker.exe
Normal file
BIN
GitUpdateChecker.exe
Normal file
Binary file not shown.
@@ -5,6 +5,8 @@ Accès lecture seule uniquement (fetch/pull/checkout, jamais de push).
|
|||||||
Tous les chemins sont relatifs à l'emplacement de l'exécutable.
|
Tous les chemins sont relatifs à l'emplacement de l'exécutable.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
VERSION = "0.1"
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@@ -139,25 +141,80 @@ def check_self_update():
|
|||||||
|
|
||||||
|
|
||||||
def do_self_update():
|
def do_self_update():
|
||||||
"""Pull les mises à jour du programme lui-même. Retourne (ok, message)."""
|
"""
|
||||||
|
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 git pull le nouveau.
|
||||||
|
Retourne (ok, message).
|
||||||
|
"""
|
||||||
exe_dir = str(get_exe_dir())
|
exe_dir = str(get_exe_dir())
|
||||||
|
is_frozen = getattr(sys, "frozen", False)
|
||||||
|
|
||||||
code, branch, _ = run_git(["rev-parse", "--abbrev-ref", "HEAD"], cwd=exe_dir)
|
code, branch, _ = run_git(["rev-parse", "--abbrev-ref", "HEAD"], cwd=exe_dir)
|
||||||
if code != 0:
|
if code != 0:
|
||||||
return False, "Impossible de lire la branche"
|
return False, "Impossible de lire la branche"
|
||||||
|
|
||||||
# Restaurer les fichiers locaux modifiés d'abord
|
# Si on tourne en .exe, renommer l'exe actuel pour libérer le fichier
|
||||||
run_git(["checkout", "--", "."], cwd=exe_dir)
|
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}"
|
||||||
|
|
||||||
|
# Restaurer les fichiers locaux modifiés puis pull
|
||||||
|
run_git(["checkout", "--", "."], cwd=exe_dir)
|
||||||
|
code, _, err = run_git(["pull", "origin", branch], cwd=exe_dir)
|
||||||
|
|
||||||
code, out, err = run_git(["pull", "origin", branch], cwd=exe_dir)
|
|
||||||
if code == 0:
|
if code == 0:
|
||||||
log.info(f"Auto-update: pull OK")
|
log.info("Auto-update: pull OK")
|
||||||
return True, "Mise a jour du programme reussie !\nRedemarre le programme pour appliquer."
|
return True, "Mise a jour reussie !\nLe programme va redemarrer."
|
||||||
else:
|
else:
|
||||||
|
# En cas d'échec, restaurer l'ancien exe
|
||||||
|
if is_frozen and exe_old_path and exe_old_path.exists():
|
||||||
|
try:
|
||||||
|
exe_old_path.rename(Path(sys.executable))
|
||||||
|
log.info("Auto-update: exe restaure apres echec")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
log.error(f"Auto-update: pull echoue: {err}")
|
log.error(f"Auto-update: pull echoue: {err}")
|
||||||
return False, f"Erreur pull: {err}"
|
return False, f"Erreur pull: {err}"
|
||||||
|
|
||||||
|
|
||||||
|
def relaunch_program():
|
||||||
|
"""Relance le programme (nouvel exe) et quitte le processus actuel."""
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
exe_path = str(Path(sys.executable))
|
||||||
|
log.info(f"Auto-update: relance de {exe_path}")
|
||||||
|
# Lancer un batch qui attend 1s puis lance le nouvel exe et supprime l'ancien .old
|
||||||
|
bat_path = str(get_exe_dir() / "_update.bat")
|
||||||
|
bat_content = (
|
||||||
|
f'@echo off\n'
|
||||||
|
f'timeout /t 1 /nobreak >nul\n'
|
||||||
|
f'start "" "{exe_path}"\n'
|
||||||
|
f'del "{exe_path}.old" 2>nul\n'
|
||||||
|
f'del "%~f0"\n'
|
||||||
|
)
|
||||||
|
with open(bat_path, "w") as f:
|
||||||
|
f.write(bat_content)
|
||||||
|
subprocess.Popen(
|
||||||
|
["cmd", "/c", bat_path],
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Mode script : relancer python
|
||||||
|
log.info("Auto-update: relance du script")
|
||||||
|
subprocess.Popen([sys.executable, __file__])
|
||||||
|
|
||||||
|
|
||||||
# ── Configuration ────────────────────────────────────────────────────────────
|
# ── Configuration ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def get_config_path():
|
def get_config_path():
|
||||||
@@ -359,7 +416,7 @@ def do_restore(local_path):
|
|||||||
class App(tk.Tk):
|
class App(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.title("Git Update Checker")
|
self.title(f"Git Update Checker v{VERSION}")
|
||||||
self.geometry("820x600")
|
self.geometry("820x600")
|
||||||
self.minsize(700, 450)
|
self.minsize(700, 450)
|
||||||
self.configure(bg="#1e1e2e")
|
self.configure(bg="#1e1e2e")
|
||||||
@@ -367,7 +424,7 @@ class App(tk.Tk):
|
|||||||
self.repos_config = load_repos()
|
self.repos_config = load_repos()
|
||||||
self.repo_results = []
|
self.repo_results = []
|
||||||
|
|
||||||
log.info("=== Demarrage Git Update Checker ===")
|
log.info(f"=== Demarrage Git Update Checker v{VERSION} ===")
|
||||||
self._build_ui()
|
self._build_ui()
|
||||||
self.after(100, self._check_self_update_then_repos)
|
self.after(100, self._check_self_update_then_repos)
|
||||||
|
|
||||||
@@ -395,7 +452,7 @@ class App(tk.Tk):
|
|||||||
# Header
|
# Header
|
||||||
header = ttk.Frame(self)
|
header = ttk.Frame(self)
|
||||||
header.pack(fill="x", padx=15, pady=(15, 5))
|
header.pack(fill="x", padx=15, pady=(15, 5))
|
||||||
ttk.Label(header, text="Git Update Checker", style="Title.TLabel").pack(side="left")
|
ttk.Label(header, text=f"Git Update Checker v{VERSION}", style="Title.TLabel").pack(side="left")
|
||||||
self.status_label = ttk.Label(header, text="Verification en cours...", style="Status.TLabel")
|
self.status_label = ttk.Label(header, text="Verification en cours...", style="Status.TLabel")
|
||||||
self.status_label.pack(side="right")
|
self.status_label.pack(side="right")
|
||||||
|
|
||||||
@@ -470,7 +527,8 @@ class App(tk.Tk):
|
|||||||
"""Callback après auto-update."""
|
"""Callback après auto-update."""
|
||||||
if ok:
|
if ok:
|
||||||
messagebox.showinfo("Auto-update", msg)
|
messagebox.showinfo("Auto-update", msg)
|
||||||
log.info("Auto-update appliquee, fermeture")
|
log.info("Auto-update appliquee, relance...")
|
||||||
|
relaunch_program()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user