Coder Social home page Coder Social logo

nailanawshaba / picocli-spring-boot-starter Goto Github PK

View Code? Open in Web Editor NEW

This project forked from kakawait/picocli-spring-boot-starter

0.0 1.0 0.0 39 KB

Spring boot starter for Picocli command line parser that will simplify your CommandLineRunner

License: MIT License

Java 100.00%

picocli-spring-boot-starter's Introduction

Spring boot Picocli starter

Travis SonarQube Coverage Maven Central license Twitter Follow

A Spring boot starter for Picocli command line tools. That let you easily write CLI for Spring boot application!

Features

  • Automatic integration with Spring CommandLineRunner
  • Automatic @Command beans registration
  • Display usage on help
  • Automatically run @Command if it implements java.lang.Runnable or java.lang.Callable
  • Flow control using java.lang.Callable and ExitStatus
  • Advance configuration through PicocliConfigurerAdapter

Setup

Add the Spring boot starter to your project

<dependency>
  <groupId>com.kakawait</groupId>
  <artifactId>picocli-spring-boot-starter</artifactId>
  <version>0.2.0</version>
</dependency>

Usage

There is multiple ways to define a new picocli commands.

You should start looking sample application to get more advance sample.

@Command beans

First and simplest way, is to register a new bean with @Command annotation inside your Spring context, example:

@Component
@Command(name = "greeting")
class GreetingCommand implements Runnable {

    @Parameters(paramLabel = "NAME", description = "name", arity = "0..1")
    String name;

    @Override
    public void run() {
        if (StringUtils.hasText(name)) {
            System.out.println("Hello " + name + "!");
        } else {
            System.out.println("Hello world!");
        }
    }
}

Your bean can implements Runnable or Callable<ExitStatus> (in order to control flow) or extends PicocliCommand or HelpAwarePicocliCommand (to magically have -h/--help option to display usage) if you need to execute something when command is called.

In addition, for advance usage PicocliCommand let you get access to

/**
 * Returns result of {@link CommandLine#parse(String...)}.
 * @return Picocli parsing result which results on collection of every command involve regarding your input.
 */
protected List<CommandLine> getParsedCommands() {
    return parsedCommands;
}

/**
 * Returns the current {@link CommandLine}.
 * @return current {@link CommandLine} context
 */
protected CommandLine getContext() {
    return context;
}

/**
 * Returns the root {@link CommandLine}.
 * @return root {@link CommandLine} context that must contains (or equals) the {@link #getContext()}.
 */
protected CommandLine getRootContext() {
    return rootContext;
}

That might be useful.

Main command using beans

Picocli is waiting for a Main command, cf: new CommandLine(mainCommand). To determine which @Command beans will be the Main command, starter will apply the following logic:

Main command will be the first @Command (if multiple found) bean with default name argument.

For example

@Command
class MainCommand {}

or

@Command(description = "main command")
class MainCommand {}

But the following example will not be candidate for Main command

@Command(name = "my_command")
class MainCommand {}

Nested sub-commands using beans

Picocli allows nested sub-commands, in order to describe a nested sub-command, starter is offering you nested classes scanning capability.

That means, if you're defining bean structure like following:

@Component
@Command(name = "flyway")
class FlywayCommand extends HelpAwareContainerPicocliCommand {

    @Component
    @Command(name = "migrate")
    class MigrateCommand implements Runnable {

        private final Flyway flyway;

        public MigrateCommand(Flyway flyway) {
            this.flyway = flyway;
        }

        @Override
        public void run() {
            flyway.migrate();
        }
    }

    @Component
    @Command(name = "repair")
    class RepairCommand implements Runnable {
        private final Flyway flyway;

        public RepairCommand(Flyway flyway) {
            this.flyway = flyway;
        }

        @Override
        public void run() {
            flyway.repair();
        }
    }
}

Will generate command line

Commands:
   flyway [-h, --help]
     migrate
     repair

Thus java -jar <name>.jar flyway migrate will execute Flyway migration.

ATTENTION every classes must be a bean (@Component) with @Command annotation without forgetting to file name attribute.

There is no limitation about nesting level.

Additional configuration

If you need to set additional configuration options simply register within Spring application context instance of PicocliConfigurerAdapter

@Configuration
class CustomPicocliConfiguration extends PicocliConfigurerAdapter {
    @Override
    public void configure(CommandLine commandLine) {
        // Here you can configure Picocli commandLine
        // You can add additional sub-commands or register converters.
    }
}

Otherwise you can define your own bean CommandLine but attention that will disable automatic @Command bean registration explained above.

Exit status

If you defined following command line:

@Component
@Command
class MainCommand extends HelpAwarePicocliCommand {
    @Option(names = {"-v", "--version"}, description = "display version info")
    boolean versionRequested;

    @Override
    public void run() {
        if (versionRequested) {
            System.out.println("0.1.0");
        }
    }
}

@Component
@Command(name = "greeting")
static class GreetingCommand extends HelpAwarePicocliCommand {

    @Parameters(paramLabel = "NAME", description = "name", arity = "0..1")
    String name;

    @Override
    public void run() {
        if (StringUtils.hasText(name)) {
            System.out.println("Hello " + name + "!");
        } else {
            System.out.println("Hello world!");
        }
    }
}

And you execute java -jar <name>.jar -v greeting Thibaud the output will looks like:

0.1.0
Hello Thibaud!

While you wanted that -v will break execution and other involved commands not executed. To achieve that you must replace run() method with ExitStatus call().

@Component
@Command
class MainCommand extends HelpAwarePicocliCommand {
    @Option(names = {"-v", "--version"}, description = "display version info")
    boolean versionRequested;

    @Override
    public ExitStatus call() {
        if (versionRequested) {
            System.out.println("0.1.0");
            return ExitStatus.TERMINATION;
        }
        return ExitStatus.OK;
    }
}

The main difference is ExitStatus.TERMINATION that will tell the starter to stop other executions. (ExitStatus.OK is default status).

Help & usage

Picocli documentation and principle about help argument is not exactly the same on this starter.

Indeed Picocli only consider option with help argument like following:

if one of the command line arguments is a "help" option, picocli will stop parsing the remaining arguments and will not check for required options.

While this starter in addition will force displaying usage if help was requested.

Thus following example from Picocli documentation:

@Option(names = {"-V", "--version"}, help = true, description = "display version info")
boolean versionRequested;

@Option(names = {"-h", "--help"}, help = true, description = "display this help message")
boolean helpRequested;

If you run program with -V or --version that will display usage and stop execution. It may not what you need. Thus you have to think about help argument is to displaying usage and stop execution.

Following example is much more starter compliant:

@Option(names = {"-V", "--version"}, help = false, description = "display version info")
boolean versionRequested;

@Option(names = {"-h", "--help"}, help = true, description = "display this help message")
boolean helpRequested;

License

MIT License

picocli-spring-boot-starter's People

Contributors

kakawait avatar

Watchers

James Cloos avatar

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.