JLine 中的 Picocli 命令层次结构
Picocli command hierarchy in JLine
我正在使用 Pico CLI v4.0.0-alpha-3 和 jline v3。我有以下 class (使用注释)。当我 运行 主 class 时,我似乎无法 运行 命令并调用可调用对象。如果我简单地传入参数,我就可以调用可调用对象。
@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 用户必须传入命令后跟参数。
一旦 CLI 终端打开,我就再也无法使用命令名称了。我可以只使用没有命令名称的参数。
我最终将逻辑移动到一个子命令,之后可以调用该子命令。但是,现在 CLI 将建议的命令显示为 "parent command + sub command",这让我很困惑(并且使用该选项不会产生预期的结果)。我最终从父命令中删除了描述来处理它。
命令行实用程序
我认为 java 应用程序的打包方式是导致混淆的原因。
如果您的应用程序是单个可执行文件,比方说 myapp.exe
,那么您可以像这样在命令行上调用该应用程序:
myapp -u xxx
如果您的应用程序是 Java class,您需要像这样调用它:
java -cp mylib.jar com.myorg.MyApp -u xxx
因此,top-level 命令就是 com.myorg.MyApp
class 本身,不需要指定 myapp
作为 com.myorg.MyApp
class 命令行.
现在假设您的 myapp
应用程序有一个名为 sub
的子命令。同样,如果您的应用程序是单个可执行文件,您可以像这样在命令行上调用子命令:
myapp sub --subcommand-options
作为 Java class,您需要像下面这样调用它。注意这里,你做需要指定子命令名称作为命令行参数到com.myorg.MyApp
class:
java -cp mylib.jar com.myorg.MyApp sub --subcommand-options
Side note: What people often do is create startup scripts for Windows and unix that allow you to execute your application as myapp
instead of java -cp mylib.jar com.myorg.MyApp
. One of the reasons that people are enthusiastic about GraalVM is that GraalVM native images solve this packaging problem and allow Java developers to distribute their applications as a single executable file.
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);
}
}
交互式命令行应用程序
当您使用 JLine 创建交互式 CLI shell 应用程序时,您需要记住 top-level 命令未在命令行中指定.
因此,您希望用户能够在 shell 中键入的所有命令都应该是子命令,就像您在回答中描述的那样。
top-level命令仍然可以为用户提供帮助。一种想法是在用户输入无效命令(或不带参数地按回车键)时打印一条友好的帮助消息,然后是 top-level 命令的使用帮助。
我正在使用 Pico CLI v4.0.0-alpha-3 和 jline v3。我有以下 class (使用注释)。当我 运行 主 class 时,我似乎无法 运行 命令并调用可调用对象。如果我简单地传入参数,我就可以调用可调用对象。
@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 用户必须传入命令后跟参数。
一旦 CLI 终端打开,我就再也无法使用命令名称了。我可以只使用没有命令名称的参数。
我最终将逻辑移动到一个子命令,之后可以调用该子命令。但是,现在 CLI 将建议的命令显示为 "parent command + sub command",这让我很困惑(并且使用该选项不会产生预期的结果)。我最终从父命令中删除了描述来处理它。
命令行实用程序
我认为 java 应用程序的打包方式是导致混淆的原因。
如果您的应用程序是单个可执行文件,比方说 myapp.exe
,那么您可以像这样在命令行上调用该应用程序:
myapp -u xxx
如果您的应用程序是 Java class,您需要像这样调用它:
java -cp mylib.jar com.myorg.MyApp -u xxx
因此,top-level 命令就是 com.myorg.MyApp
class 本身,不需要指定 myapp
作为 com.myorg.MyApp
class 命令行.
现在假设您的 myapp
应用程序有一个名为 sub
的子命令。同样,如果您的应用程序是单个可执行文件,您可以像这样在命令行上调用子命令:
myapp sub --subcommand-options
作为 Java class,您需要像下面这样调用它。注意这里,你做需要指定子命令名称作为命令行参数到com.myorg.MyApp
class:
java -cp mylib.jar com.myorg.MyApp sub --subcommand-options
Side note: What people often do is create startup scripts for Windows and unix that allow you to execute your application as
myapp
instead ofjava -cp mylib.jar com.myorg.MyApp
. One of the reasons that people are enthusiastic about GraalVM is that GraalVM native images solve this packaging problem and allow Java developers to distribute their applications as a single executable file.
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);
}
}
交互式命令行应用程序
当您使用 JLine 创建交互式 CLI shell 应用程序时,您需要记住 top-level 命令未在命令行中指定.
因此,您希望用户能够在 shell 中键入的所有命令都应该是子命令,就像您在回答中描述的那样。
top-level命令仍然可以为用户提供帮助。一种想法是在用户输入无效命令(或不带参数地按回车键)时打印一条友好的帮助消息,然后是 top-level 命令的使用帮助。