Ajout log dans interface
Passe a la version 0.2
This commit is contained in:
Binary file not shown.
109
git_updater.py
109
git_updater.py
@@ -5,7 +5,7 @@ Accès lecture seule uniquement (fetch/pull/checkout, jamais de push).
|
||||
Tous les chemins sont relatifs à l'emplacement de l'exécutable.
|
||||
"""
|
||||
|
||||
VERSION = "0.1"
|
||||
VERSION = "0.2"
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -460,9 +460,13 @@ class App(tk.Tk):
|
||||
date_label = ttk.Label(self, text=datetime.now().strftime(" %d/%m/%Y %H:%M:%S"), style="Status.TLabel")
|
||||
date_label.pack(anchor="w", padx=15)
|
||||
|
||||
# Panneau principal (PanedWindow vertical : cartes en haut, log en bas)
|
||||
paned = ttk.PanedWindow(self, orient="vertical")
|
||||
paned.pack(fill="both", expand=True, padx=15, pady=10)
|
||||
|
||||
# Zone scrollable pour les repos
|
||||
container = ttk.Frame(self)
|
||||
container.pack(fill="both", expand=True, padx=15, pady=10)
|
||||
container = ttk.Frame(paned)
|
||||
paned.add(container, weight=3)
|
||||
|
||||
self.canvas = tk.Canvas(container, bg=bg, highlightthickness=0)
|
||||
scrollbar = ttk.Scrollbar(container, orient="vertical", command=self.canvas.yview)
|
||||
@@ -478,6 +482,35 @@ class App(tk.Tk):
|
||||
# Scroll avec la molette
|
||||
self.canvas.bind_all("<MouseWheel>", lambda e: self.canvas.yview_scroll(int(-1 * (e.delta / 120)), "units"))
|
||||
|
||||
# Panneau de log en bas
|
||||
log_frame = tk.Frame(paned, bg="#181825")
|
||||
paned.add(log_frame, weight=1)
|
||||
|
||||
log_header = tk.Frame(log_frame, bg="#181825")
|
||||
log_header.pack(fill="x", padx=8, pady=(6, 2))
|
||||
tk.Label(log_header, text="Journal des operations", bg="#181825", fg="#a6adc8", font=("Segoe UI", 9, "bold")).pack(side="left")
|
||||
tk.Button(log_header, text="Effacer", bg="#313244", fg="#cdd6f4", bd=0, font=("Segoe UI", 8),
|
||||
command=self._clear_log_panel, activebackground="#45475a", activeforeground="#cdd6f4").pack(side="right")
|
||||
|
||||
self.log_text = tk.Text(log_frame, bg="#11111b", fg="#cdd6f4", font=("Consolas", 9),
|
||||
height=8, bd=0, highlightthickness=0, wrap="word",
|
||||
state="disabled", padx=8, pady=4)
|
||||
log_scroll = ttk.Scrollbar(log_frame, orient="vertical", command=self.log_text.yview)
|
||||
self.log_text.configure(yscrollcommand=log_scroll.set)
|
||||
|
||||
self.log_text.pack(side="left", fill="both", expand=True, padx=(8, 0), pady=(0, 8))
|
||||
log_scroll.pack(side="right", fill="y", padx=(0, 8), pady=(0, 8))
|
||||
|
||||
# Tags couleur pour le log GUI
|
||||
self.log_text.tag_configure("info", foreground="#cdd6f4")
|
||||
self.log_text.tag_configure("success", foreground="#a6e3a1")
|
||||
self.log_text.tag_configure("warning", foreground="#f9e2af")
|
||||
self.log_text.tag_configure("error", foreground="#f38ba8")
|
||||
self.log_text.tag_configure("file_add", foreground="#a6e3a1")
|
||||
self.log_text.tag_configure("file_mod", foreground="#f9e2af")
|
||||
self.log_text.tag_configure("file_del", foreground="#f38ba8")
|
||||
self.log_text.tag_configure("dim", foreground="#6c7086")
|
||||
|
||||
# Boutons en bas
|
||||
btn_frame = ttk.Frame(self)
|
||||
btn_frame.pack(fill="x", padx=15, pady=(0, 15))
|
||||
@@ -504,6 +537,26 @@ class App(tk.Tk):
|
||||
|
||||
threading.Thread(target=work, daemon=True).start()
|
||||
|
||||
def _log_gui(self, message, tag="info"):
|
||||
"""Ajoute une ligne dans le panneau de log."""
|
||||
def _append():
|
||||
self.log_text.configure(state="normal")
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
self.log_text.insert("end", f"[{timestamp}] ", "dim")
|
||||
self.log_text.insert("end", f"{message}\n", tag)
|
||||
self.log_text.see("end")
|
||||
self.log_text.configure(state="disabled")
|
||||
# Appel thread-safe
|
||||
if threading.current_thread() is threading.main_thread():
|
||||
_append()
|
||||
else:
|
||||
self.after(0, _append)
|
||||
|
||||
def _clear_log_panel(self):
|
||||
self.log_text.configure(state="normal")
|
||||
self.log_text.delete("1.0", "end")
|
||||
self.log_text.configure(state="disabled")
|
||||
|
||||
def _handle_self_update(self, needs_update, info):
|
||||
"""Gère le résultat de l'auto-update."""
|
||||
if needs_update:
|
||||
@@ -540,6 +593,7 @@ class App(tk.Tk):
|
||||
self.btn_refresh.state(["disabled"])
|
||||
self.btn_update_all.state(["disabled"])
|
||||
self.status_label.configure(text="Verification en cours...")
|
||||
self._log_gui("Verification des depots...", "info")
|
||||
self.repos_config = load_repos()
|
||||
|
||||
if not self.repos_config:
|
||||
@@ -573,6 +627,7 @@ class App(tk.Tk):
|
||||
total = len(self.repo_results)
|
||||
up = sum(1 for r in self.repo_results if r["up_to_date"])
|
||||
log.info(f"Resultat: {up}/{total} depots a jour")
|
||||
self._log_gui(f"Verification terminee : {up}/{total} depots a jour", "success" if up == total else "warning")
|
||||
self.status_label.configure(text=f"{up}/{total} depots a jour")
|
||||
self.btn_refresh.state(["!disabled"])
|
||||
|
||||
@@ -678,7 +733,9 @@ class App(tk.Tk):
|
||||
|
||||
def _do_update(self, res):
|
||||
"""Met à jour un dépôt (pull + restore)."""
|
||||
log.info(f"[{res['name']}] MAJ unitaire demandee")
|
||||
name = res["name"]
|
||||
log.info(f"[{name}] MAJ unitaire demandee")
|
||||
self._log_gui(f"[{name}] Mise a jour en cours...", "info")
|
||||
if "_btn" in res:
|
||||
res["_btn"].state(["disabled"])
|
||||
|
||||
@@ -688,41 +745,60 @@ class App(tk.Tk):
|
||||
local_path = res["local_path"]
|
||||
branch = res["branch"]
|
||||
|
||||
tag_map = {"A": "file_add", "M": "file_mod", "D": "file_del", "R": "file_mod"}
|
||||
|
||||
if res["commits"]:
|
||||
log.info(f"[{res['name']}] Pull de {len(res['commits'])} commit(s)...")
|
||||
log.info(f"[{name}] Pull de {len(res['commits'])} commit(s)...")
|
||||
self._log_gui(f"[{name}] Telechargement de {len(res['commits'])} commit(s)...", "info")
|
||||
ok, out, err = do_pull(local_path, branch)
|
||||
if ok:
|
||||
msg = f"Pull OK : {len(res['commits'])} commits telecharges."
|
||||
log.info(f"[{res['name']}] {msg}")
|
||||
log.info(f"[{name}] {msg}")
|
||||
self._log_gui(f"[{name}] {msg}", "success")
|
||||
# Logger chaque fichier distant
|
||||
for f in res.get("files", []):
|
||||
tag = tag_map.get(f["status_char"], "info")
|
||||
self._log_gui(f" [{f['status']:>9}] {f['file']}", tag)
|
||||
messages.append(msg)
|
||||
else:
|
||||
msg = f"Erreur pull : {err}"
|
||||
log.error(f"[{res['name']}] {msg}")
|
||||
log.error(f"[{name}] {msg}")
|
||||
self._log_gui(f"[{name}] {msg}", "error")
|
||||
messages.append(msg)
|
||||
success = False
|
||||
|
||||
if res["local_changes"]:
|
||||
log.info(f"[{res['name']}] Restauration de {len(res['local_changes'])} fichier(s)...")
|
||||
log.info(f"[{name}] Restauration de {len(res['local_changes'])} fichier(s)...")
|
||||
self._log_gui(f"[{name}] Restauration de {len(res['local_changes'])} fichier(s)...", "info")
|
||||
ok, err = do_restore(local_path)
|
||||
if ok:
|
||||
msg = f"Restauration OK : {len(res['local_changes'])} fichiers restaures."
|
||||
log.info(f"[{res['name']}] {msg}")
|
||||
log.info(f"[{name}] {msg}")
|
||||
self._log_gui(f"[{name}] {msg}", "success")
|
||||
# Logger chaque fichier restauré
|
||||
for f in res["local_changes"]:
|
||||
tag = tag_map.get(f["status_char"], "info")
|
||||
self._log_gui(f" [Restaure] {f['file']}", tag)
|
||||
messages.append(msg)
|
||||
else:
|
||||
msg = f"Erreur restauration : {err}"
|
||||
log.error(f"[{res['name']}] {msg}")
|
||||
log.error(f"[{name}] {msg}")
|
||||
self._log_gui(f"[{name}] {msg}", "error")
|
||||
messages.append(msg)
|
||||
success = False
|
||||
|
||||
status = "SUCCES" if success else "ECHEC"
|
||||
log.info(f"[{res['name']}] MAJ unitaire terminee - {status}")
|
||||
log.info(f"[{name}] MAJ unitaire terminee - {status}")
|
||||
self._log_gui(f"[{name}] Termine - {status}", "success" if success else "error")
|
||||
self.after(0, lambda: self._show_update_result(res, messages, success))
|
||||
|
||||
threading.Thread(target=work, daemon=True).start()
|
||||
|
||||
def _do_clone(self, res):
|
||||
"""Clone un dépôt."""
|
||||
log.info(f"[{res['name']}] Clonage demande - {res['url']}")
|
||||
name = res["name"]
|
||||
log.info(f"[{name}] Clonage demande - {res['url']}")
|
||||
self._log_gui(f"[{name}] Clonage en cours depuis {res['url']}...", "info")
|
||||
if "_btn" in res:
|
||||
res["_btn"].state(["disabled"])
|
||||
|
||||
@@ -731,11 +807,13 @@ class App(tk.Tk):
|
||||
def work():
|
||||
ok, err = do_clone(repo)
|
||||
if ok:
|
||||
msg = f"Depot '{res['name']}' clone avec succes !"
|
||||
log.info(f"[{res['name']}] {msg}")
|
||||
msg = f"Depot '{name}' clone avec succes !"
|
||||
log.info(f"[{name}] {msg}")
|
||||
self._log_gui(f"[{name}] {msg}", "success")
|
||||
else:
|
||||
msg = f"Erreur de clonage : {err}"
|
||||
log.error(f"[{res['name']}] {msg}")
|
||||
log.error(f"[{name}] {msg}")
|
||||
self._log_gui(f"[{name}] {msg}", "error")
|
||||
self.after(0, lambda: messagebox.showinfo("Clonage", msg))
|
||||
self.after(100, self._start_check)
|
||||
|
||||
@@ -750,6 +828,7 @@ class App(tk.Tk):
|
||||
"""Met à jour tous les dépôts qui ont des MAJ."""
|
||||
to_update = [r for r in self.repo_results if not r["up_to_date"] and not r.get("error") and not r.get("needs_clone")]
|
||||
log.info(f"MAJ globale demandee - {len(to_update)} depot(s) a mettre a jour")
|
||||
self._log_gui(f"MAJ globale : {len(to_update)} depot(s) a mettre a jour", "warning")
|
||||
for res in to_update:
|
||||
self._do_update(res)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user