Skip to content

Commit 1790a3b

Browse files
committed
feat: add envs function
1 parent fdbbf66 commit 1790a3b

File tree

1 file changed

+172
-0
lines changed
  • clap_builder/src/builder

1 file changed

+172
-0
lines changed

clap_builder/src/builder/arg.rs

+172
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,178 @@ impl Arg {
22112211
pub fn env_os(self, name: impl Into<OsStr>) -> Self {
22122212
self.env(name)
22132213
}
2214+
2215+
/// Read from `names` environment variable when argument is not present.
2216+
///
2217+
/// If it is not present in the environment, then default
2218+
/// rules will apply.
2219+
///
2220+
/// If user sets the argument in the environment:
2221+
/// - When [`Arg::action(ArgAction::Set)`] is not set, the flag is considered raised.
2222+
/// - When [`Arg::action(ArgAction::Set)`] is set,
2223+
/// [`ArgMatches::get_one`][crate::ArgMatches::get_one] will
2224+
/// return value of the environment variable.
2225+
///
2226+
/// If user doesn't set the argument in the environment:
2227+
/// - When [`Arg::action(ArgAction::Set)`] is not set, the flag is considered off.
2228+
/// - When [`Arg::action(ArgAction::Set)`] is set,
2229+
/// [`ArgMatches::get_one`][crate::ArgMatches::get_one] will
2230+
/// return the default specified.
2231+
///
2232+
/// Like with command-line values, this will be split by [`Arg::value_delimiter`].
2233+
///
2234+
/// # Examples
2235+
///
2236+
/// In this example, we show the variable coming from the environment.
2237+
/// Note that because of the first `MY_FLAG` has a value, so the next environment variable is not valid again.
2238+
///
2239+
/// ```rust
2240+
/// # use clap_builder as clap;
2241+
/// # use std::env;
2242+
/// # use clap::{Command, Arg, ArgAction};
2243+
///
2244+
/// env::set_var("MY_FLAG", "one");
2245+
/// env::set_var("MY_SECOND_FLAG", "two");
2246+
///
2247+
/// let m = Command::new("prog")
2248+
/// .arg(Arg::new("flag")
2249+
/// .long("flag")
2250+
/// .envs(["MY_FLAG", "MY_SECOND_FLAG"])
2251+
/// .action(ArgAction::Set))
2252+
/// .get_matches_from(vec![
2253+
/// "prog"
2254+
/// ]);
2255+
///
2256+
/// assert_eq!(m.get_one::<String>("flag").unwrap(), "one");
2257+
/// ```
2258+
///
2259+
/// In this example, because `prog` is a flag that accepts an optional, case-insensitive
2260+
/// boolean literal.
2261+
///
2262+
/// Note that the value parser controls how flags are parsed. In this case we've selected
2263+
/// [`FalseyValueParser`][crate::builder::FalseyValueParser]. A `false` literal is `n`, `no`,
2264+
/// `f`, `false`, `off` or `0`. An absent environment variable will also be considered as
2265+
/// `false`. Anything else will considered as `true`.
2266+
///
2267+
/// ```rust
2268+
/// # use clap_builder as clap;
2269+
/// # use std::env;
2270+
/// # use clap::{Command, Arg, ArgAction};
2271+
/// # use clap::builder::FalseyValueParser;
2272+
///
2273+
/// env::set_var("TRUE_FLAG", "true");
2274+
/// env::set_var("FALSE_FLAG", "0");
2275+
///
2276+
/// let m = Command::new("prog")
2277+
/// .arg(Arg::new("true_flag")
2278+
/// .long("true_flag")
2279+
/// .action(ArgAction::SetTrue)
2280+
/// .value_parser(FalseyValueParser::new())
2281+
/// .envs(["TRUE_FLAG"]))
2282+
/// .arg(Arg::new("false_flag")
2283+
/// .long("false_flag")
2284+
/// .action(ArgAction::SetTrue)
2285+
/// .value_parser(FalseyValueParser::new())
2286+
/// .envs(["FALSE_FLAG"]))
2287+
/// .arg(Arg::new("absent_flag")
2288+
/// .long("absent_flag")
2289+
/// .action(ArgAction::SetTrue)
2290+
/// .value_parser(FalseyValueParser::new())
2291+
/// .envs(["ABSENT_FLAG"]))
2292+
/// .get_matches_from(vec![
2293+
/// "prog"
2294+
/// ]);
2295+
///
2296+
/// assert!(m.get_flag("true_flag"));
2297+
/// assert!(!m.get_flag("false_flag"));
2298+
/// assert!(!m.get_flag("absent_flag"));
2299+
/// ```
2300+
///
2301+
/// In this example, we show the variable coming from an option on the CLI:
2302+
///
2303+
/// ```rust
2304+
/// # use clap_builder as clap;
2305+
/// # use std::env;
2306+
/// # use clap::{Command, Arg, ArgAction};
2307+
///
2308+
/// env::set_var("MY_FLAG", "env");
2309+
///
2310+
/// let m = Command::new("prog")
2311+
/// .arg(Arg::new("flag")
2312+
/// .long("flag")
2313+
/// .envs(["MY_FLAG"])
2314+
/// .action(ArgAction::Set))
2315+
/// .get_matches_from(vec![
2316+
/// "prog", "--flag", "opt"
2317+
/// ]);
2318+
///
2319+
/// assert_eq!(m.get_one::<String>("flag").unwrap(), "opt");
2320+
/// ```
2321+
///
2322+
/// In this example, we show the variable coming from the environment even with the
2323+
/// presence of a default:
2324+
///
2325+
/// ```rust
2326+
/// # use clap_builder as clap;
2327+
/// # use std::env;
2328+
/// # use clap::{Command, Arg, ArgAction};
2329+
///
2330+
/// env::set_var("MY_FLAG", "env");
2331+
///
2332+
/// let m = Command::new("prog")
2333+
/// .arg(Arg::new("flag")
2334+
/// .long("flag")
2335+
/// .envs(["MY_FLAG"])
2336+
/// .action(ArgAction::Set)
2337+
/// .default_value("default"))
2338+
/// .get_matches_from(vec![
2339+
/// "prog"
2340+
/// ]);
2341+
///
2342+
/// assert_eq!(m.get_one::<String>("flag").unwrap(), "env");
2343+
/// ```
2344+
///
2345+
/// In this example, we show the use of multiple values in a single environment variable:
2346+
///
2347+
/// ```rust
2348+
/// # use clap_builder as clap;
2349+
/// # use std::env;
2350+
/// # use clap::{Command, Arg, ArgAction};
2351+
///
2352+
/// env::set_var("MY_FLAG_MULTI", "env1,env2");
2353+
///
2354+
/// let m = Command::new("prog")
2355+
/// .arg(Arg::new("flag")
2356+
/// .long("flag")
2357+
/// .envs(["MY_FLAG_MULTI"])
2358+
/// .action(ArgAction::Set)
2359+
/// .num_args(1..)
2360+
/// .value_delimiter(','))
2361+
/// .get_matches_from(vec![
2362+
/// "prog"
2363+
/// ]);
2364+
///
2365+
/// assert_eq!(m.get_many::<String>("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]);
2366+
/// ```
2367+
/// [`Arg::action(ArgAction::Set)`]: Arg::action()
2368+
/// [`Arg::value_delimiter(',')`]: Arg::value_delimiter()
2369+
#[cfg(feature = "env")]
2370+
#[inline]
2371+
#[must_use]
2372+
pub fn envs(mut self, names: impl IntoIterator<Item = impl Into<OsStr>>) -> Self {
2373+
for name in names {
2374+
if let Some(name) = name.into_resettable().into_option() {
2375+
if let Some(value) = env::var_os(&name) {
2376+
self.env = Some((name, Some(value)));
2377+
break;
2378+
}
2379+
} else {
2380+
self.env = None;
2381+
break;
2382+
}
2383+
}
2384+
self
2385+
}
22142386
}
22152387

22162388
/// # Help

0 commit comments

Comments
 (0)