#serde-derive #cli-config #command-line-arguments #arguments-parser #config-parser #cli

clap-serde-derive

将 clap 和 serde 的结果合并到具有 derive 的结构体中

3 个不稳定版本

0.2.1 2023年10月19日
0.2.0 2022年10月14日
0.1.0 2022年10月13日

170配置

Download history 620/week @ 2024-03-13 529/week @ 2024-03-20 596/week @ 2024-03-27 454/week @ 2024-04-03 623/week @ 2024-04-10 622/week @ 2024-04-17 532/week @ 2024-04-24 404/week @ 2024-05-01 715/week @ 2024-05-08 573/week @ 2024-05-15 394/week @ 2024-05-22 524/week @ 2024-05-29 674/week @ 2024-06-05 758/week @ 2024-06-12 1004/week @ 2024-06-19 490/week @ 2024-06-26

3,088 每月下载量
用于 2 crates

AGPL-3.0-or-later

16KB

Clap 和 Serde derive

Crates.io Crates.io Docs.rs License GitLab pipeline

使用 ClapSerde 过程宏,可以从结构体中派生 clap 和 serde。
然后,该结构体可以从 clap 和 serde 源进行解析,就像分层配置一样:最后一个源具有优先级。

Args::from(serde_parsed)
    .merge_clap();

在片段中,优先级是

  1. 来自 clap 的命令行;
  2. 来自 serde 的配置文件;
  3. 默认值。

示例

在这个例子中,我们定义了一个同时从 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