Fix Update-Banner hing endlos: git-Warnzeile wurde als Ziel-Commit gelesen (t_50a07d4b-Live-Bug, Meldung Sly 20.10.)

git_run mischt stdout+stderr; bei der HTTP-Umleitung der Forgejo-URL schreibt
git zuerst 'warning: Umleitung nach ...'. Die alte Fassung nahm die ERSTE
Zeile und hielt 'warning' fuer den Remote-SHA -> Banner 'Update verfuegbar:
<sha> -> warning' blieb fuer immer, obwohl der Klon auf origin/main stand
(live auf dem PC belegt: STDOUT korrekt, STDERR Warnung).

Jetzt: sha_aus_ls_remote() liest nur echte '<sha>\t<refs/heads/...>'-Zeilen
(Warnungen/hints/fatal uebersprungen, SHA muss Hex sein), Notnagel = erste
hex-artige Zeile; 'kein Commit in der Ausgabe' gilt als unreachable statt
update_available. Regressionstest: 6 neue Checks in test_updater.gd.
This commit is contained in:
Hermes (scopedvr-dev) 2026-10-20 05:27:02 +00:00
parent d0d4fbd221
commit 437f6bf368
2 changed files with 78 additions and 2 deletions

View file

@ -124,7 +124,7 @@ static func remote_sha(git_exe: String, project_dir: String, branch: String) ->
var text := str(r["output"]).strip_edges() var text := str(r["output"]).strip_edges()
if text.is_empty(): if text.is_empty():
return "" 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. ## 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(): if text2.is_empty():
return {"status": "unreachable", "local": local, "remote": "", return {"status": "unreachable", "local": local, "remote": "",
"error": "Origin nicht erreichbar (offline oder Tunnel weg)."} "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: if local == remote:
return {"status": "up_to_date", "local": local, "remote": remote, "error": ""} return {"status": "up_to_date", "local": local, "remote": remote, "error": ""}
return {"status": "update_available", "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: <sha> → warning", das nie verschwand, obwohl
## der Pull korrekt lief (live belegt 20.10., Klon stand auf origin/main).
## Regeln: nur Zeilen "<sha>\t<ref>" 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). ## Kurzer SHA für Anzeigen (7 Zeichen, wie git log --oneline).
static func short_sha(sha: String) -> String: static func short_sha(sha: String) -> String:
return sha.substr(0, 7) return sha.substr(0, 7)

View file

@ -26,6 +26,7 @@ func _init() -> void:
TEST_DIR_PREFIX + "_" + str(Time.get_ticks_msec())) TEST_DIR_PREFIX + "_" + str(Time.get_ticks_msec()))
DirAccess.make_dir_recursive_absolute(base) DirAccess.make_dir_recursive_absolute(base)
_run_tests() _run_tests()
_test_ls_remote_warnzeile()
_cleanup_dir(base) # best effort — git-Pack-Dateien können read-only sein _cleanup_dir(base) # best effort — git-Pack-Dateien können read-only sein
if failures == 0: if failures == 0:
print("ALL OK: %d checks" % checks) print("ALL OK: %d checks" % checks)
@ -336,3 +337,25 @@ func _run_tests() -> void:
var self_args := EditorUpdater.self_restart_args("/pfad/zum/klon") var self_args := EditorUpdater.self_restart_args("/pfad/zum/klon")
_check(str(self_args[0]) == "--path" and str(self_args[1]) == "/pfad/zum/klon", _check(str(self_args[0]) == "--path" and str(self_args[1]) == "/pfad/zum/klon",
"Selbst-Restart: --path <klon> (startet die Map-Editor-APP, nicht die Godot-Editor-Shell)") "Selbst-Restart: --path <klon> (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: <sha> → warning" hing
## endlos, obwohl der Klon aktuell war. Erwartung: echte "<sha>\t<ref>"-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")