Repository: clap-rs/clap
Pull request #1609 (2019-12-20 09:19:49)

fixed: failed of multiple_occurrences with env
The example code.

~~~rust
use clap::{App, Arg};

fn main() {
  let matches = App::new("My Super Program")
    .arg(
      Arg::with_name("verbose")
        .help("Sets the level of verbosity")
        .short('v')
        .long("verbose")
        .takes_value(false)
        .multiple_occurrences(true)
        .env("VERBOSE"),
    )
    .get_matches();

  match matches.occurrences_of("verbose") {
    0 => println!("0 No verbose info"),
    1 => println!("1 Some verbose info"),
    2 => println!("2 Tons of verbose info"),
    3 | _ => println!("3 >= Don't be crazy"),
  }
}
~~~

It code use multiple_occurrences with env.
But it do not work.
`env` method set require take value.

It result see under.

~~~console
% cargo run -- -v
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/foo -v`
error: The argument '--verbose <verbose>...' requires a value but none was supplied

USAGE:
    foo [OPTIONS]

For more information try --help
~~~

And, structopt or clap_derive may be create similar code.
So I am confused by structopt.

This to fix code small.


Patch:
diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs
index e22760d4..8736379f 100644
--- a/src/build/arg/mod.rs
+++ b/src/build/arg/mod.rs
@@ -2646,7 +2646,9 @@ impl<'help> Arg<'help> {
     /// 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: &'help OsStr) -> Self {
-        self.setb(ArgSettings::TakesValue);
+        if !self.is_set(ArgSettings::MultipleOccurrences) {
+            self.setb(ArgSettings::TakesValue);
+        }
 
         self.env = Some((name, env::var_os(name)));
         self


Test patch:
diff --git a/tests/multiple_occurrences.rs b/tests/multiple_occurrences.rs
index f0a6db93..caa74280 100644
--- a/tests/multiple_occurrences.rs
+++ b/tests/multiple_occurrences.rs
@@ -76,3 +76,57 @@ fn multiple_occurrences_of_flags_large_quantity() {
     assert!(m.is_present("multflag"));
     assert_eq!(m.occurrences_of("multflag"), 1024);
 }
+
+#[test]
+fn multiple_occurrences_of_before_env() {
+    let app = App::new("mo_before_env").arg(
+        Arg::with_name("verbose")
+            .env("VERBOSE")
+            .short('v')
+            .long("verbose")
+            .takes_value(false)
+            .multiple_occurrences(true),
+    );
+
+    let m = app.clone().try_get_matches_from(vec![""]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 0);
+
+    let m = app.clone().try_get_matches_from(vec!["", "-v"]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 1);
+
+    let m = app.clone().try_get_matches_from(vec!["", "-vv"]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 2);
+    let m = app.clone().try_get_matches_from(vec!["", "-vvv"]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
+}
+
+#[test]
+fn multiple_occurrences_of_after_env() {
+    let app = App::new("mo_after_env").arg(
+        Arg::with_name("verbose")
+            .short('v')
+            .long("verbose")
+            .takes_value(false)
+            .multiple_occurrences(true)
+            .env("VERBOSE"),
+    );
+
+    let m = app.clone().try_get_matches_from(vec![""]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 0);
+
+    let m = app.clone().try_get_matches_from(vec!["", "-v"]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 1);
+
+    let m = app.clone().try_get_matches_from(vec!["", "-vv"]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 2);
+    let m = app.clone().try_get_matches_from(vec!["", "-vvv"]);
+    assert!(m.is_ok(), "{}", m.unwrap_err().message);
+    assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
+}