Масштабируемые приложения с picocli. Вопрос о лучшей практике

Скажем, в моем проекте много логики и несколько точек входа, это команды CLI.

Я аннотирую свои точки входа с помощью @Command, инициализирую свои аннотированные поля @Parameters и @Option и выполняю логику, которая больше не требует CLI.

На мой взгляд, мне было бы удобно объявить 1 main метода на @Command аннотированный класс, однако я не уверен, что это хорошая идея.

Может какой CommandFactory нужен?

Я никогда раньше не создавал приложения CLI и не использовал picocli, поэтому, если мой мыслительный процесс ошибочен, укажите это.


person saæ    schedule 07.11.2018    source источник


Ответы (1)


Совершенно нормально иметь отдельный метод main для каждого @Command, являющегося точкой входа. Метод main необходим, чтобы команду можно было вызывать отдельно из командной строки.

Например:

@Command(name = "hello")
class Hello implements Runnable {
    public static void main(String[] args) {
        CommandLine.run(new Hello(), args);
    }
    public void run() { System.out.println("hello"); }
}

@Command(name = "bye")
class Bye implements Runnable {
    public static void main(String[] args) {
        CommandLine.run(new Bye(), args);
    }
    public void run() { System.out.println("bye"); }
}

Единственным исключением являются команды вашего приложения с подкомандами. В этом случае вам потребуется только main методов для команд верхнего уровня, а не для подкоманд.

Пример с подкомандами:

@Command(name = "git", subcommands = {Commit.class, Status.class})
class Git implements Runnable {
    public static void main(String[] args) { // top-level command needs main
        CommandLine.run(new Git(), args);
    }
    public void run() { System.out.println("Specify a subcommand"); }
}

@Command(name = "commit")
class Commit implements Runnable {
    @Option(names = "-m") String message;
    @Parameters File[] files;

    public void run() {
        System.out.printf("Committing %s with message '%s'%n",
                Arrays.toString(files), message);
    }
}

@Command(name = "status")
class Status implements Runnable {
    public void run() { System.out.println("All ok."); }
}

Обратите внимание, что только команда верхнего уровня нуждается в методе main при наличии подкоманд. Даже с подкомандами фабрика не нужна.

person Remko Popma    schedule 07.11.2018
comment
Интересно, насколько хорошо он масштабируется. Скажем, я хотел собрать его в файл .jar. Как бы мне это сделать, если бы я хотел, чтобы у него было две точки входа, для myprogram mycommand -o=option и myprogram anothercommand -o=option, чтобы он знал, что нужно запускать отдельные основные методы? Должен ли я играть с манифестом, чтобы добиться этого? - person saæ; 07.11.2018
comment
В вашем примере myprogram — это команда верхнего уровня, а mycommand и anothercommand — подкоманды, не так ли? - person Remko Popma; 07.11.2018
comment
Я должен был бы исследовать подкоманды как вещь. Если бы git был создан с помощью picocli, были бы pull и commit и т. д. подкомандами? Если так, то это то, что я ищу. - person saæ; 07.11.2018
comment
Читая примеры, я обнаружил, что концепция подкоманд — это именно то, что мне нужно. Спасибо, что терпите меня! - person saæ; 07.11.2018
comment
Рад слышать! - person Remko Popma; 07.11.2018