【问题标题】:Picocli command hierarchy in JLineJLine 中的 Picocli 命令层次结构
【发布时间】:2019-10-22 05:19:48
【问题描述】:

我正在使用 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 用户必须传入命令和参数。

【问题讨论】:

  • 您能举例说明您是如何尝试调用该命令的吗?
  • @RemkoPopma 我添加了通话。当我运行 CLI 应用程序时,似乎只在我传入参数(例如 -u abc -p ab123)时才调用调用,而不是作为 Test CLI -u abc -p abc123
  • @RemkoPopma 我也尝试过使用此处引用的 jline v3 示例:github.com/remkop/picocli/tree/master/picocli-shell-jline3
  • 现在明白了。稍后我会发布答案。
  • 感谢您提出这个问题!我从来没有意识到,但这可能会让人很困惑。我将更新 picocli-shell-* 模块的文档以更好地解释这一点。

标签: shell command-line-interface interactive picocli jline3


【解决方案1】:

命令行实用程序

我认为 java 应用程序的打包方式是造成混乱的原因。 如果您的应用程序是一个单独的可执行文件,比如说myapp.exe,那么您可以像这样在命令行上调用该应用程序:

myapp -u xxx

如果你的应用是一个 Java 类,你需要像这样调用它:

java -cp mylib.jar com.myorg.MyApp -u xxx

因此,顶级命令是com.myorg.MyApp 类本身,无需在命令行上将myapp 指定为com.myorg.MyApp 类的参数。 p>

现在假设您的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);

    }
}

交互式命令行应用程序

当您使用 JLine 创建交互式 CLI shell 应用程序时,您需要记住顶级命令未在命令行中指定

因此,您希望用户能够在 shell 中键入的所有命令都应该是子命令,就像您在回答中描述的那样。

顶级命令仍然可以为用户提供帮助。一种想法是在用户输入无效命令(或不带参数直接回车)时打印一条友好的帮助消息,然后是顶级命令的使用帮助。

【讨论】:

    【解决方案2】:

    一旦打开 CLI 终端,我就无法使用命令名称。我可以只使用没有命令名称的参数。

    我最终将逻辑移至子命令,之后可以调用该子命令。但是,现在 CLI 将建议的命令显示为“父命令 + 子命令”,我可以看到这非常令人困惑(并且使用该选项不会产生预期的结果)。我最终从父命令中删除了描述以处理它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-29
      • 2021-08-22
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      相关资源
      最近更新 更多