Java annotation-based framework for parsing Git like command line structures

Related tags

CLI airline
Overview

Airline

Airline is a Java annotation-based framework for parsing Git like command line structures.

Latest release is 0.8, available from Maven Central.

<dependency>
    <groupId>io.airlift</groupId>
    <artifactId>airline</artifactId>
    <version>0.8</version>
</dependency>

Here is a quick example:

public class Git
{
    public static void main(String[] args)
    {
        CliBuilder<Runnable> builder = Cli.<Runnable>builder("git")
                .withDescription("the stupid content tracker")
                .withDefaultCommand(Help.class)
                .withCommands(Help.class, Add.class);

        builder.withGroup("remote")
                .withDescription("Manage set of tracked repositories")
                .withDefaultCommand(RemoteShow.class)
                .withCommands(RemoteShow.class, RemoteAdd.class);

        Cli<Runnable> gitParser = builder.build();

        gitParser.parse(args).run();
    }

    public static class GitCommand implements Runnable
    {
        @Option(type = OptionType.GLOBAL, name = "-v", description = "Verbose mode")
        public boolean verbose;

        public void run()
        {
            System.out.println(getClass().getSimpleName());
        }
    }

    @Command(name = "add", description = "Add file contents to the index")
    public static class Add extends GitCommand
    {
        @Arguments(description = "Patterns of files to be added")
        public List<String> patterns;

        @Option(name = "-i", description = "Add modified contents interactively.")
        public boolean interactive;
    }

    @Command(name = "show", description = "Gives some information about the remote <name>")
    public static class RemoteShow extends GitCommand
    {
        @Option(name = "-n", description = "Do not query remote heads")
        public boolean noQuery;

        @Arguments(description = "Remote to show")
        public String remote;
    }

    @Command(name = "add", description = "Adds a remote")
    public static class RemoteAdd extends GitCommand
    {
        @Option(name = "-t", description = "Track only a specific branch")
        public String branch;

        @Arguments(description = "Remote repository to add")
        public List<String> remote;
    }
}

Assuming you have packaged this as an executable program named 'git', you would be able to execute the following commands:

$ git add -p file

$ git remote add origin [email protected]:airlift/airline.git

$ git -v remote show origin

Single Command Mode

Airline can also be used for simple, single-command programs:

@Command(name = "ping", description = "network test utility")
public class Ping
{
    @Inject
    public HelpOption helpOption;

    @Option(name = {"-c", "--count"}, description = "Send count packets")
    public int count = 1;

    public static void main(String... args)
    {
        Ping ping = SingleCommand.singleCommand(Ping.class).parse(args);

        if (ping.helpOption.showHelpIfRequested()) {
            return;
        }

        ping.run();
    }

    public void run()
    {
        System.out.println("Ping count: " + count);
    }
}

Assuming you have packaged this as an executable program named 'ping', you would be able to execute the following commands:

$ ping

$ ping -c 5

$ ping --help

Help System

Airline contains a fully automated help system, which generates man-page-like documentation driven by the Java annotations.

As you may have noticed in the git code above, we added Help.class to the cli. This command is provided by Airline and works as follows:

$ git help
usage: git [-v] <command> [<args>]

The most commonly used git commands are:
    add       Add file contents to the index
    help      Display help information
    remote    Manage set of tracked repositories

See 'git help <command>' for more information on a specific command.


$ git help git
NAME
        git - the stupid content tracker

SYNOPSIS
        git [-v] <command> [<args>]

OPTIONS
        -v
            Verbose mode

COMMANDS
        help
            Display help information

        add
            Add file contents to the index

        remote show
            Gives some information about the remote <name>

        remote add
            Adds a remote



$ git help add
NAME
        git add - Add file contents to the index

SYNOPSIS
        git [-v] add [-i] [--] [<patterns>...]

