Picocli 需要基于主要选项的选项选择
Picocli required options selection based on a primary option
我想用 picocli 解析以下格式的选项:
application -mode CLIENT -c aaaa -d bbbb
application -mode SERVER -e xxxx -f yyyy
mode
是具有值 { CLIENT, SERVER }
的 enum
- 如果
mode == CLIENT
、-c
和-d
选项是必须的,-e
、-f
则不能使用。
- 如果
mode == SERVER
、-e
和-f
选项是必须的,-c
、-d
则不能使用。
换句话说,我想根据一个关键选项来选择所需的选项。这在 picocli 中可行吗?
是的,这是可能的。一种方法是简单的编程验证:
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.Spec;
import java.util.Objects;
import java.util.function.Predicate;
@Command(name = "application", mixinStandardHelpOptions = true)
public class MyApp implements Runnable {
enum Mode {CLIENT, SERVER}
@Option(names = "-mode", required = true)
Mode mode;
@Option(names = "-c") String c;
@Option(names = "-d") String d;
@Option(names = "-e") String e;
@Option(names = "-f") String f;
@Spec CommandSpec spec;
public static void main(String[] args) {
System.exit(new CommandLine(new MyApp()).execute(args));
}
@Override
public void run() {
validateInput();
// business logic here...
}
private void validateInput() {
String INVALID = "Error: option(s) %s cannot be used in %s mode";
String REQUIRED = "Error: option(s) %s are required in %s mode";
if (mode == Mode.CLIENT) {
check(INVALID, "CLIENT", Objects::isNull, e, "-e", f, "-f");
check(REQUIRED, "CLIENT", Objects::nonNull, c, "-c", d, "-d");
} else if (mode == Mode.SERVER) {
check(INVALID, "SERVER", Objects::isNull, c, "-c", d, "-d");
check(REQUIRED, "SERVER", Objects::nonNull, e, "-e", f, "-f");
}
}
private void check(String msg, String param, Predicate<String> validator, String... valuesAndLabels) {
String desc = "";
String sep = "";
for (int i = 0; i < valuesAndLabels.length; i += 2) {
if (validator.test(valuesAndLabels[i])) {
desc = sep + valuesAndLabels[i + 1];
sep = ", ";
}
}
if (desc.length() > 0) {
throw new ParameterException(spec.commandLine(), String.format(msg, desc, param));
}
}
}
或者,如果您愿意稍微更改您的要求,我们可以使用 picocli 的 argument groups 来获得更具声明性的方法:
import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "application", mixinStandardHelpOptions = true)
public class MyApp2 implements Runnable {
static class ClientArgs {
@Option(names = "-clientMode", required = true) boolean clientMode;
@Option(names = "-c", required = true) String c;
@Option(names = "-d", required = true) String d;
}
static class ServerArgs {
@Option(names = "-serverMode", required = true) boolean serverMode;
@Option(names = "-e", required = true) String e;
@Option(names = "-f", required = true) String f;
}
static class Args {
@ArgGroup(exclusive = false, multiplicity = "1", heading = "CLIENT mode args%n")
ClientArgs clientArgs;
@ArgGroup(exclusive = false, multiplicity = "1", heading = "SERVER mode args%n")
ServerArgs serverArgs;
}
@ArgGroup(exclusive = true, multiplicity = "1")
Args args;
public static void main(String[] args) {
System.exit(new CommandLine(new MyApp2()).execute(args));
}
@Override
public void run() {
// business logic here...
}
}
仅使用 -serverMode
调用时,第二个示例将显示此错误消息,然后是用法帮助消息:
Error: Missing required argument(s): -e=<e>, -f=<f>
Usage: application ((-clientMode -c=<c> -d=<d>) | (-serverMode -e=<e> -f=<f>))
...
请注意,这种声明性方法无法通过单个 -mode
选项实现:每个参数组都需要自己的选项(我在本例中选择了 -clientMode
和 -serverMode
)。这允许 picocli 解析器找出哪些选项必须一起出现,哪些选项是互斥的。
我想用 picocli 解析以下格式的选项:
application -mode CLIENT -c aaaa -d bbbb
application -mode SERVER -e xxxx -f yyyy
mode
是具有值 { CLIENT, SERVER }
enum
- 如果
mode == CLIENT
、-c
和-d
选项是必须的,-e
、-f
则不能使用。 - 如果
mode == SERVER
、-e
和-f
选项是必须的,-c
、-d
则不能使用。
换句话说,我想根据一个关键选项来选择所需的选项。这在 picocli 中可行吗?
是的,这是可能的。一种方法是简单的编程验证:
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.Spec;
import java.util.Objects;
import java.util.function.Predicate;
@Command(name = "application", mixinStandardHelpOptions = true)
public class MyApp implements Runnable {
enum Mode {CLIENT, SERVER}
@Option(names = "-mode", required = true)
Mode mode;
@Option(names = "-c") String c;
@Option(names = "-d") String d;
@Option(names = "-e") String e;
@Option(names = "-f") String f;
@Spec CommandSpec spec;
public static void main(String[] args) {
System.exit(new CommandLine(new MyApp()).execute(args));
}
@Override
public void run() {
validateInput();
// business logic here...
}
private void validateInput() {
String INVALID = "Error: option(s) %s cannot be used in %s mode";
String REQUIRED = "Error: option(s) %s are required in %s mode";
if (mode == Mode.CLIENT) {
check(INVALID, "CLIENT", Objects::isNull, e, "-e", f, "-f");
check(REQUIRED, "CLIENT", Objects::nonNull, c, "-c", d, "-d");
} else if (mode == Mode.SERVER) {
check(INVALID, "SERVER", Objects::isNull, c, "-c", d, "-d");
check(REQUIRED, "SERVER", Objects::nonNull, e, "-e", f, "-f");
}
}
private void check(String msg, String param, Predicate<String> validator, String... valuesAndLabels) {
String desc = "";
String sep = "";
for (int i = 0; i < valuesAndLabels.length; i += 2) {
if (validator.test(valuesAndLabels[i])) {
desc = sep + valuesAndLabels[i + 1];
sep = ", ";
}
}
if (desc.length() > 0) {
throw new ParameterException(spec.commandLine(), String.format(msg, desc, param));
}
}
}
或者,如果您愿意稍微更改您的要求,我们可以使用 picocli 的 argument groups 来获得更具声明性的方法:
import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "application", mixinStandardHelpOptions = true)
public class MyApp2 implements Runnable {
static class ClientArgs {
@Option(names = "-clientMode", required = true) boolean clientMode;
@Option(names = "-c", required = true) String c;
@Option(names = "-d", required = true) String d;
}
static class ServerArgs {
@Option(names = "-serverMode", required = true) boolean serverMode;
@Option(names = "-e", required = true) String e;
@Option(names = "-f", required = true) String f;
}
static class Args {
@ArgGroup(exclusive = false, multiplicity = "1", heading = "CLIENT mode args%n")
ClientArgs clientArgs;
@ArgGroup(exclusive = false, multiplicity = "1", heading = "SERVER mode args%n")
ServerArgs serverArgs;
}
@ArgGroup(exclusive = true, multiplicity = "1")
Args args;
public static void main(String[] args) {
System.exit(new CommandLine(new MyApp2()).execute(args));
}
@Override
public void run() {
// business logic here...
}
}
仅使用 -serverMode
调用时,第二个示例将显示此错误消息,然后是用法帮助消息:
Error: Missing required argument(s): -e=<e>, -f=<f>
Usage: application ((-clientMode -c=<c> -d=<d>) | (-serverMode -e=<e> -f=<f>))
...
请注意,这种声明性方法无法通过单个 -mode
选项实现:每个参数组都需要自己的选项(我在本例中选择了 -clientMode
和 -serverMode
)。这允许 picocli 解析器找出哪些选项必须一起出现,哪些选项是互斥的。