diff --git a/src/editor/updater.gd b/src/editor/updater.gd index 6d6b126..19e80e7 100644 --- a/src/editor/updater.gd +++ b/src/editor/updater.gd @@ -124,7 +124,7 @@ static func remote_sha(git_exe: String, project_dir: String, branch: String) -> var text := str(r["output"]).strip_edges() if text.is_empty(): return "" - return text.split("\n")[0].strip_edges().split("\t")[0] + return sha_aus_ls_remote(text, branch) ## Update-Check: lokaler HEAD vs. origin/main. @@ -152,12 +152,65 @@ static func check_update(git_exe: String, project_dir: String) -> Dictionary: if text2.is_empty(): return {"status": "unreachable", "local": local, "remote": "", "error": "Origin nicht erreichbar (offline oder Tunnel weg)."} - var remote := text2.split("\n")[0].strip_edges().split("\t")[0] + var remote := sha_aus_ls_remote(text2, BRANCH) + if remote.is_empty(): + # Kein echter Commit in der Ausgabe (nur Warnungen/leer) — NICHT als + # Update deuten, sonst hängt das Banner endlos (Karte t_50a07d4b-Live-Bug). + return {"status": "unreachable", "local": local, "remote": "", + "error": "Origin lieferte keinen Commit (nur Warnungen)."} if local == remote: return {"status": "up_to_date", "local": local, "remote": remote, "error": ""} return {"status": "update_available", "local": local, "remote": remote, "error": ""} +## Aus der gemischten ls-remote-Ausgabe den Commit für `branch` lesen. +## WARUM: `git_run` mischt stdout+stderr, und der git-Client schreibt bei einer +## HTTP-Umleitung zuerst "warning: Umleitung nach ..." — die alte Fassung nahm +## stumpf die ERSTE Zeile und hielt "warning" für den Ziel-Commit. Ergebnis war +## ein Banner "Update verfügbar: → warning", das nie verschwand, obwohl +## der Pull korrekt lief (live belegt 20.10., Klon stand auf origin/main). +## Regeln: nur Zeilen "\t" zählen, sha = echter Hex-String. +static func sha_aus_ls_remote(text: String, branch: String) -> String: + var ziel := "refs/heads/%s" % branch + var locker := "" + for zeile in text.split("\n"): + var z := zeile.strip_edges() + if z.is_empty(): + continue + var klein := z.to_lower() + if klein.begins_with("warning") or klein.begins_with("hint") \ + or klein.begins_with("fatal") or klein.begins_with("error"): + continue + var teile := z.split("\t") + if teile.size() < 2: + continue + var sha := teile[0].strip_edges() + if not ist_sha(sha): + continue + if teile[1].strip_edges() == ziel: + return sha + if locker.is_empty(): + locker = sha + return locker + + +## Sieht der Text wie ein Git-Objekt-Hash aus (7-40 Hex-Zeichen)? +static func ist_sha(text: String) -> bool: + var t := text.strip_edges() + if t.length() < 7 or t.length() > 40: + return false + for i in t.length(): + var c := t[i] + if c >= "0" and c <= "9": + continue + if c >= "a" and c <= "f": + continue + if c >= "A" and c <= "F": + continue + return false + return true + + ## Kurzer SHA für Anzeigen (7 Zeichen, wie git log --oneline). static func short_sha(sha: String) -> String: return sha.substr(0, 7) diff --git a/tests/test_updater.gd b/tests/test_updater.gd index bac23a3..7943644 100644 --- a/tests/test_updater.gd +++ b/tests/test_updater.gd @@ -26,6 +26,7 @@ func _init() -> void: TEST_DIR_PREFIX + "_" + str(Time.get_ticks_msec())) DirAccess.make_dir_recursive_absolute(base) _run_tests() + _test_ls_remote_warnzeile() _cleanup_dir(base) # best effort — git-Pack-Dateien können read-only sein if failures == 0: print("ALL OK: %d checks" % checks) @@ -336,3 +337,25 @@ func _run_tests() -> void: var self_args := EditorUpdater.self_restart_args("/pfad/zum/klon") _check(str(self_args[0]) == "--path" and str(self_args[1]) == "/pfad/zum/klon", "Selbst-Restart: --path (startet die Map-Editor-APP, nicht die Godot-Editor-Shell)") + + +## Regression (20.10., Live-Bug im Map-Builder): git schreibt bei einer +## HTTP-Umleitung zuerst "warning: Umleitung nach ..." in die GEMISCHTE +## Ausgabe (git_run mischt stdout+stderr). Die alte Fassung nahm die ERSTE +## Zeile als Ziel-Commit → Banner "Update verfügbar: → warning" hing +## endlos, obwohl der Klon aktuell war. Erwartung: echte "\t"-Zeile +## gewinnt, Warnzeilen werden nie als SHA gelesen. +func _test_ls_remote_warnzeile() -> void: + var sha := "d0d4fbd2213e596d117b779c6d931629bf9b20ed" + var mit_warnung := "warning: Umleitung nach http://127.0.0.1:13020/x.git/\n%s\trefs/heads/main\n" % sha + _check(EditorUpdater.sha_aus_ls_remote(mit_warnung, "main") == sha, + "Warnzeile ignoriert, echter Commit gelesen") + _check(not EditorUpdater.ist_sha("warning"), "'warning' gilt nicht als SHA") + _check(EditorUpdater.sha_aus_ls_remote("warning: Umleitung nach x\n", "main") == "", + "nur Warnzeilen → leerer Commit (kein Update-Banner)") + _check(EditorUpdater.sha_aus_ls_remote("fatal: could not read Username\n", "main") == "", + "fatal-Zeile wird nicht als SHA gelesen") + _check(EditorUpdater.sha_aus_ls_remote("%s\trefs/heads/main" % sha, "main") == sha, + "normale Zeile funktioniert weiterhin") + _check(EditorUpdater.sha_aus_ls_remote("%s\trefs/heads/anderer" % sha, "main") == sha, + "anderer Branch: SHA bleibt als Notnagel nutzbar")