Есть ли способ получить хлопать, чтобы использовать значения по умолчанию из файла? - PullRequest
1 голос
/ 13 марта 2019

Я программирую CLI, используя clap для анализа моих аргументов. Я хочу указать значения по умолчанию для параметров, но если есть файл конфигурации, файл конфигурации должен победить значения по умолчанию.

Легко расставить приоритеты аргументов командной строки по умолчанию, но мне нужен порядок приоритетов:

  1. аргументы командной строки
  2. файл конфигурации
  3. по умолчанию

Если файл конфигурации не задан параметрами командной строки, его также легко настроить, просто проанализировав файл конфигурации перед запуском parse_args и передав значения из проанализированного файла конфигурации в default_value , Проблема заключается в том, что если вы укажете файл конфигурации в командной строке, вы не сможете изменить значения по умолчанию до окончания анализа.

Единственный способ, которым я могу думать об этом, это не устанавливать default_value, а затем вручную сопоставлять "" в value_of. Проблема в том, что в этом случае хлоп не сможет собрать полезную --help.

Есть ли способ заставить хлопать читать сам файл конфигурации?

1 Ответ

2 голосов
/ 13 марта 2019

Из документации clap по default_value:

ПРИМЕЧАНИЕ. Если пользователь не использует этот аргумент во время выполнения, ArgMatches::is_present все равно вернет true.Если вы хотите определить, использовался ли аргумент во время выполнения или нет, рассмотрите ArgMatches::occurrences_of, который вернет 0, если аргумент не использовался во время выполнения.

https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.default_value

Это может быть использовано для получения поведения, которое вы описали:

extern crate clap;
use clap::{App, Arg};
use std::fs::File;
use std::io::prelude::*;

fn main() {
    let matches = App::new("MyApp")
        .version("0.1.0")
        .about("Example for StackOverflow")
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file"),
        )
        .arg(
            Arg::with_name("example")
                .short("e")
                .long("example")
                .help("Sets an example parameter")
                .default_value("default_value")
                .takes_value(true),
        )
        .get_matches();

    let mut value = String::new();

    if let Some(c) = matches.value_of("config") {
        let file = File::open(c);
        match file {
            Ok(mut f) => {
                // Note: I have a file `config.txt` that has contents `file_value`
                f.read_to_string(&mut value).expect("Error reading value");
            }
            Err(_) => println!("Error reading file"),
        }

        // Note: this lets us override the config file value with the
        // cli argument, if provided
        if matches.occurrences_of("example") > 0 {
            value = matches.value_of("example").unwrap().to_string();
        }
    } else {
        value = matches.value_of("example").unwrap().to_string();
    }

    println!("Value for config: {}", value);
}

// Code above licensed CC0
// https://creativecommons.org/share-your-work/public-domain/cc0/ 

В результате поведение:

./target/debug/example
Value for config: default_value
./target/debug/example --example cli_value
Value for config: cli_value
./target/debug/example --config config.txt
Value for config: file_value
./target/debug/example --example cli_value --config config.txt
Value for config: cli_value
...