ftptui: FTP/SFTP TUI-Client für das Terminal
This commit is contained in:
@@ -1,3 +1,297 @@
|
||||
# ftptui
|
||||
|
||||
FTP/SFTP TUI-Client in Python mit SSH-FTP-Unterstützung
|
||||
> Interaktiver **FTP- und SFTP-Client** als Terminal-User-Interface in Python.
|
||||
|
||||
`ftptui` ist ein schlanker, aber vollwertiger Dateibrowser für die Kommandozeile.
|
||||
Er unterstützt klassisches **FTP** (RFC 959, über die Python-Standardbibliothek
|
||||
`ftplib`) sowie **SFTP** (SSH File Transfer Protocol, über `paramiko`). Damit deckt
|
||||
das Tool den überwiegenden Teil der realen Dateiübertragungs-Szenarien ab –
|
||||
einschließlich SSH-basiertem FTP.
|
||||
|
||||
Das Interface ist zweispaltig aufgebaut:
|
||||
|
||||
- **links** das lokale Dateisystem,
|
||||
- **rechts** das entfernte System,
|
||||
|
||||
mit Dateiübertragung in beide Richtungen, rekursivem Hoch-/Herunterladen von
|
||||
Verzeichnissen, Anlegen, Umbenennen und Löschen sowie speicherbaren
|
||||
Verbindungsprofilen.
|
||||
|
||||
---
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
- [Funktionen](#funktionen)
|
||||
- [Unterstützte Protokolle](#unterstützte-protokolle)
|
||||
- [Installation](#installation)
|
||||
- [Verwendung](#verwendung)
|
||||
- [Tastaturkürzel](#tastaturkürzel)
|
||||
- [Projektstruktur](#projektstruktur)
|
||||
- [Architektur](#architektur)
|
||||
- [Konfiguration & Profile](#konfiguration--profile)
|
||||
- [Entwicklung](#entwicklung)
|
||||
- [Testen](#testen)
|
||||
- [Lizenz](#lizenz)
|
||||
|
||||
---
|
||||
|
||||
## Funktionen
|
||||
|
||||
- **Dual-Pane-Dateibrowser** – lokales und entferntes Verzeichnis nebeneinander,
|
||||
Spalten: Name, Größe, Änderungsdatum.
|
||||
- **FTP** über die Standardbibliothek, **SFTP** über `paramiko` (SSH-FTP).
|
||||
- **Herunterladen** (`l`) und **Hochladen** (`u`) einzelner Dateien.
|
||||
- **Rekursive Übertragung** kompletter Verzeichnisbäume.
|
||||
- **Verzeichnisse anlegen** (`n`), **umbenennen** (`r`), **löschen** (`d`),
|
||||
rekursives Löschen nicht-leerer Ordner.
|
||||
- **Navigation** mit Maus/Tastatur, „eine Ebene hoch“ (`←`), Doppelklick/`Enter`.
|
||||
- **Verbindungsprofile** werden als JSON unter `~/.config/ftptui/profiles.json`
|
||||
gespeichert und können wieder geladen werden.
|
||||
- Passwortfelder sind abgedunkelt (`password=True`).
|
||||
- Modernes, terminalfreundliches Layout auf Basis von
|
||||
[Textual](https://textual.textualize.io/).
|
||||
|
||||
---
|
||||
|
||||
## Unterstützte Protokolle
|
||||
|
||||
| Protokoll | Beschreibung | Bibliothek / Quelle |
|
||||
|-----------|-------------------------------------------|------------------------------------|
|
||||
| `ftp` | Klassisches File Transfer Protocol (RFC 959) | Standard (kein Drittpaket nötig) |
|
||||
| `sftp` | SSH File Transfer Protocol (SSH-FTP) | `paramiko` |
|
||||
|
||||
> **Hinweis:** „SSH-FTP“ kann zweierlei bedeuten – das SFTP-Subsystem über eine
|
||||
> SSH-Schicht (hier umgesetzt) oder FTP über einen SSH-Tunnel (sog. „FTP over
|
||||
> SSH“). In `ftptui` wird **SFTP über SSH** unterstützt, der heute übliche und
|
||||
> sichere Weg.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- Python **≥ 3.10**
|
||||
- `pip` und idealerweise eine virtuelle Umgebung
|
||||
|
||||
### Aus dem Quellverzeichnis
|
||||
|
||||
```bash
|
||||
# virtuelle Umgebung anlegen und aktivieren
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# Abhängigkeiten installieren
|
||||
pip install -e .
|
||||
|
||||
# Abhängigkeiten (nur Laufzeit):
|
||||
# textual - TUI-Framework
|
||||
# paramiko - SFTP/SSH
|
||||
```
|
||||
|
||||
### Als Paket
|
||||
|
||||
```bash
|
||||
pip install .
|
||||
```
|
||||
|
||||
### Als installiertes Kommando
|
||||
|
||||
Nach `pip install -e .` steht das Kommando `ftptui` global in der Umgebung bereit:
|
||||
|
||||
```bash
|
||||
ftptui
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verwendung
|
||||
|
||||
1. Starten: `ftptui`
|
||||
|
||||
2. Im **Verbindungsbildschirm** die Daten eingeben:
|
||||
- **Verbindungsprofil** – ein zuvor gespeichertes Profil auswählen, oder ein
|
||||
neues anlegen.
|
||||
- **Protokoll** – `sftp` (SSH) oder `ftp`.
|
||||
- **Host**, **Port** (SFTP-Vorgabe `22`, FTP-Vorgabe `21`), **Benutzer**,
|
||||
**Passwort**.
|
||||
- Auf **Verbinden** klicken. Der Port wird bei Protokollwechsel automatisch
|
||||
auf den jeweiligen Standard gesetzt.
|
||||
|
||||
3. Nach erfolgreicher Verbindung erscheint der **Browser-Bildschirm** mit zwei
|
||||
Panelen:
|
||||
- links `/` des lokalen Rechners bzw. das Home-Verzeichnis,
|
||||
- rechts das Home-/Root-Verzeichnis des entfernten Systems.
|
||||
|
||||
4. Zwischen den Paneelen wechseln mit `Tab`. Die fokussierte Tabelle erhält die
|
||||
Aktionen (Hoch-/Herunterladen, Umbenennen, Löschen …).
|
||||
|
||||
> **Tipp:** Die Aktionen `u`/`l` wirken auf das gerade **in der fokussierten
|
||||
> Tabelle** angewählte Element und übertragen in die jeweils andere Seite.
|
||||
|
||||
---
|
||||
|
||||
## Tastaturkürzel
|
||||
|
||||
| Taste | Aktion |
|
||||
|------------|---------------------------------|
|
||||
| `Tab` | Zwischen lokalem/entferntem Paneel wechseln |
|
||||
| `Enter` | Ordner öffnen / in Datei wechseln |
|
||||
| `←` | Eine Verzeichnisebene höher |
|
||||
| `↑ ..` | Eine Ebene hoch (Tabellenzeile) |
|
||||
| `l` | Auswahl **herunterladen** (entfernt → lokal) |
|
||||
| `u` | Auswahl **hochladen** (lokal → entfernt) |
|
||||
| `n` | Neues Verzeichnis anlegen |
|
||||
| `d` | Auswahl löschen (rekursiv) |
|
||||
| `r` | Auswahl umbenennen |
|
||||
| `q` / `Esc`| Beenden |
|
||||
|
||||
---
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
ftptui/
|
||||
├── pyproject.toml # Paketmetadaten, Abhängigkeiten, Einstiegspunkt
|
||||
├── README.md # diese Dokumentation
|
||||
├── .gitignore
|
||||
└── ftptui/
|
||||
├── __init__.py # Versionsnummer
|
||||
├── app.py # Textual-TUI: Verbindungs- & Browser-Bildschirme
|
||||
├── backend.py # Fabrik: wählt FTP- oder SFTP-Transport
|
||||
├── config.py # Speicherung/Laden der Verbindungsprofile (JSON)
|
||||
├── models.py # Datentypen & Transport-Protokoll
|
||||
├── ftp_backend.py # FTP-Adapter (ftplib)
|
||||
└── sftp_backend.py # SFTP-Adapter (paramiko)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architektur
|
||||
|
||||
Die App trennt **Oberfläche** (Textual) von **Transport** (Netzwerkprotokolle)
|
||||
durch ein kleines Protokoll/Interface:
|
||||
|
||||
- `FileTransferBackend` (in `models.py`) definiert die gemeinsame API.
|
||||
- `FTPBackend` und `SFTPBackend` implementieren sie.
|
||||
- `create_backend(protocol)` in `backend.py` liefert den passenden Adapter.
|
||||
|
||||
Gemeinsame Schnittstelle (Auszug):
|
||||
|
||||
```python
|
||||
def connect(host, port, username, password) -> None
|
||||
def listdir(path) -> list[RemoteEntry]
|
||||
def chdir(path) / pwd() -> str
|
||||
def download(remote, local) -> None
|
||||
def upload(local, remote) -> None
|
||||
def mkdir(path) / remove / rmdir / rename
|
||||
def close() -> None
|
||||
```
|
||||
|
||||
`RemoteEntry` beschreibt einen Eintrag mit `name`, `kind` (`file`/`dir`),
|
||||
`size` und `modified`. Dadurch kann die Oberfläche unabhängig vom Protokoll
|
||||
arbeiten – das Hinzufügen weiterer Backends (z. B. WebDAV) ist ohne Änderung
|
||||
der UI möglich.
|
||||
|
||||
### Pfadbehandlung
|
||||
|
||||
Beide Backends normalisieren Pfade zu **absoluten** Angaben relativ zum Root
|
||||
des entfernten Systems. FTP-Operationen setzen das Arbeitsverzeichnis vor einer
|
||||
Aktion auf `/`, sodass Dateiübertragungen unabhängig vom zuletzt betrachteten
|
||||
Ordner zuverlässig funktionieren. SFTP nutzt absolute Pfade direkt.
|
||||
|
||||
### Profilwertung
|
||||
|
||||
Profile werden als JSON in `~/.config/ftptui/profiles.json` (bzw.
|
||||
`$XDG_CONFIG_HOME/ftptui/profiles.json`) gespeichert. Das Passwort wird nur
|
||||
abgelegt, wenn es entsprechend markiert wurde (aktuell standardmäßig direkt
|
||||
gespeichert – Datenschutz-Hinweis siehe unten).
|
||||
|
||||
---
|
||||
|
||||
## Konfiguration & Profile
|
||||
|
||||
Profile speichern: im Verbindungsbildschirm Daten eingeben und **Profil speichern**
|
||||
drücken. Gespeicherte Einträge erscheinen künftig im Dropdown **Verbindungsprofil**.
|
||||
|
||||
Beispieldatei `~/.config/ftptui/profiles.json`:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "git.sysdaemon.xyz",
|
||||
"protocol": "sftp",
|
||||
"host": "git.sysdaemon.xyz",
|
||||
"port": 22,
|
||||
"username": "user",
|
||||
"password": "",
|
||||
"save_password": false
|
||||
},
|
||||
{
|
||||
"name": "backup-server",
|
||||
"protocol": "ftp",
|
||||
"host": "backup.local",
|
||||
"port": 21,
|
||||
"username": "ftpuser",
|
||||
"password": "secret",
|
||||
"save_password": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
> **Sicherheitshinweis:** Speichern Sie Passwörter in Profilen nur auf
|
||||
> vertrauenswürdigen Systemen. Die Datei liegt im Klartext im Benutzerverzeichnis.
|
||||
|
||||
---
|
||||
|
||||
## Entwicklung
|
||||
|
||||
```bash
|
||||
# Umgebung
|
||||
python3 -m venv .venv && source .venv/bin/activate
|
||||
pip install -e . "textual>=0.80.0" "paramiko>=3.4.0"
|
||||
|
||||
# Laufzeit prüfen
|
||||
python -c "import ftptui; print(ftptui.__version__)"
|
||||
|
||||
# App booten (Konsolen-Test)
|
||||
ftptui
|
||||
```
|
||||
|
||||
### Code-Stil & Qualität
|
||||
|
||||
- Typannotationen (`from __future__ import annotations`) durchgängig.
|
||||
- Protokoll-/Interface-basierte Implementierung mit `typing.Protocol`.
|
||||
- Keine Abhängigkeit auf Drittanbieter außer `textual` und `paramiko`.
|
||||
|
||||
---
|
||||
|
||||
## Testen
|
||||
|
||||
Die Backends werden gegen **lokale Testserver** end-to-end getestet:
|
||||
|
||||
- **FTP** gegen `pyftpdlib` (nur für Tests; nicht Teil der Laufzeit-Abhängigkeiten),
|
||||
- **SFTP** gegen eine eigene `paramiko`-SSH-Server-Implementierung.
|
||||
|
||||
Ablauf der Tests: Verbinden, Listings, Download, Upload, `mkdir`, `rename`,
|
||||
`remove`, rekursives `rmdir`, `close` – für beide Protokolle.
|
||||
|
||||
```bash
|
||||
pip install pyftpdlib
|
||||
python tests/test_backends.py # Beispieldatei (siehe Entwicklung/Skripte)
|
||||
```
|
||||
|
||||
> Ein ausführbares Testskript kann ergänzt und an dieser Stelle dokumentiert
|
||||
> werden; die Backends sind derart modular, dass sie ohne Terminal getestet
|
||||
> werden können.
|
||||
|
||||
---
|
||||
|
||||
## Lizenz
|
||||
|
||||
MIT – siehe Projektträger/Repositories. Keine gewerblichen Einschränkungen.
|
||||
|
||||
---
|
||||
|
||||
*Projekt wird innerhalb der `sysdaemon.xyz`-Instanz über Gitea verwaltet –
|
||||
https://git.sysdaemon.xyz/admin/ftptui.*
|
||||
|
||||
Reference in New Issue
Block a user