Иерархия команд Picocli в JLine
Я использую Pico CLI v4.0.0-alpha-3 и jline v3. У меня есть следующий класс (с использованием аннотаций). Когда я запускаю основной класс, я не могу запустить команду и вызвать вызываемый объект. Я могу вызвать вызываемое, если просто передам параметры.
@CommandLine.Command(name = "Test CLI",
description = "CLI tool",
header = "%n@|green test cli |@",
footer = {"",
"@|cyan Press Ctrl-D to exit the CLI.|@",
""},
version = "1.0.0",
showDefaultValues = true,
optionListHeading = "@|bold %nOptions|@:%n",
subcommands = {
Sync.class,
Status.class
})
public class Tester implements Callable<Integer> {
private static final String PROMPT = "Test CLI> ";
private LineReaderImpl lineReader;
private PrintWriter out;
@Option(names = {"-u", "--username"}, required = true, description = "user name")
private String userName;
@Option(names = {"-p", "--password"}, required = true, description = "password")
private String password;
final Tester tester = new Tester();
final CommandLine cmd = prepareCommand(tester);
final int exitCode = cmd.execute(args);
Когда я запускаю приложение java и запускаю команду с параметрами, вызываемая функция не вызывается. Когда я просто передаю параметры, вызывается вызываемый объект. Любые мысли о том, как это исправить, чтобы пользователь CLI передавал команду, а затем параметры.
2 ответа
Утилиты командной строки
Я думаю, что путаница в том, как упаковываются Java-приложения. Если ваше приложение было одним исполняемым файлом, скажем myapp.exe
тогда вы бы вызвали приложение из командной строки следующим образом:
myapp -u xxx
Если ваше приложение является классом Java, вам нужно вызвать его следующим образом:
java -cp mylib.jar com.myorg.MyApp -u xxx
Итак, команда верхнего уровня com.myorg.MyApp
сам класс, указывать не нужно myapp
в качестве аргумента com.myorg.MyApp
класс в командной строке.
Теперь представьте, что ваш myapp
Приложение имеет подкоманду под названием sub
, Опять же, если бы ваше приложение было одним исполняемым файлом, вы бы вызвали подкоманду в командной строке следующим образом:
myapp sub --subcommand-options
Как Java-класс, вы должны вызывать его, как показано ниже. Обратите внимание, что здесь вам необходимо указать имя подкоманды в качестве аргумента командной строки для com.myorg.MyApp
класс:
java -cp mylib.jar com.myorg.MyApp sub --subcommand-options
Примечание: что люди часто делают, это создают сценарии запуска для Windows и Unix, которые позволяют вам выполнять ваше приложение как
myapp
вместоjava -cp mylib.jar com.myorg.MyApp
, Одна из причин, по которой люди с энтузиазмом относятся к GraalVM, заключается в том, что собственные изображения GraalVM решают эту проблему упаковки и позволяют разработчикам Java распространять свои приложения в виде одного исполняемого файла.
Основным вариантом использования Picocli является облегчение создания утилит командной строки в Java. Так что это очень легко сделать с помощью следующего кода:
package com.myorg;
@Command(name = "myapp")
public class MyApp implements Runnable {
@Option(names = {"-u", "--username"}, description = "user name")
private String userName;
@Command // subcommand "sub"
public void sub(@Option(names = "--subcommand-options") String option) {
System.out.printf("sub says hello %s!%n", userName);
}
@Override
public void run() {
System.out.printf("myapp says hi %s!%n", userName);
}
public static void main(String[] args) {
int exitCode = new CommandLine(new MyApp()).execute(args);
}
}
Интерактивные приложения командной строки
Когда вы создаете интерактивную оболочку CLI с помощью JLine, вам необходимо помнить, что команда верхнего уровня не указана в командной строке.
Поэтому все команды, которые вы хотите, чтобы пользователи могли вводить в оболочке, должны быть подкомандами, как вы описали в своем ответе.
Команда верхнего уровня все еще может быть полезна для оказания помощи пользователям. Одна идея состоит в том, чтобы напечатать дружеское справочное сообщение, за которым следует справка по использованию команды верхнего уровня, когда пользователь вводит недопустимую команду (или просто нажимает ввод без параметров).
Я никогда не мог использовать имя команды, когда терминал CLI был открыт. Я мог бы просто использовать параметры без имени команды.
Я закончил тем, что переместил логику в подкоманду, после чего подкоманда может быть вызвана. Однако теперь CLI отображает предложенную команду как "родительская команда + вспомогательная команда", что, как я вижу, довольно запутанно (и использование этой опции не дает желаемого результата). Я закончил тем, что удалил описание из родительской команды, чтобы позаботиться об этом.