OPTIONS
        -i
            Add modified contents interactively.

        -v
            Verbose mode

        --
            This option can be used to separate command-line options from the
            list of argument, (useful when arguments might be mistaken for
            command-line options

        <patterns>
            Patterns of files to be added



$ git help remote
NAME
        git remote - Manage set of tracked repositories

SYNOPSIS
        git [-v] remote
        git [-v] remote add [-t <branch>]
        git [-v] remote show [-n]

OPTIONS
        -v
            Verbose mode

COMMANDS
        With no arguments, Gives some information about the remote <name>

        show
            Gives some information about the remote <name>

            With -n option, Do not query remote heads

        add
            Adds a remote

            With -t option, Track only a specific branch



$ git help remote show
NAME
        git remote show - Gives some information about the remote <name>

SYNOPSIS
        git [-v] remote show [-n] [--] [<remote>]

OPTIONS
        -n
            Do not query remote heads

        -v
            Verbose mode

        --
            This option can be used to separate command-line options from the
            list of argument, (useful when arguments might be mistaken for
            command-line options

        <remote>
            Remote to show

We have also, add Help.class as the default command for git, so if you execute git without any arguments, you will see the following:

$ git help
usage: git [-v] <command> [<args>]

The most commonly used git commands are:
    add       Add file contents to the index
    help      Display help information
    remote    Manage set of tracked repositories

See 'git help <command>' for more information on a specific command.

For simple, single-command programs like ping, use the HelpOption option as shown in the example above. HelpOption handles the options -h and --help and provides the showHelpIfRequested() method to automatically show the following help output:

$ ping -h
NAME
        ping - network test utility

SYNOPSIS
        ping [(-c <count> | --count <count>)] [(-h | --help)]

OPTIONS
        -c <count>, --count <count>
            Send count packets

        -h, --help
            Display help information
Comments
  • update project to airbase

    update project to airbase

    updates to airbase as parent, fixing all the various findbugs, pmd, and license problems. Updated various plugin versions to get above working and current.

    More notably updates to guava 14.01, which didn't need any changes.

    opened by codefromthecrypt 17
  • Add optionEndsValues bool to the @Option annotation

    Add optionEndsValues bool to the @Option annotation

    Add optionEndsValues bool to the @Option annotation to allow for variable length parameter lists. When true, this allows options with arity > 1 to end when a new option is encountered, even if the set arity hasn't been reached.

    opened by Randgalt 8
  • Upgrade to Guava 24.1+

    Upgrade to Guava 24.1+

    Google Guava versions 11.0 through 24.1 are vulnerable to unbounded memory allocation in the AtomicDoubleArray class (when serialized with Java serialization) and Compound Ordering class (when serialized with GWT serialization). An attacker could exploit applications that use Guava and deserialize untrusted data to cause a denial of service. Could you upgrade guava to version 24.1 or above?

    https://github.com/google/guava/wiki/CVE-2018-10237

    opened by brusdev 7
  • Allow mutually exclusive required options

    Allow mutually exclusive required options

    As this option in picocli, it would be nice to have a way to provide mutually exclusive options :

    https://picocli.info/#_mutually_exclusive_options

    I will make a PR for this one

    opened by rguillome 5
  • Does not compile

    Does not compile

    Just forked the project, ran mvn clean install and got the following

    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    objc[85520]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.
    Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
        at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
    Caused by: java.lang.RuntimeException: Class java/util/UUID could not be instrumented.
        at org.jacoco.agent.rt.internal_5d10cad.core.runtime.ModifiedSystemClassRuntime.createFor(ModifiedSystemClassRuntime.java:138)
        at org.jacoco.agent.rt.internal_5d10cad.core.runtime.ModifiedSystemClassRuntime.createFor(ModifiedSystemClassRuntime.java:99)
        at org.jacoco.agent.rt.internal_5d10cad.PreMain.createRuntime(PreMain.java:51)
        at org.jacoco.agent.rt.internal_5d10cad.PreMain.premain(PreMain.java:43)
        ... 6 more
    Caused by: java.lang.NoSuchFieldException: $jacocoAccess
        at java.lang.Class.getField(Class.java:1703)
        at org.jacoco.agent.rt.internal_5d10cad.core.runtime.ModifiedSystemClassRuntime.createFor(ModifiedSystemClassRuntime.java:136)
        ... 9 more
    FATAL ERROR in native method: processing of -javaagent failed
    /bin/sh: line 1: 85520 Abort trap: 6           /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/bin/java -javaagent:/Users/frenaud/.m2/repository/org/jacoco/org.jacoco.agent/0.6.2.201302030002/org.jacoco.agent-0.6.2.201302030002-runtime.jar=destfile=/Users/frenaud/projects/me/airline/target/jacoco.exec -jar /Users/frenaud/projects/me/airline/target/surefire/surefirebooter5947238246567954039.jar /Users/frenaud/projects/me/airline/target/surefire/surefire8523588895070006246tmp /Users/frenaud/projects/me/airline/target/surefire/surefire_04622422368411571876tmp
    
    Results :
    
    Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 4.676 s
    [INFO] Finished at: 2015-10-07T05:05:23-07:00
    [INFO] Final Memory: 22M/383M
    [INFO] ------------------------------------------------------------------------
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.14:test (default-test) on project airline: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.14:test failed: The forked VM terminated without saying properly goodbye. VM crash or System.exit called ?
    [ERROR] Command was/bin/sh -c cd /Users/frenaud/projects/me/airline && /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/bin/java -javaagent:/Users/frenaud/.m2/repository/org/jacoco/org.jacoco.agent/0.6.2.201302030002/org.jacoco.agent-0.6.2.201302030002-runtime.jar=destfile=/Users/frenaud/projects/me/airline/target/jacoco.exec -jar /Users/frenaud/projects/me/airline/target/surefire/surefirebooter5947238246567954039.jar /Users/frenaud/projects/me/airline/target/surefire/surefire8523588895070006246tmp /Users/frenaud/projects/me/airline/target/surefire/surefire_04622422368411571876tmp
    [ERROR] -> [Help 1]
    [ERROR] 
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR] 
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
    

    My java:

    java version "1.8.0_45"
    Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
    Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
    
    opened by fabienrenaud 5
  • Fix Issue #26

    Fix Issue #26

    Modifies Parser so that the allowedValues for an option are honoured and an error thrown on illegal values

    Includes unit test which verifies the improve behaviour

    opened by rvesse 5
  • ParseOptionConversionException is not transporting the cause

    ParseOptionConversionException is not transporting the cause

    I have the following problem: my CLI application has commands accepting an argument, which I provide a class, ClusterID having a constructor taking a String, for parsing and validating the argument.

        @Arguments(required = true, description = "Cluster ID ...")
        public ClusterID cluster;
    

    While this is working fine for the happy case, ClusterID's constructor would raise an exception with a proper message if something has failed.

    I'd like to report that message to the user, but I get an io.airlift.airline.ParseOptionConversionException only, without the cause.

    io.airlift.airline.ParseOptionConversionException: cluster: can not convert "098" to a ClusterID
    	at io.airlift.airline.TypeConverter.convert(TypeConverter.java:78)
    	at io.airlift.airline.Parser.parseArg(Parser.java:265)
    	at io.airlift.airline.Parser.parseArgs(Parser.java:255)
    	at io.airlift.airline.Parser.parse(Parser.java:70)
    	at io.airlift.airline.Cli.parse(Cli.java:121)
    	at io.airlift.airline.Cli.parse(Cli.java:108)
    	at io.airlift.airline.Cli.parse(Cli.java:103)
    	at Main.main(Main.java:53)
    

    I'd appreciate TypeConverter.java#L75 would not ignore the Throwable but pass in on io.airlift.airline.ParseOptionConversionException as cause.

    opened by rtib 2
  • Add @SafeVarargs annotation to Cli.java

    Add @SafeVarargs annotation to Cli.java

    Summary:

    Cli.CliBuilder and Cli.GroupBuilder have

    public CliBuilder<C> withCommands(Class<? extends C> command, Class<? extends C>... moreCommands);
    
    public GroupBuilder<C> withCommands(Class<? extends C> command, Class<? extends C>... moreCommands)
    

    Both of them use the moreCommands array in a typesafe way, which means they could be annotated with @SafeVarargs. They were not, though, which generates unchecked warnings at call sites.

    Note that the methods must be made final for SafeVarargs to be valid.

    A description of SafeVarargs is https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.6.4.7

    Test plan: mvn clean verify passes on 8u141

    opened by jesboat 2
  • Option.allowedValues() does not appear to be respected

    Option.allowedValues() does not appear to be respected

    The Option annotation has a allowedValues() that can be set but this does not appear to actually get honoured by the parser

    The only place this is used is when OptionMetadata is populated by MetadataLoader and then the only place that OptionMetadata.getAllowedValues() is used is in the Parser where it only gets used to display an error message

    opened by rvesse 2
  • Added unit tests for TypeConverter

    Added unit tests for TypeConverter

    These are unit tests I created for all types in TypeConverter. Originally done for a school project, which I feel might be useful to add to the main codebase.

    opened by pprasan 1
  • ParseArgumentsUnexpectedException although following usage

    ParseArgumentsUnexpectedException although following usage

    java -jar app-jar-with-dependencies.jar help a

    NAME
            app a -
    
    SYNOPSIS
            app [(-n <number> | --number <number>)] a
    
    OPTIONS
            -n <number>, --number <number>
    

    java -jar app-jar-with-dependencies.jar a --number 1

    Exception in thread "main" io.airlift.airline.ParseArgumentsUnexpectedException: Found unexpected parameters: [--number, 1]
        at io.airlift.airline.Cli.validate(Cli.java:148)
        at io.airlift.airline.Cli.parse(Cli.java:116)
        at io.airlift.airline.Cli.parse(Cli.java:97)
        at my.App.main(App.java:23)```
    

    Text book example:

    public class App {
    
      public static void main(String[] args) {
        CliBuilder<Runnable> builder = new Cli.CliBuilder<Runnable>("app")
          .withDescription("The app cli")
          .withDefaultCommand(Help.class)
          .withCommands(Help.class, A.class);
    
        Cli<Runnable> parser = builder.build();
        parser.parse(args).run();
      }
    
      public static abstract class Abstract implements Runnable {
    
        @Option(name = {"-n", "--number"}, type = OptionType.GLOBAL)
        public int number;
      }
    
      @Command(name = "a")
      public static final class A extends Abstract {
    
        @Override
        public void run() {
          System.out.println(number);
        }
    
      }
    }
    
    opened by fabienrenaud 1
  • Cli.commandFactory is never used?

    Cli.commandFactory is never used?

    The member variable Cli.commandFactory is never used? Generally, user call the method Cli.parse(String ...), the CommandFactory instance that installed by Cli.CliBuilder.withCommandFactory(factory) should be used instead of create a new one.

    Another optimization point is that you don't have to create a new CommandFactory object every time it's called,CommandFactory instance can be created once on the calling of Cli.CliBuilder.build().

    opened by mayanjun 0
  • group-aware help

    group-aware help

    With

    builder.withGroup("subcommand")
        ....
        .withCommand(Help.class);
    

    running

    x subcommand help
    

    should print subcommand-specific help, just like x help subcommand does.

    This would play nicely when group has .withDefaultCommand(Help.class).

    enhancement 
    opened by findepi 0
  • Information about Inheritance and Composition

    Information about Inheritance and Composition

    I see that part of the documentation is still in TBD. I probably wont need a full fledged documentation, but some hints would be very helpfull.

    I have a number of options that I want to use for several (but not all) commands, and the list of relevant options is different for each command.

    opened by morostr 2
  • Feature Request: Support for Kotlin types

    Feature Request: Support for Kotlin types

    at a minimum just List

    Currently get compile warnings

    w: Main.kt: (53, 16): This class shouldn't be used in Kotlin. Use kotlin.collections.List or kotlin.collections.MutableList instead.

    opened by yschimke 0
  • NPE when running

    NPE when running "help" when argument is marked as hidden

    https://github.com/airlift/airline/blob/0.7/src/main/java/io/airlift/airline/GlobalUsageSummary.java#L67-L69 converts hidden options to nulls.

    That list is used just below that in appendWords which throws a NPE.

    opened by SerialVelocity 0
Owner
null
TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

Emmet Hayes 1 Dec 2, 2022
Annotation-based command framework for Minestom

Minestand Annotation-based command framework for Minestom Advantages over other frameworks Minestand works by converting your classes into Minestom co

null 6 Aug 27, 2022
A command line parser generator

jbock is a command line parser that works similar to airline and picocli. While most of these other tools scan for annotations at runtime, jbock is an

H90 73 Dec 13, 2022
Command-line API for Atlassian JIRA using the Tomitribe CREST library

Atlassian JIRA Command-Line (CLI) Jamira is a command-line API for Atlassian JIRA using the Tomitribe CREST library. Installation Jamira can be downlo

Tomitribe 12 Sep 10, 2022
DeV Tools - Swiss Army Knife of command line utilities

dvt aims to bundle all small utilities used by developers (typically a mix of cli and online tools) into one binary that you can simply use in the console. No need for complex pipe-ing, copy-pasting on different sites or keep installing cli utilities for every need.

Madalin Ilie 13 Sep 15, 2022
AWS JSON TRANSLATOR CLI is a command line application to translate JSON files using AWS Translate

A command line tool to translate JSON files using AWS Translate.

Marc Guillem 0 May 30, 2022
Wrapper around ping command for Windows and MacOS

Wrapper around ping command for Windows and MacOS. Extended with functionality to intercept results provided by the ping command output (latency, ttl and etc.)

Vladislav Kozlov 1 Jan 6, 2022
Java library for creating text-based GUIs

Lanterna Lanterna is a Java library allowing you to write easy semi-graphical user interfaces in a text-only environment, very similar to the C librar

null 2k Dec 31, 2022
Spring based interactive shell

Spring Shell 3 Spring Shell 3 is a work to solely depend on Spring Boot 2.x and not trying to keep any backward compatibility with older Spring Shell

Spring 609 Dec 14, 2022
Jansi is a small java library that allows you to use ANSI escape sequences to format your console output which works even on windows.

Description Jansi is a small java library that allows you to use ANSI escape codes to format your console output which works even on Windows. It also

FuseSource 955 Dec 28, 2022
ASCII renderer in pure java with no external dependencies

Java ASCII Render ASCII renderer in pure java with no external dependencies. Java ASCII Render supports graphical primitives/elements, layers, context

David E. Veliev 140 Dec 12, 2022
JLine is a Java library for handling console input.

JLine JLine is a Java library for handling console input. It is similar in functionality to BSD editline and GNU readline but with additional features

null 1.2k Jan 5, 2023
A library for creating interactive console applications in Java

Text-IO Text-IO is a library for creating Java console applications. It can be used in applications that need to read interactive input from the user.

Beryx 295 Jan 5, 2023
Yet another Java annotation-based command parsing library, with Dependency Injection inspired by Guice

Commander A universal java command parsing library Building This project uses Gradle. Clone this repository: git clone https://github.com/OctoPvP/Comm

OctoDev 4 Oct 2, 2022
Command line parsing framework for Java

JCommander This is an annotation based parameter parsing framework for Java 8. Here is a quick example: public class JCommanderTest { @Parameter

Cedric Beust 1.8k Dec 29, 2022
Annotation/Reflection Based Bukkit Command API. Containing many features such as help-service, command providers, tab completion, and many more!

CommandAPI Annotation/Reflection Based Command API that just does what you want it to do without any problems. Importing Maven <repository> <id>

damt 1 Jun 13, 2022
TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

TransitScheduler - a command line tool that can read .json data formulated for tracking transit patterns to a multithreaded concurrent simulation of passengers boarding and unboarding trains that constantly move to the next station on the line. The trick here, is that two trains cannot occupy the same station at any time.

Emmet Hayes 1 Dec 2, 2022
An intelliJ plugin providing a UI layer for git-flow, which in itself is a collection of Git extensions to provide high-level repository operations for Vincent Driessen's branching model.

Git Flow Integration Plus for Intellij An intelliJ plugin providing a UI layer for git-flow, which in itself is a collection of Git extensions to prov

RubinCarter 35 Nov 8, 2022