Repository: kbknapp/clap-rs
Pull request #1122 (2017-12-02 20:12:21)

Hide env vars
cc @softprops

Once this merges I'll put out v2.29.0

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/1122)
<!-- Reviewable:end -->



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 541185da..43a9a897 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+<a name="2.29.0"></a>
+## 2.29.0 (2017-12-02)
+
+
+#### API Additions
+
+* **Arg:**  adds Arg::hide_env_values(bool) which allows one to hide any current env values and display only the key in help messages ([fb41d062](https://github.com/kbknapp/clap-rs/commit/fb41d062eedf37cb4f805c90adca29909bd197d7))
+
+
+
 <a name="2.28.0"></a>
 ## 2.28.0 (2017-11-28)
 
diff --git a/Cargo.toml b/Cargo.toml
index a12f0712..63e9922b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "clap"
-version = "2.28.0"
+version = "2.29.0"
 authors = ["Kevin K. <kbknapp@gmail.com>"]
 exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
 repository = "https://github.com/kbknapp/clap-rs"
diff --git a/README.md b/README.md
index c1e2c064..445f89e9 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,10 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
 
 ## What's New
 
+Here's whats new in 2.29.0:
+
+* **Arg:**  adds Arg::hide_env_values(bool) which allows one to hide any current env values and display only the key in help messages
+
 Here's whats new in 2.28.0:
 
 The minimum required Rust is now 1.20. This was done to start using bitflags 1.0 and having >1.0 deps is a *very good* thing!
@@ -297,7 +301,7 @@ subcommands:
 
 Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml:
 
-Simply change your `clap = "2.28"` to `clap = {version = "2.87", features = ["yaml"]}`.
+Simply change your `clap = "2.29"` to `clap = {version = "2.87", features = ["yaml"]}`.
 
 Finally we create our `main.rs` file just like we would have with the previous two examples:
 
@@ -417,7 +421,7 @@ For full usage, add `clap` as a dependency in your `Cargo.toml` () to use from c
 
 ```toml
 [dependencies]
-clap = "~2.28"
+clap = "~2.29"
 ```
 
 (**note**: If you are concerned with supporting a minimum version of Rust that is *older* than the current stable Rust minus 2 stable releases, it's recommended to use the `~major.minor.patch` style versions in your `Cargo.toml` which will only update the patch version automatically. For more information see the [Compatibility Policy](#compatibility-policy))
@@ -441,7 +445,7 @@ To disable these, add this to your `Cargo.toml`:
 
 ```toml
 [dependencies.clap]
-version = "2.28"
+version = "2.29"
 default-features = false
 ```
 
@@ -449,7 +453,7 @@ You can also selectively enable only the features you'd like to include, by addi
 
 ```toml
 [dependencies.clap]
-version = "2.28"
+version = "2.29"
 default-features = false
 
 # Cherry-pick the features you'd like to use
@@ -497,7 +501,7 @@ In order to keep from being surprised of breaking changes, it is **highly** reco
 
 ```toml
 [dependencies]
-clap = "~2.28"
+clap = "~2.29"
 ```
 
 This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust.
@@ -514,11 +518,11 @@ Right now Cargo's version resolution is pretty naive, it's just a brute-force se
 
 # In one Cargo.toml
 [dependencies]
-clap = "~2.28.0"
+clap = "~2.29.0"
 
 # In another Cargo.toml
 [dependencies]
-clap = "2.28"
+clap = "2.29"
 ```
 
 This is inherently an unresolvable crate graph in Cargo right now. Cargo requires there's only one major version of a crate, and being in the same workspace these two crates must share a version. This is impossible in this location, though, as these version constraints cannot be met.
diff --git a/src/app/help.rs b/src/app/help.rs
index 4eab07cf..fc118a9e 100644
--- a/src/app/help.rs
+++ b/src/app/help.rs
@@ -505,11 +505,17 @@ impl<'a> Help<'a> {
                 env.0,
                 env.1
             );
-            spec_vals.push(format!(
-                " [env: {}={}]",
+            let env_val = if !a.is_set(ArgSettings::HideEnvValues) {
+                format!("={}", env.1.map_or(Cow::Borrowed(""), |val| val.to_string_lossy()))
+            } else {
+                String::new()
+            };
+            let env_info = format!(
+                " [env: {}{}]",
                 env.0.to_string_lossy(),
-                env.1.map_or(Cow::Borrowed(""), |val| val.to_string_lossy())
-            ));
+                env_val
+            );
+            spec_vals.push(env_info);
         }
         if !a.is_set(ArgSettings::HideDefaultValue) {
             if let Some(pv) = a.default_val() {
diff --git a/src/args/arg.rs b/src/args/arg.rs
index d6b92e34..92a5e762 100644
--- a/src/args/arg.rs
+++ b/src/args/arg.rs
@@ -3515,6 +3515,15 @@ impl<'a, 'b> Arg<'a, 'b> {
         self
     }
 
+    /// @TODO @p2 @docs @release: write docs
+    pub fn hide_env_values(self, hide: bool) -> Self { 
+        if hide {
+            self.set(ArgSettings::HideEnvValues)
+        } else {
+            self.unset(ArgSettings::HideEnvValues)
+        }
+    }
+
     /// 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.
diff --git a/src/args/settings.rs b/src/args/settings.rs
index d7d065fb..9de94d69 100644
--- a/src/args/settings.rs
+++ b/src/args/settings.rs
@@ -22,6 +22,7 @@ bitflags! {
         const LAST             = 1 << 14;
         const HIDE_DEFAULT_VAL = 1 << 15;
         const CASE_INSENSITIVE = 1 << 16;
+        const HIDE_ENV_VALS    = 1 << 17;
     }
 }
 
@@ -49,6 +50,7 @@ impl ArgFlags {
         RequireEquals => Flags::REQUIRE_EQUALS,
         Last => Flags::LAST,
         CaseInsensitive => Flags::CASE_INSENSITIVE,
+        HideEnvValues => Flags::HIDE_ENV_VALS,
         HideDefaultValue => Flags::HIDE_DEFAULT_VAL
     }
 }
@@ -96,6 +98,8 @@ pub enum ArgSettings {
     HideDefaultValue,
     /// Makes `Arg::possible_values` case insensitive
     CaseInsensitive,
+    /// Hides ENV values in the help message
+    HideEnvValues,
     #[doc(hidden)] RequiredUnlessAll,
     #[doc(hidden)] ValueDelimiterNotSet,
 }
@@ -121,6 +125,7 @@ impl FromStr for ArgSettings {
             "last" => Ok(ArgSettings::Last),
             "hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue),
             "caseinsensitive" => Ok(ArgSettings::CaseInsensitive),
+            "hideenvvalues" => Ok(ArgSettings::HideEnvValues),
             _ => Err("unknown ArgSetting, cannot convert from str".to_owned()),
         }
     }
@@ -197,6 +202,10 @@ mod test {
             "caseinsensitive".parse::<ArgSettings>().unwrap(),
             ArgSettings::CaseInsensitive
         );
+        assert_eq!(
+            "hideenvvalues".parse::<ArgSettings>().unwrap(),
+            ArgSettings::HideEnvValues
+        );
         assert!("hahahaha".parse::<ArgSettings>().is_err());
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index bf2ec0ef..a55ed80e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -513,7 +513,7 @@
 //! this repository for more information.
 
 #![crate_type = "lib"]
-#![doc(html_root_url = "https://docs.rs/clap/2.28.0")]
+#![doc(html_root_url = "https://docs.rs/clap/2.29.0")]
 #![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
         unused_import_braces, unused_allocation)]
 // Lints we'd like to deny but are currently failing for upstream crates


