-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
api(Arg): add from_env #1057
api(Arg): add from_env #1057
Changes from all commits
f254807
bad5d19
ec46b55
779560b
5fccd1f
1401faa
81cae1f
2fa8f83
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ use std::ffi::{OsString, OsStr}; | |
use osstringext::OsStrExt3; | ||
#[cfg(not(target_os="windows"))] | ||
use std::os::unix::ffi::OsStrExt; | ||
|
||
use std::env; | ||
|
||
#[cfg(feature = "yaml")] | ||
use yaml_rust::Yaml; | ||
|
@@ -128,6 +128,7 @@ impl<'a, 'b> Arg<'a, 'b> { | |
"default_value" => yaml_to_str!(a, v, default_value), | ||
"default_value_if" => yaml_tuple3!(a, v, default_value_if), | ||
"default_value_ifs" => yaml_tuple3!(a, v, default_value_if), | ||
"env" => yaml_to_str!(a, v, env), | ||
"value_names" => yaml_vec_or_str!(v, a, value_name), | ||
"groups" => yaml_vec_or_str!(v, a, group), | ||
"requires" => yaml_vec_or_str!(v, a, requires), | ||
|
@@ -3014,7 +3015,7 @@ impl<'a, 'b> Arg<'a, 'b> { | |
/// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will | ||
/// still return `true`. If you wish to determine whether the argument was used at runtime or | ||
/// not, consider [`ArgMatches::occurrences_of`] which will return `0` if the argument was *not* | ||
/// used at runtmie. | ||
/// used at runtime. | ||
/// | ||
/// **NOTE:** This setting is perfectly compatible with [`Arg::default_value_if`] but slightly | ||
/// different. `Arg::default_value` *only* takes affect when the user has not provided this arg | ||
|
@@ -3311,6 +3312,119 @@ impl<'a, 'b> Arg<'a, 'b> { | |
self | ||
} | ||
|
||
/// Specifies that if the value is not passed in as an argument, that it should be retrieved | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll try and add similar docs to the others. |
||
/// from the environment, if available. If it is not present in the environment, then default | ||
/// rules will apply. | ||
/// | ||
/// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`] | ||
/// will return `0` even though the [`ArgMatches::value_of`] will return the default specified. | ||
/// | ||
/// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will | ||
/// return `true` if the variable is present in the environemnt . If you wish to determine whether | ||
/// the argument was used at runtime or not, consider [`ArgMatches::occurrences_of`] which will | ||
/// return `0` if the argument was *not* used at runtime. | ||
/// | ||
/// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. | ||
/// | ||
/// **NOTE:** If [`Arg::multiple(true)`] is set then [`Arg::use_delimiter(true)`] should also be | ||
/// set. Otherwise, only a single argument will be returned from the environment variable. The | ||
/// default delimiter is `,` and follows all the other delimiter rules. | ||
/// | ||
/// # Examples | ||
/// | ||
/// In this example, we show the variable coming from the environment: | ||
/// | ||
/// ```rust | ||
/// # use std::env; | ||
/// # use clap::{App, Arg}; | ||
/// | ||
/// env::set_var("MY_FLAG", "env"); | ||
/// | ||
/// let m = App::new("prog") | ||
/// .arg(Arg::with_name("flag") | ||
/// .long("flag") | ||
/// .env("MY_FLAG")) | ||
/// .get_matches_from(vec![ | ||
/// "prog" | ||
/// ]); | ||
/// | ||
/// assert_eq!(m.value_of("flag"), Some("env")); | ||
/// ``` | ||
/// | ||
/// In this example, we show the variable coming from an option on the CLI: | ||
/// | ||
/// ```rust | ||
/// # use std::env; | ||
/// # use clap::{App, Arg}; | ||
/// | ||
/// env::set_var("MY_FLAG", "env"); | ||
/// | ||
/// let m = App::new("prog") | ||
/// .arg(Arg::with_name("flag") | ||
/// .long("flag") | ||
/// .env("MY_FLAG")) | ||
/// .get_matches_from(vec![ | ||
/// "prog", "--flag", "opt" | ||
/// ]); | ||
/// | ||
/// assert_eq!(m.value_of("flag"), Some("opt")); | ||
/// ``` | ||
/// | ||
/// In this example, we show the variable coming from the environment even with the | ||
/// presence of a default: | ||
/// | ||
/// ```rust | ||
/// # use std::env; | ||
/// # use clap::{App, Arg}; | ||
/// | ||
/// env::set_var("MY_FLAG", "env"); | ||
/// | ||
/// let m = App::new("prog") | ||
/// .arg(Arg::with_name("flag") | ||
/// .long("flag") | ||
/// .env("MY_FLAG") | ||
/// .default_value("default")) | ||
/// .get_matches_from(vec![ | ||
/// "prog" | ||
/// ]); | ||
/// | ||
/// assert_eq!(m.value_of("flag"), Some("env")); | ||
/// ``` | ||
/// | ||
/// In this example, we show the use of multiple values in a single environment variable: | ||
/// | ||
/// ```rust | ||
/// # use std::env; | ||
/// # use clap::{App, Arg}; | ||
/// | ||
/// env::set_var("MY_FLAG_MULTI", "env1,env2"); | ||
/// | ||
/// let m = App::new("prog") | ||
/// .arg(Arg::with_name("flag") | ||
/// .long("flag") | ||
/// .env("MY_FLAG_MULTI") | ||
/// .multiple(true) | ||
/// .use_delimiter(true)) | ||
/// .get_matches_from(vec![ | ||
/// "prog" | ||
/// ]); | ||
/// | ||
/// assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]); | ||
/// ``` | ||
pub fn env(self, name: &'a str) -> Self { | ||
self.env_os(OsStr::new(name)) | ||
} | ||
|
||
/// Specifies that if the value is not passed in as an argument, that it should be retrieved | ||
/// from the environment if available in the exact same manner as [`Arg::env`] only using | ||
/// [`OsStr`]s instead. | ||
pub fn env_os(mut self, name: &'a OsStr) -> Self { | ||
self.setb(ArgSettings::TakesValue); | ||
|
||
self.v.env = env::var_os(name).map(|value| (name, value)); | ||
self | ||
} | ||
|
||
/// When set to `true` the help string will be displayed on the line after the argument and | ||
/// indented once. This can be helpful for arguments with very long or complex help messages. | ||
/// This can also be helpful for arguments with very long flag names, or many/long value names. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,20 +8,26 @@ use std::mem; | |
|
||
// Internal | ||
use Arg; | ||
use args::{ArgSettings, Base, Switched, AnyArg, DispOrder}; | ||
use args::{AnyArg, ArgSettings, Base, DispOrder, Switched}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let me know if you don't want the default rustfmt changes to be merged in... this is current rustfmt, at least up to a few days ago. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm good with the rustfmt changes. I try to stay using the latest and greatest update so as to stick with community best practices. |
||
use map::{self, VecMap}; | ||
|
||
#[derive(Default, Clone, Debug)] | ||
#[doc(hidden)] | ||
pub struct FlagBuilder<'n, 'e> | ||
where 'n: 'e | ||
where | ||
'n: 'e, | ||
{ | ||
pub b: Base<'n, 'e>, | ||
pub s: Switched<'e>, | ||
} | ||
|
||
impl<'n, 'e> FlagBuilder<'n, 'e> { | ||
pub fn new(name: &'n str) -> Self { FlagBuilder { b: Base::new(name), ..Default::default() } } | ||
pub fn new(name: &'n str) -> Self { | ||
FlagBuilder { | ||
b: Base::new(name), | ||
..Default::default() | ||
} | ||
} | ||
} | ||
|
||
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> { | ||
|
@@ -83,10 +89,12 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> { | |
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { | ||
None | ||
} | ||
fn env<'s>(&'s self) -> Option<(&'n OsStr, &'s OsString)> { None } | ||
fn longest_filter(&self) -> bool { self.s.long.is_some() } | ||
fn aliases(&self) -> Option<Vec<&'e str>> { | ||
if let Some(ref aliases) = self.s.aliases { | ||
let vis_aliases: Vec<_> = aliases.iter() | ||
let vis_aliases: Vec<_> = aliases | ||
.iter() | ||
.filter_map(|&(n, v)| if v { Some(n) } else { None }) | ||
.collect(); | ||
if vis_aliases.is_empty() { | ||
|
@@ -105,9 +113,7 @@ impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> { | |
} | ||
|
||
impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> { | ||
fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { | ||
self.b == other.b | ||
} | ||
fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { self.b == other.b } | ||
} | ||
|
||
#[cfg(test)] | ||
|
@@ -142,8 +148,12 @@ mod test { | |
fn flagbuilder_display_multiple_aliases() { | ||
let mut f = FlagBuilder::new("flg"); | ||
f.s.short = Some('f'); | ||
f.s.aliases = | ||
Some(vec![("alias_not_visible", false), ("f2", true), ("f3", true), ("f4", true)]); | ||
f.s.aliases = Some(vec![ | ||
("alias_not_visible", false), | ||
("f2", true), | ||
("f3", true), | ||
("f4", true), | ||
]); | ||
assert_eq!(&*format!("{}", f), "-f"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up not trying to dedup this with default. I found it was going to be annoying. If it's required for commit, I can, but otherwise I'd prefer to leave as is.