Dlaczego narzędzia konsolowe potrzebują własnej alternatywy dla OpenAPI i jak działa projekt Usage
Za każdym razem, gdy piszę małe narzędzie konsolowe, ta sama historia się powtarza. Najpierw szkicujesz argumenty i flagi w kodzie. Potem decydujesz się dodać autouzupełnianie dla Basza i zsh, grzebać w zapamiętywaniu składni skryptów powłoki lub szukać generatorów. Następnie musisz sformatować dokumentację w Markdown, zaktualizować strony man i pamiętać o obsłudze zmiennych środowiskowych. Jeśli projekt zostanie przepisany w innym języku lub zyska wrappery Pythona lub Basza, musisz ręcznie zduplikować całą strukturę argumentów.
Deweloper jdx, znany z popularnego menedżera wersji mise, podszedł do tej rutyny systematycznie i stworzył projekt Usage.
Kontrakt zamiast rozrzuconych obejść
Główna idea Usage jest prosta: oprogramowanie konsolowe potrzebuje własnego odpowiednika OpenAPI lub Swaggera. Zamiast wiązać opisy argumentów z konkretną biblioteką w konkretnym języku, Usage oferuje jedną przenośną specyfikację w formacie KDL.
KDL nie został wybrany przypadkowo. Ten język dokumentów jest czystszy i bardziej czytelny niż JSON czy YAML, co czyni go wygodnym do opisywania zagnieżdżonych poleceń, flag, krótkich aliasów i typów danych.
Jednokrotne opisanie interfejsu narzędzia w tym formacie rozwiązuje od razu kilka problemów:
- Generowanie skryptów autouzupełniania dla wszystkich popularnych powłok poleceń.
- Automatyczne tworzenie dokumentacji w Markdown i stron man.
- Parsowanie argumentów ze skryptów w innych językach.
- Szkielet kodu dla różnych bibliotek CLI.
Jak to wygląda w Rust
Jeśli piszesz w Rust, nie musisz w ogóle pisać manifestu KDL ręcznie. Projekt zawiera crate usage-rs, który generuje specyfikację bezpośrednio ze struktury danych za pomocą makr derive.
Oto podstawowy przykład:
[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 готовы к работе
}
Parser runtime nie ciągnie za sobą ciężkich zależności. Jednocześnie możesz wyeksportować gotową specyfikację KDL z tej samej struktury i użyć jej w zewnętrznej infrastrukturze budowania lub pipeline'ach CI/CD.
Różnice w porównaniu z znanym clap
Większość deweloperów Rust jest przyzwyczajona do używania clap. Autor Usage otwarcie przyznaje wpływ tej biblioteki i zachował podobny format wyjściowy dla wiadomości pomocy i raportów błędów, aby przejście było jak najbardziej bezbolesne.
Różnica tkwi w filozofii. clap jest ściśle zorientowany na ekosystem Rust. usage przenosi schemat interfejsu na wyższy poziom, przekształcając go w uniwersalny kontrakt. Możesz wziąć specyfikację i parsować argumenty w skrypcie Basza za pomocą narzędzia CLI usage bez przepisywania logiki walidacji flag.
Firmy takie jak 37signals są już wśród sponsorów projektu. Świadczy to o zainteresowaniu branży standaryzacją interfejsów terminalowych.
Komu projekt jest teraz przydatny
Usage prawdopodobnie nie będzie potrzebny do jednorazowego skryptu z dwudziestoma liniami. Jednak narzędzie idealnie sprawdza się przy tworzeniu złożonych wewnętrznych narzędzi firmowych, klientów CLI API i narzędzi platformowych używanych przez różne zespoły.
Jeśli masz dość ręcznego synchronizowania dokumentacji z flagami i pisania skryptów autouzupełniania dla każdej powłoki, projekt zdecydowanie warto sprawdzić. Dokumentacja i przewodniki migracji są dostępne na oficjalnej stronie usage.jdx.dev.
Powiązane projekty