Test patch:
diff --git a/tests/help.rs b/tests/help.rs
index 7cdca9ce..3b8b0b0b 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -491,6 +491,32 @@ ARGS:
     <arg1>    
             some option";
 
+static HIDE_ENV_VALS: &'static str = "ctest 0.1
+
+USAGE:
+    ctest [OPTIONS]
+
+FLAGS:
+    -h, --help       Prints help information
+    -V, --version    Prints version information
+
+OPTIONS:
+    -c, --cafe <FILE>    A coffeehouse, coffee shop, or café. [env: ENVVAR]
+    -p, --pos <VAL>      Some vals [values: fast, slow]";
+
+static SHOW_ENV_VALS: &'static str = "ctest 0.1
+
+USAGE:
+    ctest [OPTIONS]
+
+FLAGS:
+    -h, --help       Prints help information
+    -V, --version    Prints version information
+
+OPTIONS:
+    -c, --cafe <FILE>    A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL]
+    -p, --pos <VAL>      Some vals [values: fast, slow]";
+
 fn setup() -> App<'static, 'static> {
     App::new("test")
         .author("Kevin K.")
@@ -1082,3 +1108,53 @@ fn issue_1052_require_delim_help() {
 
     assert!(test::compare_output(app, "test --help", REQUIRE_DELIM_HELP, false));
 }
+
+#[test]
+fn hide_env_vals() {
+    use std::env;
+
+    env::set_var("ENVVAR", "MYVAL");
+    let app = App::new("ctest")
+        .version("0.1")
+        .arg(Arg::with_name("pos")
+            .short("p")
+            .long("pos")
+            .value_name("VAL")
+            .possible_values(&["fast", "slow"])
+            .help("Some vals")
+            .takes_value(true))
+        .arg(Arg::with_name("cafe")
+            .short("c")
+            .long("cafe")
+            .value_name("FILE")
+            .hide_env_values(true)
+            .env("ENVVAR")
+            .help("A coffeehouse, coffee shop, or café.")
+            .takes_value(true));
+    assert!(test::compare_output(app, "ctest --help", HIDE_ENV_VALS, false));
+}
+
+#[test]
+fn show_env_vals() {
+    use std::env;
+
+    env::set_var("ENVVAR", "MYVAL");
+    let app = App::new("ctest")
+        .version("0.1")
+        .arg(Arg::with_name("pos")
+            .short("p")
+            .long("pos")
+            .value_name("VAL")
+            .possible_values(&["fast", "slow"])
+            .help("Some vals")
+            .takes_value(true))
+        .arg(Arg::with_name("cafe")
+            .short("c")
+            .long("cafe")
+            .value_name("FILE")
+            .hide_possible_values(true)
+            .env("ENVVAR")
+            .help("A coffeehouse, coffee shop, or café.")
+            .takes_value(true));
+    assert!(test::compare_output(app, "ctest --help", SHOW_ENV_VALS, false));
+}
\ No newline at end of file