diff --git a/GitUpdateChecker.exe b/GitUpdateChecker.exe index 4619ede..9dd1984 100644 Binary files a/GitUpdateChecker.exe and b/GitUpdateChecker.exe differ diff --git a/git_updater.py b/git_updater.py index 9a8a383..278fc8f 100644 --- a/git_updater.py +++ b/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.5.2" +VERSION = "0.5.3" import subprocess import sys @@ -77,13 +77,13 @@ def setup_logging(): log = setup_logging() -def run_git(args, cwd=None): +def run_git(args, cwd=None, timeout=30): # -c safe.directory=* : évite l'erreur "dubious ownership" sur clé USB cmd = ["git", "-c", "safe.directory=*"] + args log.debug(f"git {' '.join(args)} (cwd={cwd})") try: result = subprocess.run( - cmd, cwd=cwd, capture_output=True, text=True, timeout=30, + cmd, cwd=cwd, capture_output=True, text=True, timeout=timeout, creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0, ) if result.returncode != 0 and result.stderr.strip(): @@ -341,21 +341,19 @@ def check_repo(repo): return result result["branch"] = branch - # Vérifier que le remote est accessible via l'URL du config.ini - code, _, err = run_git(["ls-remote", "--exit-code", url, "HEAD"]) - if code != 0: - log.warning(f"[{name}] Remote inaccessible: {url}") - result["error"] = "Depot hors ligne (remote inaccessible)" - result["offline"] = True - return result - # Mettre à jour l'URL origin si elle a changé dans config.ini run_git(["remote", "set-url", "origin", url], cwd=local_path) - # Fetch + # Fetch (détecte aussi si le remote est inaccessible) code, _, err = run_git(["fetch", "origin"], cwd=local_path) if code != 0: - result["error"] = f"Erreur fetch : {err}" + offline_keywords = ["could not resolve", "connection refused", "unable to connect", "timed out", "the remote end hung up"] + if any(kw in err.lower() for kw in offline_keywords): + log.warning(f"[{name}] Remote inaccessible: {url}") + result["error"] = "Depot hors ligne (remote inaccessible)" + result["offline"] = True + else: + result["error"] = f"Erreur fetch : {err}" return result # Comparer HEAD local vs origin @@ -436,7 +434,7 @@ def do_clone(repo): """Clone un dépôt.""" local_path = str(resolve_relative(repo["path"])) log.info(f"Clonage: {repo['url']} -> {local_path}") - code, _, err = run_git(["clone", repo["url"], local_path]) + code, _, err = run_git(["clone", repo["url"], local_path], timeout=300) if code == 0: log.info(f"Clonage reussi: {local_path}") else: @@ -447,7 +445,7 @@ def do_clone(repo): def do_pull(local_path, branch): """Pull les mises à jour (lecture seule).""" log.info(f"Pull: {local_path} (branche {branch})") - code, out, err = run_git(["pull", "origin", branch], cwd=local_path) + code, out, err = run_git(["pull", "origin", branch], cwd=local_path, timeout=120) if code == 0: log.info(f"Pull reussi: {local_path}") else: @@ -800,7 +798,7 @@ class App(tk.Tk): return card - def _do_update(self, res): + def _do_update(self, res, batch=False): """Met à jour un dépôt (pull + restore).""" name = res["name"] log.info(f"[{name}] MAJ unitaire demandee") @@ -859,7 +857,7 @@ class App(tk.Tk): status = "SUCCES" if success else "ECHEC" 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)) + self.after(0, lambda: self._show_update_result(res, messages, success, batch=batch)) threading.Thread(target=work, daemon=True).start() @@ -888,18 +886,28 @@ class App(tk.Tk): threading.Thread(target=work, daemon=True).start() - def _show_update_result(self, res, messages, success): - title = "Mise a jour" if success else "Erreur" - messagebox.showinfo(title, f"{res['name']}\n\n" + "\n".join(messages)) - self._start_check() + def _show_update_result(self, res, messages, success, batch=False): + if batch: + # En mode batch : pas de messagebox individuelle, on ne rafraichit qu'une fois à la fin + self._batch_remaining -= 1 + if self._batch_remaining == 0: + self._start_check() + else: + title = "Mise a jour" if success else "Erreur" + messagebox.showinfo(title, f"{res['name']}\n\n" + "\n".join(messages)) + self._start_check() def _update_all(self): """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")] + if not to_update: + return 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") + # Compteur pour n'appeler _start_check qu'une seule fois quand tous sont termines + self._batch_remaining = len(to_update) for res in to_update: - self._do_update(res) + self._do_update(res, batch=True) def _show_no_repos(self): bg_card = "#313244" diff --git a/version.txt b/version.txt index cb0c939..be14282 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.5.2 +0.5.3