PicoCLI: смешанные зависимые и исключающие аргументы

Я пытаюсь добиться чего-то вроде следующего с помощью PicoCLI:

  • Вариант 0 (помощь, подробно)
  • Option A
    • Dependent Option A-1
    • Зависимый вариант А-2
    • Зависимый вариант А-3
  • Option B
    • Requires Option A
    • Но не допускает никаких вариантов A-*

Я не знаю, смогу ли я выполнить эту настройку с помощью инструментов PicoCLI или просто проверю после анализа пользовательского кода.

В этом состоянии Option A находится в ArgGroup, где Option A требуется, а Optioan A-* — нет. Вариант B находится в другой группе ArgGroup. Я пытался установить некоторые вещи эксклюзивными, но я не могу понять, как ArgGroup/Exclusive работают должным образом...

Любые подсказки?


person Spyse    schedule 18.03.2020    source источник
comment
Итак, чтобы уточнить, -A1 требует -A и разрешает (но не требует) -A2 и -A3. Точно так же -A2 требует -A и разрешает (но не требует) -A1 и -A3. Параметр -A позволяет, но не требует использования параметров -A1, -A2 и -A3. Это правильно?   -  person Remko Popma    schedule 18.03.2020
comment
Да, ты понял ;)   -  person Spyse    schedule 18.03.2020


Ответы (1)


Подводя итог взаимосвязям, которые должны иметь эти параметры:

  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 разрешают друг друга).

Одна группа, такая как [-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(" "));
    }
}
person Remko Popma    schedule 18.03.2020