Erster Stand des öffentlichen Ausschnitts aus dem Vault. Die .gitignore arbeitet als Positivliste: ausgeschlossen ist alles, eingeschlossen nur, was ausdrücklich wieder aufgenommen wird. Notizen, Projekte, Finanzen, das Sitzungsgedächtnis und settings.local.json bleiben damit außen vor. Der Kundenname in AI/Regelwerk/seo.md ist durch eine neutrale Bezeichnung ersetzt; die Regeln selbst sind unverändert. Co-Authored-By: Claude Opus 5 <[email protected]>
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
"""Berichtsausgabe. Läuft auf der Windows-Konsole unter cp1252, nicht unter UTF-8."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .abgleich import (
|
|
ANHAENGEN,
|
|
ANLEGEN,
|
|
ITEM_ENTFERNT,
|
|
KONFLIKT,
|
|
NACH_PLANE,
|
|
NACH_VAULT,
|
|
UNVERAENDERT,
|
|
ZEILE_ENTFERNT,
|
|
Aktion,
|
|
)
|
|
|
|
BESCHRIFTUNG = {
|
|
ANLEGEN: "ANLEGEN ",
|
|
NACH_PLANE: "NACH PLANE ",
|
|
NACH_VAULT: "NACH VAULT ",
|
|
KONFLIKT: "KONFLIKT ",
|
|
ANHAENGEN: "ANHAENGEN ",
|
|
ZEILE_ENTFERNT: "ZEILE WEG ",
|
|
ITEM_ENTFERNT: "ITEM WEG ",
|
|
}
|
|
|
|
|
|
def sichere_ausgabe(strom, text: str) -> None:
|
|
"""Schreibt so, dass eine cp1252-Konsole den Lauf nicht abbricht."""
|
|
kodierung = getattr(strom, "encoding", None) or "utf-8"
|
|
try:
|
|
text.encode(kodierung)
|
|
except (UnicodeEncodeError, LookupError):
|
|
text = text.encode(kodierung, errors="replace").decode(kodierung, errors="replace")
|
|
strom.write(text + "\n")
|
|
|
|
|
|
def schreibe_bericht(strom, projektname: str, aktionen: list[Aktion], anwenden: bool) -> None:
|
|
sichere_ausgabe(strom, "")
|
|
sichere_ausgabe(strom, f"=== {projektname} ===")
|
|
kopf = "ANGEWENDET" if anwenden else "Probelauf - es wurde nichts geschrieben"
|
|
sichere_ausgabe(strom, kopf)
|
|
|
|
zaehler: dict[str, int] = {}
|
|
for aktion in aktionen:
|
|
zaehler[aktion.art] = zaehler.get(aktion.art, 0) + 1
|
|
if aktion.art == UNVERAENDERT:
|
|
continue
|
|
sichere_ausgabe(
|
|
strom,
|
|
f" {BESCHRIFTUNG.get(aktion.art, aktion.art)} "
|
|
f"{aktion.marker or '(neu)'} {_titel(aktion)}",
|
|
)
|
|
if aktion.art == KONFLIKT:
|
|
sichere_ausgabe(strom, f" Vault: [{_haken(aktion.vault.erledigt)}] "
|
|
f"{aktion.vault.text}")
|
|
sichere_ausgabe(strom, f" Plane: [{_haken(aktion.plane.erledigt)}] "
|
|
f"{aktion.plane.titel}")
|
|
sichere_ausgabe(
|
|
strom,
|
|
f" Entscheiden mit --konflikt {aktion.marker}=vault "
|
|
f"oder --konflikt {aktion.marker}=plane",
|
|
)
|
|
|
|
sichere_ausgabe(strom, " ---")
|
|
for art in sorted(zaehler):
|
|
sichere_ausgabe(strom, f" {BESCHRIFTUNG.get(art, art).strip()}: {zaehler[art]}")
|
|
|
|
|
|
def _titel(aktion: Aktion) -> str:
|
|
if aktion.vault is not None:
|
|
return aktion.vault.text
|
|
if aktion.plane is not None:
|
|
return aktion.plane.titel
|
|
return ""
|
|
|
|
|
|
def _haken(erledigt: bool) -> str:
|
|
return "x" if erledigt else " "
|