PicoCLI: Dependent and Exclusive Arguments mixed

假装没事ソ 提交于 2020-05-31 05:56:25

问题


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:

  1. -B, -A1, -A2 and -A3 all require the -A option
  2. -B disallows any of the -A1, -A2 and -A3 options
  3. the -A1, -A2 and -A3 options do allow each other
  4. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!