Git Product home page Git Product logo

airline's Introduction

⚠️ DEPRECATED ⚠️

This project is no longer maintained. We recommend Airline 2 or Picocli as a replacement.

Airline

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

Latest release is 0.9, available from Maven Central.

<dependency>
    <groupId>io.airlift</groupId>
    <artifactId>airline</artifactId>
    <version>0.9</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

airline's People

Contributors

cheddar avatar dain avatar dmarchignoli avatar electrum avatar findepi avatar jesboat avatar johngmyers avatar martint avatar novanic avatar parambirs avatar pprasan avatar rtib avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

airline's Issues

Automatically show help when user types invalid command?

When the user enters a command that doesn't exist (e.g. mis-typed a command), an exception is thrown.

Exception in thread "main" io.airlift.airline.ParseArgumentsUnexpectedException: Found unexpected parameters: [blah, something]
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)

Since the end-user mistyping a command is an obvious use case, I'm assuming I've done something wrong. I've set Help as the default command, but I guess that isn't it.

    Cli.CliBuilder<Runnable> builder = Cli.<Runnable>builder("muse")
        .withDescription("Muse command-line tools")
        .withDefaultCommand(Help.class)
        .withCommands(Help.class)
        .withCommands(implementors);
    Cli<Runnable> muse_parser = builder.build();
    muse_parser.parse(args).run();

My fix thus far is to catch the exception and run the Help command by re-parsing an empty command line. That seems like a hack. new Help().run() threw an exception, too, so that wasn't any better.

I feel like I'm missing an obvious solution, since none of the examples include catching an exception.

TIA!
Chris

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.

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

Interactive command line

I can't use airline to build a personal interactive command line, can I?
Classic example of such:

php -a;
python;
mysql;

Then you type all the commands within and it works.

I know it doesn't make sense for all the applications which provide an interactive terminal, but it would be very convenient for the ones that just want to be a subset of what terminal commands are...

Edit: less than 1 minute later after writing this post, i re-read the README and i believe this is actually possible. :) (and -_- on me)
Will confirm soon.

Support sub-groups

git-flow is a nice add-on to git, which uses sub-groups or chains of groups, for example, you can do something like git flow feature start newFeatureName or git flow release finish theReleaseName

I think having these sub groups or chains of groups together makes for a natural CLI, but does not seem to be possible as Cli assumes there is only top level groups -- Cli.withGroup produces a GroupBuilder which itself does not allow another group.

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

Conflicting arguments, although they don't conflict

I have a command with two arguments:

@Arguments( title = "recordType", description = "Record type", required = true )
public String recordType;

@Arguments( title = "id", description = "Record id", required = true )
public long id;

when building a CLI for that command I get exception:

java.lang.IllegalArgumentException: Conflicting arguments definitions: ArgumentsMetadata{title='recordType', description='Record type', usage='', required=true, accessors=[DumpPropertyChain.recordType]}, ArgumentsMetadata{title='id', description='Record id', usage='', required=true, accessors=[DumpPropertyChain.id]}
    at com.google.common.base.Preconditions.checkArgument(Preconditions.java:145)
    at io.airlift.airline.model.ArgumentsMetadata.<init>(ArgumentsMetadata.java:48)
    at io.airlift.airline.model.MetadataLoader$InjectionMetadata.compact(MetadataLoader.java:257)
    at io.airlift.airline.model.MetadataLoader$InjectionMetadata.access$600(MetadataLoader.java:242)
    at io.airlift.airline.model.MetadataLoader.loadInjectionMetadata(MetadataLoader.java:112)
    at io.airlift.airline.model.MetadataLoader.loadCommand(MetadataLoader.java:86)
    at io.airlift.airline.model.MetadataLoader$1.apply(MetadataLoader.java:70)
    at io.airlift.airline.model.MetadataLoader$1.apply(MetadataLoader.java:67)
    at com.google.common.collect.Iterators$8.transform(Iterators.java:799)
    at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:48)
    at com.google.common.collect.ImmutableCollection$Builder.addAll(ImmutableCollection.java:301)
    at com.google.common.collect.ImmutableList$Builder.addAll(ImmutableList.java:691)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:275)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:226)
    at io.airlift.airline.model.MetadataLoader.loadCommands(MetadataLoader.java:66)
    at io.airlift.airline.Cli.<init>(Cli.java:77)
    at io.airlift.airline.Cli.<init>(Cli.java:40)
    at io.airlift.airline.Cli$CliBuilder.build(Cli.java:246)
    ...

The two arguments doesn't conflict. Instead this looks to be an issue at https://github.com/airlift/airline/blob/master/src/main/java/io/airlift/airline/model/ArgumentsMetadata.java#L48 where that condition looks to be negated... i.e. it will always report conflict if there are more than one argument defined.

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.

Help class NPE

So far this is all I have. Will update with more details / simpler reproducable example

public static void main(String[] args) throws Exception {
Cli.CliBuilder builder = Cli.builder("hio")
.withDefaultCommand(Help.class)
.withCommands(Help.class,
InputBenchmarkCmd.class,
TailerCmd.class,
ConfOptionsCmd.class);
Cli cli = builder.build();
cli.parse(args).run();
}

