Open nreid260 opened 2 months ago
Hi @nreid260 , have you had a chance to read the section on Fallback values (and how they are different from Default values) in the picocli user manual? Hopefully that @fallbackValue
annotation is what you are looking for.
If this doesn't meet your requirements, please take a look at the section on Custom Parameter Processing. There's an example use case in the "IParameterPreprocessor
Parser Plugin" section that has some similarity to what you are describing, so you may be able to accomplish your use case with that approach.
I looked into both of these features and neither of them really capture my intent. Both of them could theoretically achieve the result, but they would be sort of clumbsy.
For fallback values, a string that parses into the desired default is needed. This isn't always possible (e.g. empty list of strings). Moreover, it's repetative, because the fallback value and default value are going to be very similar.
An IParameterPreprocessor could be written that does what I want, but it would need to be installed on every option/param separately. There's no way I can see to configure the entire command to use the same preprocessor. Also, though this isn't important for me, it might conflict with options that need some other preprocessor, besides handling empty-string.
Another case has come to mind: options that can be specified multiple times, with last-one-wins semantics. I'm not sure what the right behaviour would be for --foo=x --foo=
x
with the default value--foo=
completely, so that x
is usedAnother case has come to mind: options that can be specified multiple times, with last-one-wins semantics. I'm not sure what the right behaviour would be for
--foo=x --foo=
- Override
x
with the default value- Ignore
--foo=
completely, so thatx
is used
This can be controlled with CommandLine::setOverwrittenOptionsAllowed
(see https://picocli.info/#_overwriting_single_options ).
And in case 1: "Override x
" it will be the fallbackValue
that is used, not the default value.
I can see how the current situation is not ideal.
Getting it to work is possible but not very elegant. I arrived at something like this:
public class Issue2338 {
enum MyEnum { A, B, C}
MyEnum myEnum;
@CommandLine.Option(names = "--my_enum", defaultValue = "A", fallbackValue = "B", arity = "0..1")
void setMyEnum(String value) {
myEnum = MyEnum.valueOf(value.isEmpty() ? "B" : value);
}
public static void main(String[] args) {
Issue2338 case1 = CommandLine.populateCommand(new Issue2338());
Issue2338 case2 = CommandLine.populateCommand(new Issue2338(), "--my_enum");
Issue2338 case3 = CommandLine.populateCommand(new Issue2338(), "--my_enum=");
Issue2338 case4 = CommandLine.populateCommand(new Issue2338(), "--my_enum=C");
System.out.printf("Option not specified; myEnum=%s%n", case1.myEnum);
System.out.printf("Option specified without value; myEnum=%s%n", case2.myEnum);
System.out.printf("Option specified as empty string; myEnum=%s%n", case3.myEnum);
System.out.printf("Option specified with value; myEnum=%s%n", case4.myEnum);
}
}
This prints:
Option not specified; myEnum=A
Option specified without value; myEnum=B
Option specified as empty string; myEnum=B
Option specified with value; myEnum=C
So, it is doable, but I can see it would be nice to have a more elegant solution. My time to work on picocli is extremely limited though, and I don't see myself working on this in the near future...
This is similar in spirit to https://github.com/remkop/picocli/issues/1987
Basically, I want to be able to write CLIs such that explicitly passing empty-string as a param value is the same as having not specified the parameter at all. (e.g.
--bar=x --foo=
is the same as--bar=x
). I suggest empty string because it's the closest thing BASH has to as "null" value. I see this as the best practice for optional parameters in any language.In particular, I want support for default values to work correctly. For example:
would invoke
tool
withMyEnum.A
as the value formyEnum
My objective is to make it easier to wrappers/scripts/etc to invoke tools with default values, without having to know what the default values are. Wrappers should be able to assume empty-string is the default value for every param.
Obviously this is a backward incompatible change, but could it be added as a setter on
CommandLine
?