コンソールユーティリティに独自のOpenAPI代替手段が必要な理由と、Usageプロジェクトの仕組み
小さなコンソールユーティリティを書くたびに、同じ物語が繰り返されます。まずコードの中で引数やフラグをスケッチし、次にbashとzshの自動補完を追加することを決めて、シェルスクリプトの構文を思い出したりジェネレーターを検索したりします。その後、Markdownでドキュメントをフォーマットし、マンページを更新し、環境変数への対応を忘れたらいけません。プロジェクトが別の言語で書き直されるか、PythonやBashのラッパーが追加された場合、引数構造全体を手動で複製する必要があります。
人気のバージョンマネージャーmiseで知られる開発者jdxは、このルーティンに体系的に取り組み、Usageプロジェクトを作成しました。
バラバラなワークアラウンドではなく契約として
Usageのコアアイデアはシンプルです:コンソールソフトウェアには独自のOpenAPIまたはSwagger同等物が必要です。特定の言語の特定のライブラリに引数の説明を結びつけるのではなく、UsageはKDL形式の単一ポータブル仕様を提供します。
KDLはランダムに選択されたわけではありません。このドキュメント言語はJSONやYAMLよりもクリーンで読みやすく、ネストされたコマンド、フラグ、短縮エイリアス、データ型を記述するのに便利です。
この形式でユーティリティのインターフェースを一度記述すれば、同時にいくつかの問題が解決されます:
- すべての人気コマンドシェル用の自動補完スクリプトの生成。
- Markdownとマンページでのドキュメントの自動作成。
- 他の言語のスクリプトからの引数の解析。
- 異なるCLIライブラリ用のコードスキャフォールド。
Rustでの外観
Rustで書いている場合、KDLマニフェストを手で書く必要はありません。プロジェクトには、deriveマクロを使用してデータ構造から直接仕様を生成するクレートが含まれています。
基本的な例を示します:
[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 готовы к работе
}
ランタイムパーサーは重い依存関係を引っ張ってこないません。同時に、同じ構造から готовый KDL仕様をエクスポートし、外部ビルドインフラストラクチャやCI/CDパイプラインで使用できます。
おなじみのclapとの違い
ほとんどのRust開発者はclapの使用に慣れています。Usageの作者はこのライブラリの影響を公に認め、移行をできるだけ痛みなくするために、ヘルプメッセージとエラーレポートの同様の出力形式を保持しました。
違いは哲学にあります。clapはRustエコシステムに厳密に向けられています。Usageはインターフェーススキーマを上位レベルに移動し、普遍的な契約に変換します。仕様を取り、CLIユーティリティであるjqsを通じてBashスクリプトで引数を解析でき、フラグ検証ロジックを書き直す必要はありません。
37signalsのような企業がプロジェクトのスポンサーに名を連ねています。これはターミナルインターフェースを標準化することへの業界の関心を示しています。
誰が今すぐプロジェクトを役立つか
Usageは、1回限りの20行のスクリプトには必要ないでしょう。しかし、このツールは複雑な社内ユーティリティ、API CLIクライアント、不同のチームが使用プラットフォームツールの開発に完璧に適合します。
ドキュメントとフラグの手動同期に、各シェル用の自動補完スクリプトを書くのに疲れているなら、プロジェクトは確かに見る価値があります。ドキュメントと移行ガイドは公式サイトで確認できます。
関連プロジェクト