问题
I am trying to achieve something like the following with PicoCLI:
- Option 0 (help, verbose)
- Option A
- Dependent Option A-1
- Dependent Option A-2
- Dependent Option A-3
- Option B
- Requires Option A
- But does not allow any Option A-*
I don't know if I can do this setup with PicoCLI tools or if I just check after parsing with custom code.
To this state, Option A is in an ArgGroup where Option A is required, but Optioan A-* not. Option B is in a different ArgGroup. I tried to set some things exclusive, but I can't figure out how to ArgGroup/Exclusive things to work as intended...
Any hints?
回答1:
To summarize the relationships these options need to have:
-B
,-A1
,-A2
and-A3
all require the-A
option-B
disallows any of the-A1
,-A2
and-A3
options- the
-A1
,-A2
and-A3
options do allow each other - the
-A
option allows (but does not require) the-B
,-A1
,-A2
and-A3
options
The picocli annotations alone will not be sufficient to express all of these relationships declaratively, some custom validation will be necessary.
So we might as well simplify and create a single argument group, since we cannot express requirement 2 (-B is exclusive with -A1, -A2, -A3) at the same time as requirement 1 and 3 (-B, -A1, -A2 and -A3 all require -A and -A1, -A2, -A3 allow each other).
A single group like [-A [-B] [-A1] [-A2] [-A3]]
will take care of some of the validations: everything except requirement 2 (-B is exclusive with -A1, -A2, -A3). For requirement 2, we need to code some custom validation in the application (example below).
For your use case it may be useful to have a custom synopsis that accurately reflects the relationships between the options. Something like this:
Usage: app [-hV] [-A [-B]]
app [-hV] [-A [-A1] [-A2] [-A3]]
Example code to achieve this:
import picocli.CommandLine;
import picocli.CommandLine.*;
import picocli.CommandLine.Model.CommandSpec;
@Command(name = "app", mixinStandardHelpOptions = true,
synopsisHeading = "",
customSynopsis = {
"Usage: app [-hV] [-A [-B]]",
" app [-hV] [-A [-A1] [-A2] [-A3]]",
})
public class App implements Runnable {
static class MyGroup {
@Option(names = "-A", required = true) boolean a;
@Option(names = "-B") boolean b;
@Option(names = "-A1") boolean a1;
@Option(names = "-A2") boolean a2;
@Option(names = "-A3") boolean a3;
boolean isInvalid() {
return b && (a1 || a2 || a3);
}
}
@ArgGroup(exclusive = false)
MyGroup myGroup;
@Spec CommandSpec spec;
public void run() {
if (myGroup != null && myGroup.isInvalid()) {
String msg = "Option -B is mutually exclusive with -A1, -A2 and -A3";
throw new ParameterException(spec.commandLine(), msg);
}
System.out.printf("OK: %s%n", spec.commandLine().getParseResult().originalArgs());
}
public static void main(String[] args) {
//new CommandLine(new App()).usage(System.out);
//test: these are all valid
new CommandLine(new App()).execute();
new CommandLine(new App()).execute("-A -B".split(" "));
// requires validation in the application to disallow
new CommandLine(new App()).execute("-A -B -A1".split(" "));
// picocli validates this, gives: "Error: Missing required argument(s): -A"
new CommandLine(new App()).execute("-B -A1".split(" "));
}
}
来源:https://stackoverflow.com/questions/60734729/picocli-dependent-and-exclusive-arguments-mixed