Archiv: Quellen und Arbeitsdateien fertiger Versionen auf ARCHIV_DIR auslagern (z. B. Storage Box)
Nach jedem fertigen Lauf und beim Start nachholend; QUELLEN.md bleibt. Löschen und Zurücksetzen räumen das Archiv mit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
478ce6b412
commit
be19abc065
9 files changed
+109
-2
No files matched your search
@@ -0,0 +1,79 @@
|
||||
"""Quellen und Arbeitsdateien fertiger Versionen ins Archiv verschieben (config.ARCHIV, auf dem Server eine Storage Box).
|
||||
Nichts liest danach noch daraus: neue Versionen recherchieren neu, fertige Läufe setzen nie fort. QUELLEN.md bleibt im Speicher,
|
||||
die Buchansicht zeigt sie. Erst kopieren, dann löschen – ein Abbruch lässt den Speicher vollständig, der nächste Start holt nach."""
|
||||
import asyncio
|
||||
import logging
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from . import config, state
|
||||
|
||||
log = logging.getLogger("buchwerk")
|
||||
ORDNER = ("quellen", "arbeit")
|
||||
BLEIBT = {"QUELLEN.md"}
|
||||
_aufgaben: set[asyncio.Task] = set()
|
||||
|
||||
|
||||
def faellig(key: str) -> bool:
|
||||
"""Fertig und unter quellen/ oder arbeit/ liegt noch etwas."""
|
||||
v = state.verzeichnis(key)
|
||||
return state.zustand(key)["status"] == "fertig" and any(_eintraege(v / u) for u in ORDNER)
|
||||
|
||||
|
||||
def _eintraege(d: Path) -> list[Path]:
|
||||
return [p for p in d.iterdir() if p.name not in BLEIBT] if d.is_dir() else []
|
||||
|
||||
|
||||
def auslagern(key: str) -> None:
|
||||
"""Verschiebt quellen/ (außer QUELLEN.md) und arbeit/ nach ARCHIV/<key>/. Blockiert – im Thread aufrufen."""
|
||||
v = state.verzeichnis(key)
|
||||
for u in ORDNER:
|
||||
for p in _eintraege(v / u):
|
||||
_kopieren(p, config.ARCHIV / key / u / p.name)
|
||||
if p.is_dir() and not p.is_symlink():
|
||||
shutil.rmtree(p)
|
||||
else:
|
||||
p.unlink()
|
||||
|
||||
|
||||
def _kopieren(quelle: Path, ziel: Path) -> None:
|
||||
"""Ohne Rechte, Zeiten und Symlinks: CIFS kennt beides nicht. Links in Klonen entfallen."""
|
||||
if quelle.is_symlink():
|
||||
return
|
||||
if quelle.is_dir():
|
||||
ziel.mkdir(parents=True, exist_ok=True)
|
||||
for k in quelle.iterdir():
|
||||
_kopieren(k, ziel / k.name)
|
||||
elif quelle.is_file():
|
||||
ziel.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(quelle, ziel)
|
||||
|
||||
|
||||
async def _auslagern(key: str) -> None:
|
||||
state.ereignis(key, "archiv", "start", f"Quellen und Arbeitsdateien nach {config.ARCHIV / key}")
|
||||
try:
|
||||
await asyncio.to_thread(auslagern, key)
|
||||
state.ereignis(key, "archiv", "ende", "ausgelagert")
|
||||
except OSError as e:
|
||||
log.exception("Archiv %s", key)
|
||||
state.ereignis(key, "archiv", "fehler", f"{type(e).__name__}: {e}")
|
||||
state.speichern(key)
|
||||
|
||||
|
||||
def anstossen(key: str) -> None:
|
||||
"""Im Hintergrund, der Lauf gilt schon als fertig."""
|
||||
if config.ARCHIV and faellig(key):
|
||||
t = asyncio.create_task(_auslagern(key))
|
||||
_aufgaben.add(t)
|
||||
t.add_done_callback(_aufgaben.discard)
|
||||
|
||||
|
||||
async def nachholen() -> None:
|
||||
"""Beim Start: alle fertigen Versionen mit Restbestand, nacheinander (Bestand und abgebrochene Kopien)."""
|
||||
if not config.ARCHIV:
|
||||
return
|
||||
for t in state.themen():
|
||||
for v in state.versionen(t["name"]):
|
||||
key = f"{t['name']}/v{v}"
|
||||
if faellig(key):
|
||||
await _auslagern(key)
|
||||
Reference in new issue
Block a user