Clap: Allow getting values from environmental args if not passed in via the command line

Created on 28 Oct 2016  路  9Comments  路  Source: clap-rs/clap

Priority should be passed in manually, then env args, then default values.

parsing medium want to have new feature

Most helpful comment

@kbknapp yup, that's what I'm currently doing, it would just be nice if instead of:

App::new("cool")
    .arg(
        Arg::with_name("config")
            .env("COOL_CONFIG"))
    .arg(
        Arg::with_name("out-file")
            .env("COOL_OUT_FILE"))

I could just do:

App::new("cool")
    .map_env_with_prefix("COOL_")
    .arg(Arg::with_name("config"))
    .arg(Arg::with_name("out-file"))

It's not a huge deal, it's mostly a "every now and then I am lazy about
correctly specifying env and then it's annoying" deal.

All 9 comments

Should add a App::env_args(name) which essentially extends the command line args with whatever is inside name. In this scenario name would contain a full set of arg(s) such as --foo bar

Should also add an Arg::env_value(name) where name can be either just a value i.e. bar in --foo bar, or the whole arg, i.e. --foo bar but only for a single argument, whereas App::env_args could theoretically contain --foo bar --baz etc.

Something that I would love to see is supporting the (semi-standard?) technique of having env vars (and config vars) be option/argument names, screaming snake cased and prefixed with the name of the app. To support this it would be nice if there was a App::env_arg_prefix(name) so that you could do (in pseudo-clap):

    App::env_arg_prefix("myapp").Arg("--some").Arg("required")

and be able to run your app like:

MYAPP_SOME=thing MYAPP_REQUIRED=yes myapp

This also maps pretty cleanly to loading things from config files (you could just specify a config_arg_section and have everything work theoretically the same.)

This has already been implemented in v2 via Arg::env and Arg::env_os. Guess I forgot to close this?

Neat!

It would still be nice to have a similar App::fallback_args_from_os(PREFIX) flag that would make it so that every arg that has a long option would also accept PREFIX_${to_screaming_snake_case(long_name)}. It's a really useful paradigm for 12FA, and it's nice to be consistent.

@quodlibetor I like the idea, but for now I'd rather stick with having to declare the args one would like to use with ENV vals. If an application wants to support what you're proposing, it's as simple as adding:

Arg::with_name("some")
    .long("some")
    .env("MYAPP_SOME")

I'm not sure I'm comfortable adding code that goes through ENV vars matching a prefix, converting longs to screaming snake case, doing a match, etc. This is something that could be handled pretty easily in an external crate once v3 is out (due to App::mut_arg).

Automatically reading env vars would be really nice, but guarded by a global switch, like .auto_2fa(true) or something like that.

I'm not necessarily opposed to that feature/setting. But with the upcoming v3 and mut_arg I would like to start pairing back some settings that could be external crates and moving them out of the core clap code, or even creating a clap_extras crate that provides these one off, modification-only of an App or Arg instance and that don't rely on core clap internals to function.

If you'd like to open an issue with those features in mind so I can track it separately, that's fine. However, I can't promise I'll get to it anytime soon as getting v3 out the door is my priority right now.

@kbknapp yup, that's what I'm currently doing, it would just be nice if instead of:

App::new("cool")
    .arg(
        Arg::with_name("config")
            .env("COOL_CONFIG"))
    .arg(
        Arg::with_name("out-file")
            .env("COOL_OUT_FILE"))

I could just do:

App::new("cool")
    .map_env_with_prefix("COOL_")
    .arg(Arg::with_name("config"))
    .arg(Arg::with_name("out-file"))

It's not a huge deal, it's mostly a "every now and then I am lazy about
correctly specifying env and then it's annoying" deal.

I have a use case where env variable is not backed by an argument. I am currently using after_help to outline the available environment variables. It would be great to support env and collect environment variables under ENV section just like SUBCOMMANDS or FLAGS, i.e:

App::new("cool")
  .env("MAGIC_COOKIE", "Does something cool")
Was this page helpful?
0 / 5 - 0 ratings