Java 带Picocli的CLI:在调用子命令之前调用main命令
由于子命令支持(以及基于注释的声明),我从Apache Commons CLI切换到Picocli 考虑一个命令行工具,如Java 带Picocli的CLI:在调用子命令之前调用main命令,java,command-line-interface,picocli,Java,Command Line Interface,Picocli,由于子命令支持(以及基于注释的声明),我从Apache Commons CLI切换到Picocli 考虑一个命令行工具,如git,其中包含子命令,如push。Git有一个主开关--verbose或-v,用于在所有子命令中启用verbose模式。 如何实现在任何子命令之前执行的主开关 这是我的测试 @CommandLine.Command(name = "push", description = "Update remote refs along with associated o
git
,其中包含子命令,如push
。Git有一个主开关--verbose
或-v
,用于在所有子命令中启用verbose模式。
如何实现在任何子命令之前执行的主开关
这是我的测试
@CommandLine.Command(name = "push",
description = "Update remote refs along with associated objects")
class PushCommand implements Callable<Void> {
@Override
public Void call() throws Exception {
System.out.println("#PushCommand.call");
return null;
}
}
@CommandLine.Command(description = "Version control", subcommands = {PushCommand.class})
public class GitApp implements Callable<Void> {
@CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Display this help message.")
private boolean usageHelpRequested;
@CommandLine.Option(names = {"-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting.")
private boolean verboseMode;
public static void main(String[] args) {
GitApp app = new GitApp();
CommandLine.call(app, "--verbose", "push");
System.out.println("#GitApp.main after. verbose: " + (app.verboseMode));
}
@Override
public Void call() throws Exception {
System.out.println("#GitApp.call");
return null;
}
}
我希望在调用子命令之前调用
GitApp.call
get。但是只有sub命令被调用。因为Picocli支持带有选项的继承,我已经将--help
和--verbose
选项提取到一个抽象类BaseCommand
中,并从子命令调用super.call
abstract class BaseCommand implements Callable<Void> {
@CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Display this help message.")
private boolean usageHelpRequested;
@CommandLine.Option(names = {"-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting.")
private boolean verboseMode;
@Override
public Void call() throws Exception {
if (verboseMode) {
setVerbose();
}
return null;
}
private void setVerbose() {
System.out.println("enter verbose mode");
}
}
@CommandLine.Command(name = "push",
description = "Update remote refs along with associated objects")
class PushCommand extends BaseCommand {
@Override
public Void call() throws Exception {
super.call();
System.out.println("Execute push command");
return null;
}
}
@CommandLine.Command(description = "Version control", subcommands = {PushCommand.class})
public class GitApp extends BaseCommand {
public static void main(String[] args) {
GitApp app = new GitApp();
CommandLine.call(app, "push", "--verbose");
}
@Override
public Void call() throws Exception {
super.call();
System.out.println("GitApp.call called");
return null;
}
}
抽象类BaseCommand实现可调用{
@选项(名称={“-h”,“--help”},usageHelp=true,description=“显示此帮助消息”)
私有布尔用法helprequest;
@选项(名称={“-v”,“--verbose”},description=“verbose mode.有助于故障排除。”)
私有布尔详细模式;
@凌驾
public Void call()引发异常{
如果(详细模式){
setVerbose();
}
返回null;
}
私有void setVerbose(){
System.out.println(“进入详细模式”);
}
}
@CommandLine.Command(name=“push”,
description=“随关联对象一起更新远程参照”)
类PushCommand扩展了BaseCommand{
@凌驾
public Void call()引发异常{
super.call();
System.out.println(“执行推送命令”);
返回null;
}
}
@Command(description=“Version control”,子命令={PushCommand.class})
公共类GitApp扩展BaseCommand{
公共静态void main(字符串[]args){
GitApp app=新的GitApp();
CommandLine.call(app,“push”,“verbose”);
}
@凌驾
public Void call()引发异常{
super.call();
System.out.println(“调用GitApp.call”);
返回null;
}
}
命令行.call(和命令行.run
)方法只调用by design,因此您在原始帖子中看到的是预期的行为
调用
和运行
方法实际上是一种快捷方式。以下两行是等效的:
CommandLine.run(callable, args); // internally uses RunLast, equivalent to:
new CommandLine(callable).parseWithHandler(new RunLast(), args);
更新:从picocli 4.0开始,上述方法已被弃用,并替换为新命令行(myapp).execute(args)
。“处理程序”现在称为“执行策略”(下面的示例)
还有一个运行所有匹配命令的。以下main
方法给出了所需的行为:
public static void main(String[] args) {
args = new String[] { "--verbose", "push" };
GitApp app = new GitApp();
// before picocli 4.0:
new CommandLine(app).parseWithHandler(new RunAll(), args);
// from picocli 4.0:
//new CommandLine(app).setExecutionStrategy(new RunAll()).execute(args);
System.out.println("#GitApp.main after. verbose: " + (app.verboseMode));
}
输出:
#GitApp.call
#PushCommand.call
#GitApp.main after. verbose: true
您可能还对注释感兴趣。这告诉picocli将父命令的实例注入子命令。然后,子命令可以调用父命令上的方法,例如检查verbose
是否为true。例如:
更新:从picocli 4.0中,使用setExecutionStrategy
方法指定RunAll
。下面的示例更新为使用新的picocli 4.0+API
其他次要编辑:通过导入内部类,使注释更加紧凑。您可能还喜欢有助于减少样板代码的属性和内置子命令。非常好的提示!也谢谢你的皮科利!
#GitApp.call
#PushCommand.call
#GitApp.main after. verbose: true
import picocli.CommandLine;
import picocli.CommandLine.*;
@Command(name = "push",
description = "Update remote refs along with associated objects")
class PushCommand implements Runnable {
@ParentCommand // picocli injects the parent instance
private GitApp parentCommand;
public void run() {
System.out.printf("#PushCommand.call: parent.verbose=%s%n",
parentCommand.verboseMode); // use parent instance
}
}
@Command(description = "Version control",
mixinStandardHelpOptions = true, // auto-include --help and --version
subcommands = {PushCommand.class,
HelpCommand.class}) // built-in help subcommand
public class GitApp implements Runnable {
@Option(names = {"-v", "--verbose"},
description = "Verbose mode. Helpful for troubleshooting.")
boolean verboseMode;
public void run() {
System.out.println("#GitApp.call");
}
public static void main(String[] args) {
args = new String[] { "--verbose", "push" };
GitApp app = new GitApp();
int exitCode = new CommandLine(app)
.setExecutionStrategy(new RunAll())
.execute(args);
System.out.println("#GitApp.main after. verbose: " + (app.verboseMode));
System.exit(exitCode);
}
}