Handbuch auf MkDocs-Basis, mit Bildschirmfotos aus dem Programm
26 Kapitel in vier Teilen, in der Reihenfolge, in der man sie braucht: erst sichern, dann Dateien holen, dann ganze Maschinen wiederherstellen, dahinter der Nachschlagteil. Gebaut wird mit MkDocs + Material. Bewusst ohne Netzabhaengigkeiten: keine Schriften vom CDN (font: false), Volltextsuche mit deutschem Stemming liegt neben den Seiten. Im Notfall steht vielleicht das halbe Netz - dann nuetzt eine Doku im Internet nichts. handbuch/bauen.sh baut handbuch/site/ handbuch/bauen.sh ansehen Vorschau auf 127.0.0.1:8000 install.sh nimmt das gebaute Handbuch mit nach /usr/share/doc/pvesnap/handbuch/ - falls es vorliegt. Auf dem Host selbst wird nichts gebaut, mkdocs gehoert nicht auf einen Hypervisor. Die 28 Bildschirmfotos sind nicht abfotografiert, sondern erzeugt: Der echte Programmcode laeuft in einem Pseudo-Terminal gegen einen erfundenen Proxmox-Host (Attrappen fuer pvesh, perl und rbd), pyte baut den Bildschirm nach, heraus faellt ein SVG. Damit stimmen sie garantiert mit dem Programm ueberein, sind reproduzierbar und enthalten keine echten Daten. Die Werkstatt dafuer liegt unter handbuch/werkstatt/ samt LIESMICH.md. Nebenbei: die Schlussmeldung von install.sh warb noch mit --exchange, das mit dem eingebauten Austauschlaufwerk weggefallen ist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c484596702
commit
59e7224297
Executable
+145
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Alle Bildschirmfotos fuers Handbuch aufnehmen.
|
||||
|
||||
./scenes.py alle
|
||||
./scenes.py explorer nur die, deren Name das enthaelt
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
|
||||
from probe import TASTEN, VENV, befehl, umgebung # noqa: E402
|
||||
from shot import Terminal # noqa: E402
|
||||
|
||||
ZIEL = os.path.join(os.path.dirname(HERE), "docs", "bilder")
|
||||
|
||||
BREIT, HOCH = 118, 32
|
||||
|
||||
# (Dateiname, Szene, Tasten, Fenstertitel)
|
||||
AUFNAHMEN = [
|
||||
# -- Sicherung einrichten: der Konfigurationseditor --------------------
|
||||
("config-gruppen", "config", [],
|
||||
"root@pve1 — pvesnap config"),
|
||||
("config-gruppe", "config", ["ab", "enter"],
|
||||
"root@pve1 — pvesnap config → Gruppe taeglich"),
|
||||
("config-vms", "config", ["ab", "enter", "v"],
|
||||
"root@pve1 — pvesnap config → VMs waehlen"),
|
||||
("config-global", "config", ["g"],
|
||||
"root@pve1 — pvesnap config → Globales"),
|
||||
("config-uebersicht", "config", ["v"],
|
||||
"root@pve1 — pvesnap config → Uebersicht"),
|
||||
|
||||
# -- Dateien holen: der Explorer ---------------------------------------
|
||||
("explorer-gastauswahl", "gastauswahl", [],
|
||||
"root@pve1 — pvesnap-explorer"),
|
||||
("explorer-snapshotauswahl", "snapshotauswahl", [],
|
||||
"root@pve1 — pvesnap-explorer"),
|
||||
("explorer-fenster", "explorer", ["ab", "ab", "ab", "enter", "ab", "enter"],
|
||||
"root@pve1 — pvesnap-explorer 101"),
|
||||
("explorer-markiert", "explorer",
|
||||
["ab", "ab", "ab", "enter", "ab", "enter", "ab", "space", "space"],
|
||||
"root@pve1 — pvesnap-explorer 101"),
|
||||
("explorer-kopieren", "explorer",
|
||||
["ab", "ab", "ab", "enter", "ab", "enter", "ab", "space", "f5"],
|
||||
"root@pve1 — pvesnap-explorer 101"),
|
||||
("explorer-ansehen", "explorer",
|
||||
["enter", "ab", "ab", "ab", "ab", "f3"],
|
||||
"root@pve1 — pvesnap-explorer 101"),
|
||||
("explorer-hilfe", "explorer", ["?"],
|
||||
"root@pve1 — pvesnap-explorer 101"),
|
||||
|
||||
# -- Wiederherstellen ---------------------------------------------------
|
||||
("recovery-uebersicht", "recovery", [],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
("recovery-optionen", "neu", [],
|
||||
"root@pve1 — pvesnap-recovery → einrichten"),
|
||||
("recovery-betriebsart", "neu", ["enter"],
|
||||
"root@pve1 — pvesnap-recovery → einrichten"),
|
||||
("recovery-vorhaben", "vorhaben", [],
|
||||
"root@pve1 — pvesnap-recovery → einrichten"),
|
||||
("recovery-detail", "recovery", ["enter"],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
("recovery-loesen", "recovery", ["enter", "f"],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
("recovery-spice", "recovery", ["enter", "p"],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
("recovery-usb", "recovery", ["enter", "p", "enter"],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
("recovery-neustart", "recovery",
|
||||
["enter", "p", "enter", "ab", "ab", "enter"],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
("recovery-neustartwahl", "recovery",
|
||||
["enter", "p", "enter", "ab", "ab", "enter", "j"],
|
||||
"root@pve1 — pvesnap-recovery", 4.0),
|
||||
("recovery-verwerfen", "recovery", ["x"],
|
||||
"root@pve1 — pvesnap-recovery"),
|
||||
|
||||
# -- Austauschlaufwerke -------------------------------------------------
|
||||
("transfer-uebersicht", "transfer", [],
|
||||
"root@pve1 — pvesnap-recovery → Laufwerke"),
|
||||
("transfer-neu", "transfer", ["n"],
|
||||
"root@pve1 — pvesnap-recovery → Laufwerke"),
|
||||
("transfer-commander", "explorer-transfer", [],
|
||||
"root@pve1 — pvesnap-recovery → dumps"),
|
||||
("transfer-auswahl", "laufwerkswahl", [],
|
||||
"root@pve1 — pvesnap-recovery → einrichten"),
|
||||
|
||||
# -- Schutzmodul am SPICE-Anschluss -------------------------------------
|
||||
("dongle-vorhaben", "vorhaben-dongle", [],
|
||||
"root@pve2 — pvesnap-recovery → einrichten"),
|
||||
]
|
||||
|
||||
|
||||
def aufnehmen(name, szene, tasten, titel, nachlauf=0.3):
|
||||
"""`nachlauf` fuer Bildschirme, hinter denen noch etwas arbeitet: der
|
||||
Nachbau haelt sonst den letzten Stand fest, waehrend im Hintergrund noch
|
||||
ein Proxmox-Task laeuft und danach der naechste Dialog aufgeht."""
|
||||
env = umgebung()
|
||||
env["DOKU"] = HERE
|
||||
env["PY"] = VENV
|
||||
term = Terminal(befehl(szene), cols=BREIT, rows=HOCH, env=env, cwd=HERE)
|
||||
try:
|
||||
time.sleep(1.3)
|
||||
term.settle()
|
||||
term.send([TASTEN.get(t, t) for t in tasten], pause=0.3)
|
||||
time.sleep(nachlauf)
|
||||
term.settle()
|
||||
svg = term.to_svg(titel)
|
||||
text = "\n".join(l.rstrip() for l in term.screen.display)
|
||||
finally:
|
||||
term.close()
|
||||
|
||||
os.makedirs(ZIEL, exist_ok=True)
|
||||
with open(os.path.join(ZIEL, name + ".svg"), "w", encoding="utf-8") as handle:
|
||||
handle.write(svg)
|
||||
return text
|
||||
|
||||
|
||||
def main():
|
||||
filter_ = sys.argv[1] if len(sys.argv) > 1 else ""
|
||||
fehler = []
|
||||
for eintrag in AUFNAHMEN:
|
||||
name = eintrag[0]
|
||||
if filter_ and filter_ not in name:
|
||||
continue
|
||||
text = aufnehmen(*eintrag)
|
||||
leer = not text.strip()
|
||||
panne = "Traceback" in text
|
||||
kennzeichen = "LEER" if leer else ("ABSTURZ" if panne else "ok")
|
||||
print("%-28s %s" % (name, kennzeichen))
|
||||
if leer or panne:
|
||||
fehler.append(name)
|
||||
print("\n".join(" " + l for l in text.splitlines() if l.strip())[:1500])
|
||||
if fehler:
|
||||
print("\nNachsehen: %s" % ", ".join(fehler))
|
||||
return 1 if fehler else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user