2012-04-15 14 views
8

私は、この質問が既に尋ねられていることを知っていますが、私は特定の機能を備えたJava cliパーサーを探しています。 コマンドラインツリーを定義できるようにしたいので、サブコマンド(と複数レベルの深さ)を使用します。 私はオプションに到達する前に、私は3-4レベルのコマンドを持つことができます。 これらのサブコマンドは相互に排他的です。あなたのコマンド式が複雑な場合 おかげJava CLIパーサー

+0

解析するコマンドの例をいくつか投稿できますか? – dash1e

+1

コマンドサブコマンドサブサブコマンド-option1引数-option2引数 – Sophie

答えて

0

は、あなたは、構文を定義そのBNFを書いて、あなた自身のパーサーを作成するためにJavaCCAntLRのようなライブラリを使用するように考えることができます。

12

JCommanderで実行できます。すべてのJCommanderオブジェクトは、その本質的に、任意の数のパラメータおよび/または任意の数のネストされたサブコマンドを含むコマンドであり、JCommanderオブジェクトがルートコマンドである。コマンドパラメータは、それらが宣言されたコマンドに固有であり、他のコマンドのパラメータと干渉しない。サブコマンドを追加するためのインターフェイスは非常に直感的ではありませんが、可能である()(addCommandメソッドを参照してください)。ここ

は、概念実証テストクラスです:

public class Test{ 

@Test 
public void nestedSubCommandTest() { 
    GeneralOptions generalOpts = new GeneralOptions(); 
    JCommander jc = new JCommander(generalOpts); 

    Command command = new Command(); 
    JCommander jc_command = addCommand(jc, "command", command); 

    SubCommand1 subcommand1 = new SubCommand1(); 
    JCommander jc_subcommand1 = addCommand(jc_command, "subcommand1", 
      subcommand1); 

    SubCommand2 subcommand2 = new SubCommand2(); 
    JCommander jc_subcommand2 = addCommand(jc_subcommand1, "subcommand2", 
      subcommand2); 

    SubCommand3 subcommand3 = new SubCommand3(); 
    addCommand(jc_subcommand2, "subcommand3", subcommand3); 

    jc.parse("--general-opt", 
     "command", "--opt", 
     "subcommand1", 
     "subcommand2", "--sub-opt2", 
     "subcommand3", "--sub-opt3"); 

    assertTrue(generalOpts.opt);// --general-opt was set 
    assertTrue(command.opt);// command --opt was set 
    assertFalse(subcommand1.opt);// subcommand1 --sub-opt1 was not set 
    assertTrue(subcommand2.opt);// subcommand2 --sub-opt2 was set 
    assertTrue(subcommand3.opt);// subcommand3 --sub-opt3 was set 
} 

private static JCommander addCommand(JCommander parentCommand, 
     String commandName, Object commandObject) { 
    parentCommand.addCommand(commandName, commandObject); 
    return parentCommand.getCommands().get(commandName); 
} 

public static class GeneralOptions { 
    @Parameter(names = "--general-opt") 
    public boolean opt; 
} 

@Parameters 
public static class Command { 
    @Parameter(names = "--opt") 
    public boolean opt; 
} 

@Parameters 
public static class SubCommand1 { 
    @Parameter(names = "--sub-opt1") 
    public boolean opt; 
} 

@Parameters 
public static class SubCommand2 { 
    @Parameter(names = "--sub-opt2") 
    public boolean opt; 
} 

@Parameters 
public static class SubCommand3 { 
    @Parameter(names = "--sub-opt3") 
    public boolean opt; 
} 
} 

編集: 方法コマンドを再利用する。

ソリューション1、利用継承:

public class CommonArgs{ 
    @Parameter(names="--common-opt") 
    public boolean isCommonOpt; 
    } 

    @Parameters(description = "my command 1") 
    public class MyCommand1 extends CommonArgs{} 

    @Parameters(description = "my command 2") 
    public class MyCommand2 extends CommonArgs{} 

私は、使用状況や行動は、このいずれかのfaily明らかであると思います。 1つの欠点は、1つのクラスからしか拡張できないことです。 は今後の再利用を制限する可能性があります。

解決策2は、構図パターン(doc hereを参照)を使用して:彼らは、コマンドクラスの直接的なパラメータであるかのように

