Warum Konsolenprogramme eine eigene OpenAPI-Alternative brauchen und wie das Usage-Projekt funktioniert
Jedes Mal, wenn ich ein kleines Konsolenprogramm schreibe, wiederholt sich dieselbe Geschichte. Zuerst skizzierst du Argumente und Flags im Code. Dann entscheidest du dich, Autovervollständigung für Bash und Zsh hinzuzufügen, vertiefst dich in die Erinnerung an Shell-Script-Syntax oder suchst nach Generatoren. Als Nächstes musst du die Dokumentation in Markdown formatieren, Man-Pages aktualisieren und daran denken, Umgebungsvariablen zu unterstützen. Wenn das Projekt in einer anderen Sprache neu geschrieben wird oder Python- oder Bash-Wrapper erhält, musst du die gesamte Argumentstruktur manuell duplizieren.
Entwickler jdx, bekannt für den beliebten Version-Manager mise, hat diese Routine systematisch angegangen und das Projekt Usage geschaffen.
Ein Vertrag statt verstreuter Workarounds
Die Kernidee hinter Usage ist einfach: Konsolensoftware braucht ihr eigenes OpenAPI- oder Swagger-Äquivalent. Anstatt Argumentbeschreibungen an eine bestimmte Bibliothek in einer bestimmten Sprache zu binden, bietet Usage eine einzige portable Spezifikation im KDL-Format.
KDL wurde nicht zufällig gewählt. Diese Dokumentensprache ist sauberer und lesbarer als JSON oder YAML, was sie praktisch für die Beschreibung verschachtelter Befehle, Flags, Kurzaliase und Datentypen macht.
Die Beschreibung der Schnittstelle deines Programms in diesem Format einmal zu erstellen, löst mehrere Probleme gleichzeitig:
- Generierung von Autovervollständigungs-Skripten für alle gängigen Befehls-Shells.
- Automatische Zusammenstellung von Dokumentation in Markdown und Man-Pages.
- Parsing von Argumenten aus Skripten in anderen Sprachen.
- Code-Scaffolding für verschiedene CLI-Bibliotheken.
So sieht es in Rust aus
Wenn du in Rust schreibst, musst du das KDL-Manifest überhaupt nicht von Hand schreiben. Das Projekt enthält eine Crate usage-rs, die die Spezifikation direkt aus deiner Datenstruktur mit Derive-Makros generiert.
Hier ist ein einfaches Beispiel:
[dependencies]
usage = { package = "usage-rs", version = "6" }
use usage::Cli;
#[derive(Cli)]
#[usage(bin = "example", version)]
struct App {
/// Print more detail.
#[usage(short = 'v', long, count)]
verbose: u8,
/// Files to process.
files: Vec<String>,
}
fn main() {
let app = App::parse();
// app.verbose и app.files готовы к работе
}
Der Runtime-Parser zieht keine schweren Abhängigkeiten mit sich. Gleichzeitig kannst du eine fertige KDL-Spezifikation aus derselben Struktur exportieren und sie in externer Build-Infrastruktur oder CI/CD-Pipelines verwenden.
Unterschiede zum vertrauten clap
Die meisten Rust-Entwickler sind es gewohnt, clap zu verwenden. Der Autor von Usage erkennt den Einfluss dieser Bibliothek offen an und hat ein ähnliches Ausgabeformat für Hilfemeldungen und Fehlerberichte beibehalten, um den Übergang so schmerzlos wie möglich zu gestalten.
Der Unterschied liegt in der Philosophie. clap ist strikt auf das Rust-Ökosystem ausgerichtet. usage verschiebt das Interface-Schema auf eine höhere Ebene und macht es zu einem universellen Vertrag. Du kannst die Spezifikation nehmen und Argumente in einem Bash-Skript über das CLI-Tool usage parsen, ohne deine Flag-Validierungslogik umzuschreiben.
Unternehmen wie 37signals gehören bereits zu den Sponsoren des Projekts. Dies zeigt das Interesse der Branche an der Standardisierung von Terminal-Schnittstellen.
Wem das Projekt gerade jetzt nützt
Usage wird für ein einmaliges Zwanzig-Zeilen-Skript kaum benötigt. Allerdings fügt sich das Tool perfekt in die Entwicklung komplexer interner Unternehmensprogramme, API-CLI-Clients und Plattform-Tools ein, die von verschiedenen Teams verwendet werden.
Wenn du es leid bist, Dokumentation und Flags manuell zu synchronisieren und Autovervollständigungs-Skripte für jede Shell zu schreiben, lohnt es sich auf jeden Fall, einen Blick auf das Projekt zu werfen. Dokumentation und Migrationsanleitungen sind auf der offiziellen Website usage.jdx.dev verfügbar.
Ähnliche Projekte