Git Product home page Git Product logo

airline's Issues

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)

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

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)

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.

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.

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.

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

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

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.

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.

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

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

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.

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.

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

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.

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

  }
}

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

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.

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.

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)

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.