ここ
public class CommonArgs{ 
    @Parameter(names="--common-opt") 
    public boolean isCommonOpt; 
    } 

    @Parameters(description = "my command 1") 
    public class MyCommand1{ 
    @ParametersDelegate 
    public CommonArgs commonArgs = new CommonArgs(); 
    } 

    @Parameters(description = "my command 2") 
    public class MyCommand2{ 
    @ParametersDelegate 
    public CommonArgs commonArgs = new CommonArgs(); 
    } 

を、ネストされたcommonArgsクラスパラメータが扱われます。必要なだけ多くのデリゲートを追加したり、他のデリゲート内にデリゲートをネストすることもできます。構文解析後に委任されたオプションの値を取得するには、myCommand1.commonArgs.isCommonOptなどを実行してください。

+0

こんにちは。私は実際にJCommanderと一日中遊んでいます。私はそれにいくつかの問題があります。パーサの例外は全くわかりません。私はそれらをユーザに紹介することはできません。別のことは、コマンドごとにコマンドクラスを作成する必要があることです(また、たくさんあります)。アノテーションはジェネリックではないため、再利用できません。ああ、usage()は実際にすべてのサブコマンドとオプションを出力しません。 – Sophie

+2

JCommanderはおそらくサブコマンドを最優先にして設計されていなかったでしょう。それほど多くの例外的なケースはありませんので、おそらくもっと役に立つものにラップすることができます。 'usage()'に関しては、サブコマンドの正式なサポートはないので、ハッキングを行うか、単に手書きしなければなりません。私は再利用に同意できませんが、再利用可能性は私がJCommanderについて愛しているものです。私が具体的な事例を教えてくれれば、それを手伝うことができるかもしれません。 – rodion

+0

ありがとうございました!例えば、私は異なる命名と異なる記述を持つ2つのコマンドを持っていますが、どちらも同じパラメータを取得します。そのため、説明を設定するためには、クラス内のパラレーターは同じになりますが、コマンドクラスのインスタンスが異なる必要があります。 – Sophie

0

このマルチレベルコマンドを複数のCLIツールに分割する方がよいと思います。名前をプログラムする
program cmd sub-cmd sub-sub-cmd -option1 argument -option2 argument

アペンド一つまたは二つのレベル::

代わりの
program-cmd-sub-cmd sub-sub-cmd -option1 argument -option2 argument

実ワード例:
svn-add -q -N foo.c

あなたは、単一のJARに必要なすべてのクラスを保つことができます(そして、好きなだけ再利用してください)、いくつかの「メイン」エントリーポイントを追加してください。基本的なCLI解析については、JCommanderもお勧めします。

1

picocliは、任意の深さのネストされたサブコマンドをサポートします。

CommandLine commandLine = new CommandLine(new MainCommand()) 
     .addSubcommand("cmd1", new ChildCommand1()) // 1st level 
     .addSubcommand("cmd2", new ChildCommand2()) 
     .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // 2nd level 
       .addSubcommand("cmd3sub1", new GrandChild3Command1()) 
       .addSubcommand("cmd3sub2", new GrandChild3Command2()) 
       .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // 3rd 
         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1()) 
         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2()) 
           // etc 
       ) 
     ); 

また、ANSIのスタイルと色に関する使用法のヘルプが好きかもしれません。

使用上のヘルプには、オプションと定位置パラメーターに加えて、登録されたサブコマンドがリストされています。

enter image description here

使用方法のヘルプを簡単に注釈をカスタマイズされています。

enter image description here

  • 、アノテーションベースの
  • のgit-スタイルのサブコマンド
  • ネストされたサブサブコマンド
  • 強く型付けされたオプションパラメータ
  • 強く型付けされた位置パラメータ
  • カスタマイズ型変換
  • GNUスタイルのロングオプション
  • ANSIカラーのいずれかのオプションの接頭辞を可能にどのように多くの引数フィールドは
  • 流暢APIを消費
  • POSIXスタイルのクラスタ化された短いオプションのための多値オプション
  • 直感的なモデル使用方法ヘルプ
  • カスタマイズ可能な使用方法
  • 単一ソースファイル:アプリケーションを単一のjarファイルにするためにインクルードする