如何获取参数的 ValueSource?

问题描述 投票:0回答:1

我正在使用 Clap(派生)v4.x 作为 Rust CLI 应用程序。命令行参数、环境变量值和默认值的基础知识正常工作。

接下来,对于每场比赛,我想确定 ValueSource(默认、环境变量、命令行),但我无法弄清楚如何使用派生子命令(即下面代码中的 ContainerCommand)获取此信息。我希望有人能给我一个提示或推动我走向正确的方向。

我需要对应用程序的潜在配置数据进行分层评估:cmdline > envvar > 配置文件 > 默认值。

我的目标是从 toml 文件反序列化配置信息。 将 clap 中的数据复制到 Config 结构中。 对于 Config 结构中任何 None 或来自 Defaults 的项目,我将用从 toml 文件数据中找到的值(如果存在)替换该值。否则,将设置默认值。

我知道有一些优秀的软件包(Figment、Config-rs、Twelf 等)可以实现分层配置处理,但是当我尝试在我们的应用程序中使用它们时,它们中的每一个都带来了独特的挑战/问题。因此,我想使用我所描述的简单解决方案。

这是我用来解决问题的稻草人应用程序:

/// This is the entry point for the application.
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let app = App::parse();
    dbg!(&app);
    
    match &app.command {
        Command::Container(c) => {
             //let matches = ContainerCommand::command().get_matches();
    //         if matches.contains_id("name") {
    //             println!("{:?}", c.name);
    //             match matches.value_source("name").unwrap() {
    //                 ValueSource::DefaultValue => { println!("Is the default value")}
    //                 ValueSource::EnvVariable => { println!("Is the envvar value")}
    //                 ValueSource::CommandLine => { println!("Is the commandline value")}
    //                 _ => { println!("Unknown source for the value...")}
    //             }
    //         }
         }
     }

    Ok(())
}

/// The definition of the command line and its arguments
#[derive(Debug, Parser, Serialize)]
#[command(author, version, about, long_about = None, next_line_help = true, propagate_version = true)]
pub struct App {
    #[command(flatten)]
    global_opts: GlobalOpts,

    #[command(subcommand)]
    command: Command,
}

#[derive(Debug, Args, Serialize)]
struct GlobalOpts {
    /// config_path is the path to a configuration (.toml) file, which defaults to the current directory.
    #[arg(short = 'c', long, global = true, default_value = "config.toml")]
    config_path: std::path::PathBuf,
}

#[derive(Debug, Subcommand, Deserialize, Serialize)]
enum Command {
    #[command(about = "The hash container command determines the base64 binary MD5 hash for each blob in a container.", long_about = None)]
    /// Determines the base64 binary MD5 hash for each blob in a container
    Container(ContainerCommand),
}

/// The definition of the command line and its arguments
#[derive(Parser, Debug, Deserialize, Serialize)]
struct ContainerCommand {
    /// The name of a client
    #[arg(short = 'n', long, env("NAME"), default_value = "kdev")]
    name: Option<String>,
}
rust command-line-interface clap
1个回答
0
投票

您不能使用

parse
,因为它已经完成了所有解析并丢弃了您需要的信息。相反,你必须使用
App::command().get_matches()
:

    let matches = App::command().get_matches_from(["self", "-c", "foo", "container"]);
    if let Some((_subcommand_name, subcommand_matches)) = matches.subcommand() {
        if subcommand_matches.contains_id("name") {
            match subcommand_matches.value_source("name").unwrap() {
                ValueSource::DefaultValue => { println!("Is the default value")}
                ValueSource::EnvVariable => { println!("Is the envvar value")}
                ValueSource::CommandLine => { println!("Is the commandline value")}
                _ => { println!("Unknown source for the value...")}
            }
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.