3 个不稳定版本
0.2.1 | 2023年10月19日 |
---|---|
0.2.0 | 2022年10月14日 |
0.1.0 | 2022年10月13日 |
170 在 配置 中
3,088 每月下载量
用于 2 crates
16KB
Clap 和 Serde derive
使用 ClapSerde
过程宏,可以从结构体中派生 clap 和 serde。
然后,该结构体可以从 clap 和 serde 源进行解析,就像分层配置一样:最后一个源具有优先级。
Args::from(serde_parsed)
.merge_clap();
在片段中,优先级是
- 来自 clap 的命令行;
- 来自 serde 的配置文件;
- 默认值。
示例
在这个例子中,我们定义了一个同时从 clap 和 serde 派生的结构体。该结构体具有各种参数类型,并且其字段也有各种属性。
最后,我们使用 serde 从 YAML 文件中解析该结构体,然后使用 clap 从命令行解析。clap 的参数将覆盖 serde 的参数;如果没有源包含该字段,则将使用默认值。
use clap_serde_derive::{
clap::{self, ArgAction},
serde::Serialize,
ClapSerde,
};
#[derive(ClapSerde, Serialize)]
#[derive(Debug)]
#[command(author, version, about)]
pub struct Args {
/// Input files
pub input: Vec<std::path::PathBuf>,
/// String argument
#[arg(short, long)]
name: String,
/// Skip serde deserialize
#[default(13)]
#[serde(skip_deserializing)]
#[arg(long = "num")]
pub clap_num: u32,
/// Skip clap
#[serde(rename = "number")]
#[arg(skip)]
pub serde_num: u32,
/// Recursive fields
#[clap_serde]
#[command(flatten)]
pub suboptions: SubConfig,
}
#[derive(ClapSerde, Serialize)]
#[derive(Debug)]
pub struct SubConfig {
#[default(true)]
#[arg(long = "no-flag", action = ArgAction::SetFalse)]
pub flag: bool,
}
let args = Args::from(serde_yaml::from_str::<<Args as ClapSerde>::Opt>("number: 12").unwrap())
.merge_clap();
assert_eq!(
serde_yaml::to_string(&args).unwrap(),
serde_yaml::to_string(&Args {
serde_num: 12,
clap_num: 13,
..Args::default()
})
.unwrap(),
);
命令行配置路径
您可以通过这种方式轻松地从命令行获取配置文件路径。
use std::{fs::File, io::BufReader};
use clap_serde_derive::{
clap::{self, Parser},
ClapSerde,
};
#[derive(Parser)]
#[command(author, version, about)]
struct Args {
/// Input files
input: Vec<std::path::PathBuf>,
/// Config file
#[arg(short, long = "config", default_value = "config.yml")]
config_path: std::path::PathBuf,
/// Rest of arguments
#[command(flatten)]
pub config: <Config as ClapSerde>::Opt,
}
#[derive(ClapSerde)]
struct Config {
/// String argument
#[arg(short, long)]
name: String,
}
// Parse whole args with clap
let mut args = Args::parse();
// Get config file
let config = if let Ok(f) = File::open(&args.config_path) {
// Parse config with serde
match serde_yaml::from_reader::<_, <Config as ClapSerde>::Opt>(BufReader::new(f)) {
// merge config already parsed from clap
Ok(config) => Config::from(config).merge(&mut args.config),
Err(err) => panic!("Error in configuration file:\n{}", err),
}
} else {
// If there is not config file return only config parsed from clap
Config::from(&mut args.config)
};
依赖项
~2.5MB
~57K SLoC