command-line-api
command-line-api copied to clipboard
Provide flag on Option to hide default value if present
I created an Option<string>
for a --password
option. I am defaulting the option to Environment.GetVariableName("MY_PASSWORD_ENV")
. I don't want this environment variable to appear in plain text in the option description, but it currently does. I cannot find a way to stop this behavior.
Option<string> option = new("password");
option.SetDefaultValue(Environment.GetEnvironmentVariable(PasswordEnvironmentVariable));
AddOption(option);
Options:
password [default: password123] <-- Provide an option to hide this rendering
Perhaps something like Option.IsSecure
?
Another suggestion, although more work, is to incorporate the process of defaulting to environment variables into the library itself. This is a common enough need that it might be worth it.
It might also be nice to support cascading default values. This would support cases where a value should come from an environment variable, if present, but then fall back to a constant value if all else fails. Think options like database port:
Option value from CLI -> environment variable -> 5432
While i can't help with hiding the default value in the help output, the last part about cascading default values could be achieved by using one of the Option<T> constructor overloads featuring a Func<T> getDefaultValue
parameter or the Option.SetDefaultValueFactory
method, kinda like:
Option<string> option = new(
"password",
() => Environment.GetEnvironmentVariable("EnvVarName") ?? "abc"
);
or
Option<string> option = new("password");
option.SetDefaultValueFactory(() => Environment.GetEnvironmentVariable("EnvVarName") ?? "abc");
(I doubt it would be easy to generalize cascading default values. Some (incl. you) like to employ environment vars, others might like to use master config files instead of env vars, some others might prefer CLI -> env var -> config file -> hard-coded value, and some others might prefer some other combinations of whatever other default value providers...)
(P.S.: Off-topic side note: Suggesting the property name "IsSecure" for hiding the password value makes the impression to me (perhaps wrongly?) that you believe hiding the default password value in the help output is conducive to some sense of security. However, i would argue that anyone who is capable enough to use the command line -- which is obviously a requirement for using any form of CLI, can simply type set
, printenv
, or some such depending on the OS and shell in use, and still see the default password in all its plain-text glory ;-) )
Good point on the naming. I honestly don't care what they name it, but I do need the feature. Since defaults are resolved before help is displayed, there doesn't seem to be a way to stop it from exposing my environment variables. Imagine I'm sharing something on Zoom in a meeting: I wouldn't want it exposing some sensitive credential to everyone.
Another suggestion, although more work, is to incorporate the process of defaulting to environment variables into the library itself. This is a common enough need that it might be worth it.
This has been proposed and it's something we'd like to support. See #1191.
We've been making a number of changes to make help easier to customize. One approach that can work here is the following. Caveats afterward.
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Help;
using System.CommandLine.Parsing;
var passwordOption = new Option<string>("--password", description: "Default description", getDefaultValue: () => "S00p3r S33kr!t");
var root = new RootCommand
{
passwordOption
};
var parser = new CommandLineBuilder(root)
.UseDefaults()
.UseHelpBuilder(bindingContext =>
{
var hb = new HelpBuilder(bindingContext.Console);
hb.Customize(passwordOption, "--password", "From environment variable XYZ");
return hb;
})
.Build();
parser.Invoke("-h");
This produces the following output:
MyApp
Usage:
MyApp [options]
Options:
--password Default description [default: From environment variable XYZ]
--version Show version information
-?, -h, --help Show help and usage information
So this API is nigh impossible to discover and taking on creating the HelpBuilder
to get at this API is too complicated even once you know you can do this. A better customization API will go a long way toward letting people address a lot of these issues: https://github.com/dotnet/command-line-api/issues?q=is%3Aopen+is%3Aissue+label%3AArea-Help. We actually started work on System.CommandLine.Rendering in part because a templating engine seemed more suited than an API to the wide variety of help layouts people want. Our more pragmatic goal is:
- Enable the API to handle 80% of cases, and
- Allow a simple way to bring your own templating API.
Suggestions for improvements are more than welcome.
Hi there,
I have a similar problem. My point is that I want to provide an option which should stay null
when not explicitly set, and also display a hint about what is the default value if none is provided in the command-line.
I suppose it's a "standard" behavior:
- if a value is provided in the command-line, use it
- if not, check an environment variable
- if not, use a default const value
I don't know how the help/api could address that. I suppose that for such a case, as you suggested, the default value text in the help screen should be decorrelated from the () => null
default value.
Hi everyone,
just want to add that we are also in the same boat and would like to hide default values from the --help
output.
We have a password option and also a lot of options that are simply null
or an empty string. Most feedback we got is that the output of [Default: ]
is not helpful or is even irritating to the user.
You can override the default help output using the APIs described here: https://docs.microsoft.com/en-us/dotnet/standard/commandline/customize-help#customize-help-for-a-single-option-or-argument.
Take a look at specifying a different secondColumnText
and let us know whether this works for you.