nitayj@nitay-fb hive-io-3 (h3|● 6✚ 36) $ java -jar hive-io-exp-cmdline/target/hive-io-exp-cmdline-0.8-SNAPSHOT-jar-with-dependencies.jar help
Exception in thread "main" java.lang.NullPointerException
at io.airlift.command.UsagePrinter.appendWords(UsagePrinter.java:105)
at io.airlift.command.GlobalUsageSummary.usage(GlobalUsageSummary.java:73)
at io.airlift.command.GlobalUsageSummary.usage(GlobalUsageSummary.java:52)
at io.airlift.command.Help.help(Help.java:45)
at io.airlift.command.Help.help(Help.java:38)
at io.airlift.command.Help.run(Help.java:25)
at com.facebook.hiveio.cmdline.Main.main(Main.java:34)

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.

Support named positional arguments

There should be a way to specify that exactly two arguments are required:

git remote add <name> <url>

Currently, this must be done as List<String>, which requires the user code to do the min/max checking, and doesn't allowing mixed types, such as String and URI.

NPE when group has no default command

builder.withGroup("foo")
    .withDefaultCommand(SomeCommand.class)    // <--- NPE if this line is missing
    .withCommands(SomeCommand.class);
Exception in thread "main" java.lang.NullPointerException
    at io.airlift.command.model.MetadataLoader.loadCommand(MetadataLoader.java:79)
    at io.airlift.command.Cli$1.apply(Cli.java:83)
    at io.airlift.command.Cli$1.apply(Cli.java:80)
    at com.google.common.collect.Iterators$8.transform(Iterators.java:860)
    at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:48)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:266)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:223)
    at io.airlift.command.Cli.<init>(Cli.java:79)
    at io.airlift.command.Cli.<init>(Cli.java:40)
    at io.airlift.command.Cli$CliBuilder.build(Cli.java:243)

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);
    }

  }
}

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().

Show help when missing a required parameter

When I call "command --help" when missing a required parameter specified with required=true, all I see is a stacktrace like this:

Exception in thread "main" io.airlift.command.ParseOptionMissingException:
 Required option '-rev' is missing

When specifying the help parameter the help should be displayed no matter if required parameters are missing or not.

I used the code shown on the readme page:

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

  // cancel further processing if help is displayed
  if (command.help.showHelpIfRequested()) {
    return;
  }

  command.run();
}

The exception is thrown in the parse() method naturally. Because the Help can only be triggered AFTER the command object is created, I cannot show the help if required parameters are missing. Is there an existing solution to this?

Regards,
Tom

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)

help to include allowedValues, and respect multi-line descriptions

Part one...

I have an option where I define allowed values, but help doesn't show what those allowed values are.

    @Option(name = { "--persist" }, allowedValues = { "disabled", "auto", "rebind", "clean" }, title = "persistance mode", description = "The persistence mode.")

Help just shows:

    --persist <persistance mode>
        The persistence mode.

Part two...

I want to include in the description what each of these allowed values means. It looks like my only option is to include that in description, so I wrote the following code:

    @Option(name = { "--persist" }, allowedValues = { "disabled", "auto", "rebind", "clean" },
            title = "persistance mode",
            description = "The persistence mode. Possible values are:\n"+
                    "disabled: will not read or persist any state; \n"+
                    "auto: will rebind to any existing state, or start up fresh if no state; \n"+
                    "rebind: will rebind to the existing state, or fail if no state available; \n"+
                    "clean: will start up fresh (not using any existing state)")

However, this discarded my new-line characters to just split the lines at 79 characters, wherever that happened to occur (presumably due to the code in https://github.com/airlift/airline/blob/master/src/main/java/io/airlift/airline/UsagePrinter.java append).

    --persist <persistance mode>
        The persistence mode. Possible values are: disabled: will not read
        or persist any state; auto: will rebind to any existing state, or
        start up fresh if no state; rebind: will rebind to any existing
        state, or fail if no state available; clean: will start up fresh
        (not using any existing state)

Note I can't work around this by padding the lines with spaces, because UsagePrinter. append has split on white space, trimming each word.

Improve error messages on bad command

I just ran

java_stuff server overlord

and got

Exception in thread "main" io.airlift.command.ParseArgumentsUnexpectedException: Found unexpected parameters: [overlord]
    at io.airlift.command.Cli.validate(Cli.java:148)
    at io.airlift.command.Cli.parse(Cli.java:116)
    at io.airlift.command.Cli.parse(Cli.java:97)
    at io.druid.cli.Main.main(Main.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Which is a pretty poor error message for a user to see. Something like, "server overlord is unknown, known options are XXX" would be what I would like users to see.

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).

add optional example & discussion sections to the commands

Having a discussion section for a longer explanation of the functionality of the command, or related, but not required information, might be useful in some cases. Try "git help remote" for an example of this.

Further, having a section of example command invocations would be very help for many users.

Add support for char type

Add char to TypeConverter.convert

This should check or a string of length 1 or a standard Java escaped character (e.g., '\t', '\n') including unicode escapes ('a' is '\u0061')

Dependency on guava

Thanks a lot for the library.
Surprisingly there aren't many java CLI libraries designed for usage for commands with parameters. IMHO this is the best one.

The only disadvantage I found is dependency on guava:

  • for tiny projects it fills wrong to add 2Mb guava jar just for CLI
  • "enterprise" projects will usually have dependency on guava already, but not necessarily the same version as airline

Do you think it makes sense to copy into project only those guava bits which are used?
I could do this myself, just wanted to ask your opinion.

--help breaks when using required options when using singleCommand()

If I have:

@Option(name = { "--sourceIndexes"}, description = "Source indexes to read from.", required = true)
public List<String> sourceIndexes;

and then do --help it tells me:

io.airlift.airline.ParseOptionMissingException: Required option '--targetIndex' is missing

... but if I remove required=true

I'll get the proper help output.

which is not fun because for our use case this breaks airline. Though I might see if I can work around this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.