1

我正在尝试使用 PicoCLI 实现以下目标:

  • 选项 0(帮助,详细)
  • 选项 A
    • 从属选项 A-1
    • 从属选项 A-2
    • 从属选项 A-3
  • 选项 B
    • 需要选项 A
    • 但不允许任何选项 A-*

我不知道我是否可以使用 PicoCLI 工具进行此设置,或者我是否只是在使用自定义代码解析后进行检查。

在此状态下,选项 A 位于需要选项 A 的 ArgGroup 中,但不需要选项 A-*。选项 B 位于不同的 ArgGroup 中。我试图设置一些独占的东西,但我不知道如何让 ArgGroup/Exclusive 的东西按预期工作......

有什么提示吗?

4

1 回答 1

3

总结这些选项需要具备的关系:

  1. -B, -A1,-A2并且-A3需要-A选项
  2. -B 不允许任何-A1,-A2-A3选项
  3. ,-A1和选项确实允许-A2彼此-A3
  4. -A选项允许(但不要求)-B-A1和选项-A2-A3

仅 picocli 注释不足以以声明方式表达所有这些关系,需要一些自定义验证。

所以我们不妨简化并创建一个单独的参数组,因为我们不能同时表达要求 2(-B 与 -A1、-A2、-A3 互斥)和要求 1 和 3(-B、-A1、 -A2 和 -A3 都要求 -A 和 -A1,-A2,-A3 互相允许)。

单个组 like[-A [-B] [-A1] [-A2] [-A3]]将负责一些验证:除要求 2 之外的所有内容(-B 与 -A1、-A2、-A3 互斥)。对于需求 2,我们需要在应用程序中编写一些自定义验证(示例如下)。

对于您的用例,拥有一个准确反映选项之间关系的自定义概要可能很有用。像这样的东西:

Usage: app [-hV] [-A [-B]]
       app [-hV] [-A [-A1] [-A2] [-A3]]

实现此目的的示例代码:

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(" "));
    }
}
于 2020-03-18T09:05:54.497 回答