I have a command-line program where some arguments are needed for the program to run, but can be read from environment variables if not explicitly set on the command line. At the moment, I'm using clap directly and writing:
let host = matches
.value_of("host")
.map(String::from)
.or_else(|| env::var("HOST").ok())
.expect("A hostname is required.");
What I'd prefer to write is:
#[derive(StructOpt)]
struct Arguments {
#[structopt(short, long, or_else="host_from_env")]
pub host: String;
}
fn host_from_env() -> Option<String> {
env::var("HOST").ok()
}
The or_else would be a path of an in-scope function, and would be invoked if the value was not present in the clap arguments. If the or_else function returned None, the value would not be set and the arguments would be displayed as normal.
This approach would allow fallbacks besides just environment variables.
Why not make the field optional and handle this outside structopt?
Mostly for brevity/code clarity. The program requires that it have a hostname, it just allows for ways to provide it besides the command line. The second block of code above communicates that clearly, lets my fallback logic be clean and independent of the command-line parsing, and avoids needing to duplicate field names across two structs to support the "parsed-before-fallback" and "required-after-fallback" cases.
Note that env = "FOO" is working.
Does something like raw(default_value = "host_from_env()") fix your need?
Maybe the env = "FOO" possibility could be mentioned on https://docs.rs/structopt/0.2.14/structopt/ ? Is there a list of all arguments to #[structopt(...)] somewhere in the docs?
I can't list everything, any clap method can be used.
@TeXitoi I was pleasantly surprised to find that env worked exactly how I needed it to, down to handling types that implement FromStr but aren't strings themselves. I agree with @kaj that documenting this in structopt would be useful, possibly with an example?
I will accept a PR adding an example (adding a file in the examples folder) using the env feature (in conjonction of default_value). Feel free to submit, or I'll do it when I have the time and motivation.
@TeXitoi I took a stab at it in https://github.com/TeXitoi/structopt/pull/221.
Feedback is most welcome!
Thanks for this amazing crate, btw!
Most helpful comment
Maybe the
env = "FOO"possibility could be mentioned on https://docs.rs/structopt/0.2.14/structopt/ ? Is there a list of all arguments to#[structopt(...)]somewhere in the docs?