commands-cli
An opinionated extension to the Apache Commons CLI library which adds support for commands.
Main Features
Extends the Apache Commons CLI, adding the following features:
- Command arguments parsing and validation
- Simple command execution pattern: 
  my-cli [OPTIONS] [ARGS]
- Complex command routing patterns, e.g. git-flow style: 
  git flow feature start <NAME> git flow feature finish <NAME> git flow release start <VERSION> git flow release finish <VERSION> git flow support start <VERSION> <TAG>
- Built-in usage help option for every route and command: 
  $ my-cli --help usage: my-cli [OPTIONS] My command line tool Options: -h,--help Show this help
Usage
Maven Dependency
<dependency>
  <groupId>com.ebay.sd.commons</groupId>
  <artifactId>commands-cli</artifactId>
  <version>${commands-cli.version}</version>
</dependency> 
Simple Example
Define the executable command:
public class MyCommand extends AbstractCommand {
  
  public static final CommandDescriptor DESCRIPTOR = CommandDescriptor.builder("my-cli")
      .description("This is my command line tool")
      .addOption(Option.builder("v").longOpt("verbose").build())
      .addArgument(Argument.builder("FILE").description("The input file").required().build())
      .factory(new CommandFactory() {
        @Override
        Command create(CommandContext commandContext) throws ParseException {
          return new MyCommand(commandContext);
        }
      })
      .build();
  
  public MyCommand(CommandContext commandContext) {
    super(commandContext);
  }
  
  @Override
  protected void validate(CommandContext commandContext) throws ParseException {
    //Validate the command input if needed
  }
  
  @Override
  public void execute() throws CommandException {
    //Do what ever you want to do, use getCommandContext() to check options, get arguments, etc.
  }
} 
In the main method - define and run the program:
public class Main {
  public static void main(String[] args) {
    CommandsCliMain.builder().mainCommand(MyCommand.DESCRIPTOR).build().main(args);
  }
} 
The example above defines a simple command line interface which has a single option (flag) -v, --verbose (defined and implemented by the program) and a single required argument FILE. The actual execution is done by the command class MyCommand.
 To invoke it from the command line (assuming my-cli is an executable/script which invokes main), a user shall use the following usage pattern:
my-cli [OPTIONS] FILE
For example, with verbosity flag turned on:
my-cli --verbose path/to/file
Advanced Example
Continuing the git-flow example, define the commands, e.g. the git flow feature start <NAME> command with an optional --showcommands option:
public class GitFlowFeatureStartCommand extends AbstractCommand {
  public static final CommandDescriptor DESCRIPTOR = CommandDescriptor.builder("start")
    .description("Start a feature branch")
    .addOption(Option.builder().longOpt("showcommands").desc("Show git commands while executing them").required(false).build())
    .addArgument(Argument.builder("NAME").description("Feature name").required().build())
    .factory(new CommandFactory() {
      @Override
      public Command create(CommandContext commandContext) throws ParseException {
        return new GitFlowFeatureStartCommand(commandContext);
      }
    })
    .build();
  
  //etc...
} 
In the main program, build routing to the commands and the run it, passing the command line arguments.
public class Main {
  public static void main(String[] args){
    //Define the routes to the commands
    RouteDescriptor git = RouteDescriptor.builder("git")
        .description("The git command line tool")
        .addSubCommand(
            RouteDescriptor.builder("flow")
                .description("git-flow extensions")
                .addSubCommand(
                    RouteDescriptor.builder("feature")
                        .description("git-flow feature branch related operations")
                        .addSubCommand(GitFlowFeatureStartCommand.DESCRIPTOR)
                        .addSubCommand(GitFlowFeatureFinishCommand.DESCRIPTOR)
                        .build())
                .addSubCommand(
                    RouteDescriptor.builder("release")
                        .description("git-flow release branch related operations")
                        .addSubCommand(GitFlowReleaseStartCommand.DESCRIPTOR)
                        .addSubCommand(GitFlowReleaseFinishCommand.DESCRIPTOR)
                        .build())
                .addSubCommand(
                    RouteDescriptor.builder("support")
                        .description("git-flow support branch related operations")
                        .addSubCommand(GitFlowSupportStartCommand.DESCRIPTOR)
                        .build())
                .build())
        .build();
    
    //Build and run the main program
    CommandsCliMain.builder().mainRoute(git).build().main(args);
  }
} 
Usage Help
By default, a help option is added to each route and command:
 -h,--help   Show this help
This can be customized using the context data. For example:
public class Main {
  public static void main(String[] args){
    HelpFormatter myHelpFormatter = createMyHelpFormatter();
    Option showHelpOpt = Option.builder()
        .longOpt("show-help")
        .desc("Show my-cli help")
        .build();
    
    Map<String, Object> ctxData = new HashMap<>();
    ctxData.put(UsageHelp.CTX_HELP_OPTION, showHelpOpt);
    ctxData.put(UsageHelp.CTX_HELP_FORMATTER, myHelpFormatter); 
    ctxData.put(UsageHelp.CTX_HELP_OPTION_AUTO_ADD, false);
    
    CommandsCliMain cli = CommandsCliMain.builder()
        .contextData(ctxData)
        .mainRoute(root)
        .build();
    cli.main(args); 
  }
  //...
} 
Contributing
For instructions on contributing to this project, see CONTRIBUTING.md.
Maintainers - for detailed instructions on how to release a new version, see RELEASING.md.
License
Copyright 2018 eBay Inc.
 Developer: Yinon Avraham
Use of this source code is governed by an Apache-2.0-style
 license that can be found in the LICENSE file or at
 http://www.apache.org/licenses/LICENSE-2.0.
 JarCasting
 JarCasting