diff --git a/README.md b/README.md index e993e2e..4fa4247 100644 --- a/README.md +++ b/README.md @@ -373,7 +373,13 @@ Links der Snapshot, rechts der lokale Rechner: | `F7` / `n` | neues Verzeichnis (nur lokal) | | `F6` / `g` | Verzeichnis direkt eingeben | | `F2` / `m` | anderes Dateisystem des Snapshots wählen | -| `F10` / `q` | beenden | +| `F10` / `q` | eine Ebene zurück (Snapshot wird ausgehängt) | + +Der Explorer hat drei Ebenen: **Gastauswahl → Snapshot-Auswahl → Dateien**. Mit +`q` geht es jeweils eine Ebene zurück; beim Verlassen des Dateibrowsers wird der +Snapshot wieder ausgehängt, sodass man gleich den nächsten öffnen kann. Das +rechte Fenster behält dabei sein Verzeichnis — praktisch, wenn man aus mehreren +Snapshots ins selbe Zielverzeichnis sammelt. Kopiert wird immer vom aktiven ins andere Fenster — in den Snapshot hinein geht nichts, er ist schreibgeschützt. Beim Kopieren gibt es einen Fortschrittsbalken, diff --git a/pvesnap/explorer.py b/pvesnap/explorer.py index a04d2bf..cf138a7 100644 --- a/pvesnap/explorer.py +++ b/pvesnap/explorer.py @@ -3,6 +3,10 @@ Zwei Fenster wie im Midnight Commander: links der geoeffnete Snapshot (schreibgeschuetzt), rechts der lokale Rechner. Markieren, F5 - fertig. +Drei Ebenen, aus denen man mit q jeweils eine zurueckkommt: +Gastauswahl -> Snapshot-Auswahl -> Dateibrowser. Beim Verlassen des +Browsers wird der Snapshot wieder ausgehaengt. + pvesnap-explorer Gast und Snapshot auswaehlen pvesnap-explorer 802 Snapshot von VM 802 auswaehlen pvesnap-explorer 802 direkt oeffnen @@ -43,7 +47,7 @@ KEYS = [ ("F3", "Ansehen", "Ansehen"), ("F7", "Neuer Ordner", "Ordner"), ("F2", "Laufwerk", "Laufw."), - ("F10", "Ende", "Ende"), + ("F10", "Zurueck", "Zurueck"), ] COPY_BUFFER = 1024 * 1024 @@ -542,7 +546,7 @@ class Explorer: elif key in (curses.KEY_F10, "q", "Q"): return elif is_escape(key): - if confirm(win, "Explorer beenden?"): + if confirm(win, "Snapshot schliessen und zurueck zur Auswahl?"): return # -- Aktionen --------------------------------------------------------- @@ -719,12 +723,17 @@ class Explorer: "F6 / g Verzeichnis direkt eingeben", "F2 / m anderes Dateisystem des Snapshots waehlen", "r neu einlesen", - "F10 / q beenden", + "F10 / q zurueck zur Snapshot-Auswahl", "", "Der Snapshot ist schreibgeschuetzt eingebunden - es kann nichts", "kaputtgehen. Kopiert wird immer vom aktiven ins andere Fenster.", "Geraetedateien und Sockets werden uebersprungen, symbolische", "Verweise bleiben Verweise.", + "", + "Es gibt drei Ebenen: Gastauswahl -> Snapshot-Auswahl -> Dateien.", + "F10 oder q geht jeweils eine Ebene zurueck; der Snapshot wird", + "dabei wieder ausgehaengt. Das rechte Fenster behaelt sein", + "Verzeichnis, auch wenn man den naechsten Snapshot oeffnet.", ] height, width = win.getmaxyx() win.erase() @@ -755,7 +764,7 @@ def _pick_guest(win, guests): % ("LXC" if g.type == "lxc" else "VM ", g.vmid, truncate(g.name or "-", 24), g.status, g.node)) for g in guests] - return choose(win, "Welcher Gast?", entries) + return choose(win, "Welcher Gast? (Esc beendet)", entries) def _pick_snapshot(win, snapshots): @@ -766,7 +775,7 @@ def _pick_snapshot(win, snapshots): entries.append((snap.name, "%-34s %s %s" % (truncate(snap.name, 34), when, truncate(snap.description.replace("\n", " "), 40)))) - return choose(win, "Welcher Snapshot?", entries) + return choose(win, "Welcher Snapshot? (Esc = zurueck zur Gastauswahl)", entries) def _wait_screen(win, text): @@ -817,41 +826,71 @@ def _main(stdscr, args): message(stdscr, "Keine VMs oder Container gefunden.", error=True) return 1 - if args.vmid: - guest = next((g for g in guests if g.vmid == args.vmid), None) - if guest is None: - message(stdscr, "Gast %d nicht gefunden." % args.vmid, error=True) - return 2 - else: - guest = _pick_guest(stdscr, guests) - if guest is None: - return 0 + # Drei Ebenen, aus denen man jeweils eine zurueckkommt: + # Gastauswahl -> Snapshot-Auswahl -> Dateibrowser + # Der Snapshot wird beim Verlassen des Browsers wieder ausgehaengt, damit + # man gleich den naechsten oeffnen kann. + wanted_vmid, wanted_snapshot = args.vmid, args.snapshot - _wait_screen(stdscr, "Lese Snapshots von %s ..." % guest.label) - snapshots = list_snapshots(proxmox, guest) - if not snapshots: - message(stdscr, "%s hat keine Snapshots." % guest.label, error=True) - return 1 + while True: + if wanted_vmid: + guest = next((g for g in guests if g.vmid == wanted_vmid), None) + wanted_vmid = None + if guest is None: + message(stdscr, "Gast %d nicht gefunden." % args.vmid, error=True) + return 2 + else: + guest = _pick_guest(stdscr, guests) + if guest is None: + return 0 - if args.snapshot: - name = next((s.name for s in snapshots if s.name == args.snapshot), None) - if name is None: - message(stdscr, "Snapshot %r nicht gefunden." % args.snapshot, error=True) - return 2 - else: - name = _pick_snapshot(stdscr, snapshots) - if name is None: - return 0 + while True: + _wait_screen(stdscr, "Lese Snapshots von %s ..." % guest.label) + try: + snapshots = list_snapshots(proxmox, guest) + except ProxmoxError as exc: + message(stdscr, str(exc), error=True) + break - session = Session(proxmox, guest, name) + if wanted_snapshot: + name = next((s.name for s in snapshots if s.name == wanted_snapshot), None) + if name is None: + message(stdscr, "Snapshot %r nicht gefunden." + % wanted_snapshot, error=True) + wanted_snapshot = None + if name is None: + continue + elif not snapshots: + message(stdscr, "%s hat keine Snapshots." % guest.label, error=True) + break + else: + name = _pick_snapshot(stdscr, snapshots) + if name is None: + break # zurueck zur Gastauswahl + + _browse(stdscr, proxmox, guest, name, local) + + # Beim Zurueckkommen kann sich das Inventar geaendert haben. + _wait_screen(stdscr, "Frage Proxmox nach VMs und Containern ...") + try: + guests = proxmox.inventory(refresh=True) + except ProxmoxError as exc: + message(stdscr, str(exc), error=True) + return 3 + + +def _browse(stdscr, proxmox, guest, snapname, local): + """Einen Snapshot einbinden, durchsehen und wieder aushaengen.""" + session = Session(proxmox, guest, snapname) try: - _wait_screen(stdscr, "Binde Snapshot '%s' ein - das kann etwas dauern ..." % name) + _wait_screen(stdscr, + "Binde Snapshot '%s' ein - das kann etwas dauern ..." % snapname) session.open() session.prepare() except (SnapfsError, ProxmoxError) as exc: session.close() _show_notes(stdscr, str(exc).splitlines() + session.notes, "Fehlgeschlagen") - return 3 + return try: _show_notes(stdscr, session.notes) @@ -860,19 +899,21 @@ def _main(stdscr, args): _show_notes(stdscr, ["Es wurde kein Dateisystem eingehaengt."] + session.notes, "Nichts zu zeigen") - return 3 + return + start = entries[0][0] if len(entries) > 1: - start = choose(stdscr, "Welches Dateisystem zuerst?", entries) or start + start = choose(stdscr, "Welches Dateisystem zuerst?", entries) + if start is None: + return # zurueck zur Snapshot-Auswahl left = Pane(path=start, root=start, readonly=True, - title="%s @ %s" % (guest.label, name)) + title="%s @ %s" % (guest.label, snapname)) Explorer(left, local, session=session, - subtitle="%s - Snapshot %s" % (guest.label, name)).run(stdscr) + subtitle="%s - Snapshot %s" % (guest.label, snapname)).run(stdscr) finally: _wait_screen(stdscr, "Haenge Snapshot wieder aus ...") session.close() - return 0 def build_parser():