5 个版本
0.1.2 | 2024年3月19日 |
---|---|
0.1.1 | 2023年12月1日 |
0.1.0 | 2023年9月5日 |
0.0.1-alpha.1 | 2023年8月27日 |
0.0.0-alpha.2 |
|
179 在 命令行界面 中排名
689 每月下载量
用于 netperf
58KB
988 行(不包括注释)
一个轻量级框架,简化使用 clap.rs 构建 complex 命令行应用程序。
概述
cling
的名字是 CLI-ng(即下一代)和英文单词 "cling" 的双关语。它使功能处理程序能够 cling 到 clap 用户定义的结构体 😉。
在编写使用出色的 clap crate 的命令行应用程序时,开发人员通常会编写样板函数来找出用户执行了哪个命令,收集输入类型,然后运行执行该工作的处理函数。对于多命令应用程序,这会很快变得重复。Cling 旨在简化此工作流程,并允许开发人员声明性地将命令映射到函数。
关键特性
- 通过
#[cling(run = "my_function")]
声明性地将 CLI 命令映射到处理程序 - 将处理程序定义为常规 Rust 单元测试函数
- 在命令树中的任何级别运行处理程序(中间件样式)
- 处理程序函数的参数自动从 clap 输入中提取
- 处理程序可以返回一个
State<T>
值,该值可以由下游处理程序提取 - 处理程序可以是
sync
或async
函数 - 带有颜色的统一 CLI 友好错误处理
Credit: The handler design of cling is largely inspired by the excellent work done in [Axum](https://github.com/tokio-rs/axum).
更多详细信息,请参阅
编译器支持:需要 rustc
1.74+
演示
一个快速而简单的示例,以展示 cling 的实际应用
# Cargo.toml
[package]
name = "cling-example"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.4.1", features = ["derive", "env"] }
cling = { version = "0.1" }
tokio = { version = "1.13.0", features = ["full"] }
我们的 main.rs
可能看起来像这样
use cling::prelude::*;
// -- args --
#[derive(Run, Parser, Debug, Clone)]
#[command(author, version, long_about = None)]
/// A simple multi-command example using cling
struct MyApp {
#[clap(flatten)]
pub opts: CommonOpts,
#[clap(subcommand)]
pub cmd: Command,
}
#[derive(Collect, Parser, Debug, Clone)]
struct CommonOpts {
/// Turn debugging information on
#[arg(short, long, global = true, action = clap::ArgAction::Count)]
pub verbose: u8,
}
// Commands for the app are defined here.
#[derive(Run, Subcommand, Debug, Clone)]
enum Command {
/// Honk the horn!
Honk(HonkOpts),
#[cling(run = "beep")]
/// Beep beep!
Beep,
}
// Options of "honk" command. We define cling(run=...) here to call the
// function when this command is executed.
#[derive(Run, Collect, Parser, Debug, Clone)]
#[cling(run = "honk")]
struct HonkOpts {
/// How many times to honk?
times: u8,
}
// -- Handlers --
// We can access &CommonOpts because it derives [Collect]
fn honk(common_opts: &CommonOpts, HonkOpts { times }: &HonkOpts) {
if common_opts.verbose > 0 {
println!("Honking {} times", times);
}
(0..*times).for_each(|_| {
print!("Honk ");
});
println!("!");
}
// Maybe beeps need to be async!
async fn beep() -> anyhow::Result<()> {
println!("Beep, Beep!");
Ok(())
}
// -- main --
#[tokio::main]
async fn main() -> ClingFinished<MyApp> {
Cling::parse_and_run().await
}
现在,让我们运行它并验证它是否按预期工作
$ simple-multi-command -v honk 5
Honking 5 times
Honk Honk Honk Honk Honk !
概念
可运行对象
可运行对象指的是代表 CLI 命令的 clap 结构体。在 cling 中,任何编码命令树的 struct 或 enum 都必须继承 Run
,这包括程序的最高级 struct(例如上面示例中的 MyApp
)。Run
trait 告诉 cling,这种类型应该附加到一个 处理程序 函数。本质上,继承自 Parser
或 Subcommand
的 struct 将需要继承 Run
。
对于任何继承自 Run
的 struct/enum,可以使用 #[cling(run = ...)]
属性将其与一个 处理程序 关联起来。可以设计多级 clap 程序,其中每个级别都运行处理程序,让我们看看一些例子来了解可能做到什么程度。
单命令,单处理程序
use cling::prelude::*;
#[derive(Run, Collect, Parser, Debug, Clone)]
// standard clap attributes
#[command(author, version, about)]
#[cling(run = "my_only_handler")]
pub struct MyApp {
#[clap(short, long)]
/// User name
pub name: String,
}
fn my_only_handler(app: &MyApp) {
println!("User is {}", app.name);
}
#[tokio::main]
async fn main() -> ClingFinished<MyApp> {
Cling::parse_and_run().await
}
注意:我们在 MyApp
上继承 Collect
和 Clone
,以便将其作为共享引用 app: &MyApp
传递给处理程序 my_only_handler
。如果处理程序不需要访问 &MyApp
,则不需要继承 Collect
。
我们的程序现在将运行 my_only_handler
中的代码
$ sample-1 --name=Steve
User is Steve
具有处理程序的子命令
给定一个类似于这样的命令结构
MyApp [CommonOpts]
- projects
|- create [CreateOpts]
|- list
- whoami
use cling::prelude::*;
#[derive(Run, Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)]
pub struct MyApp {
#[clap(flatten)]
pub common: CommonOpts,
#[command(subcommand)]
pub cmd: Commands,
}
#[derive(Args, Collect, Debug, Clone)]
pub struct CommonOpts {
/// Access token
#[arg(long, global = true)]
pub access_token: Option<String>,
}
#[derive(Run, Subcommand, Debug, Clone)]
pub enum Commands {
/// Manage projects
#[command(subcommand)]
Projects(ProjectCommands),
/// Self identification
#[cling(run = "handlers::whoami")]
WhoAmI,
}
#[derive(Run, Subcommand, Debug, Clone)]
pub enum ProjectCommands {
/// Create new project
Create(CreateOpts),
/// List all projects
#[cling(run = "handlers::list_projects")]
List,
}
#[derive(Run, Args, Collect, Debug, Clone)]
#[cling(run = "handlers::create_project")]
pub struct CreateOpts {
/// Project name
pub name: String,
}
mod handlers {
pub fn whoami() {}
pub fn list_projects() {}
pub fn create_project() {}
}
CommonOpts
程序范围内的选项。任何处理程序都可以选择访问它。ProjectOpts
适用于projects [OPTIONS]
CreateOpts
适用于projects create
命令ListOpts
适用于projects list
命令
为了了解这是如何工作的,考虑 projects list
子命令可以传递的不同选项集
Usage: myapp [COMMON-OPTIONS] projects create <NAME>
在此设计中,我们的可运行对象是:MyApp
、Commands
、ProjectCommands
和 CreateOpts
。
我们可以通过使用#[cling(run = "...")]
属性,将处理器附加到任何Run
类型。这个处理器将在任何子命令处理器(如果有)之前运行。对于实现了Subcommand
的枚举,我们必须在没有任何参数的枚举变体(如ProjectCommands::List
)上附加#[cling(run = "...")]
。然而,对于任何带有参数的枚举变体,参数类型本身Run
。
处理程序
处理器是常规的Rust函数,当运行clap命令时执行。处理器通过使用#[cling(run = "function::path")]
属性附加到实现了Run
的任何类型。
每个具有#[cling(run = ...)]
的类型,将在运行内部可运行的处理器的处理器之前运行其处理器函数。
示例
use cling::prelude::*;
#[derive(Run, Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)]
#[cling(run = "init")]
pub struct MyApp {
#[clap(flatten)]
pub common: CommonOpts,
#[command(subcommand)]
pub cmd: Commands,
}
#[derive(Args, Collect, Debug, Clone)]
pub struct CommonOpts {
/// Access token
#[arg(long, global = true)]
pub access_token: Option<String>,
}
#[derive(Run, Subcommand, Debug, Clone)]
pub enum Commands {
#[cling(run = "run_beep")]
Beep,
/// Self identification
#[cling(run = "run_whoami")]
WhoAmI,
}
fn init() {
println!("init handler!");
}
fn run_whoami() {
println!("I'm groot!");
}
fn run_beep() {
println!("Beep beep!");
}
#[tokio::main]
async fn main() -> ClingFinished<MyApp> {
Cling::parse_and_run().await
}
init
处理器将始终在该结构中的其他任何处理器之前运行。
$ many-handlers beep
init handler!
Beep beep!
功能标志
功能 | 激活 | 效果 |
---|---|---|
派生 |
默认 | 启用#[derive(Run)] 和#[derive(Collect)] |
shlex |
"shlex"功能 | 启用从文本解析,当构建REPL时很有用 |
支持的Rust版本
Cling的最小支持Rust版本是1.74.0
。
许可证
双许可,根据Apache 2.0或MIT。
贡献
除非您明确声明,否则您有意提交以包含在作品中的任何贡献都应双重许可,如上所述,不附加任何额外条款或条件。
依赖项
~2–10MB
~93K SLoC