Skip to content

Commit

Permalink
Wrap CLI Options API to avoid direct dependency on JOpt lib in comma…
Browse files Browse the repository at this point in the history
…nds #17
  • Loading branch information
andrus committed Jan 26, 2016
1 parent 27cf684 commit 89a4eea
Show file tree
Hide file tree
Showing 19 changed files with 263 additions and 125 deletions.
12 changes: 8 additions & 4 deletions RELEASE-NOTES.txt
@@ -1,19 +1,23 @@
0.11
0.12:

#17 Wrap CLI Options API to avoid direct dependency on JOpt lib in commands

0.11:

#8 Remove API's deprecated since 0.10
#10 Service shutdown functionality

0.10
0.10:

#5 FactoryConfigurationService refactoring
#6 Service/Module override support
#7 Start publishing Bootique to Maven central repo

0.9
0.9:

#4 FactoryConfigurationService - support for loading parameterized types

0.8
0.8:

#1 Merge bundles and modules into a single concept
#2 Auto-load extensions
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/com/nhl/bootique/BQCoreModule.java
Expand Up @@ -7,6 +7,7 @@
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.nhl.bootique.cli.Options;
import com.nhl.bootique.command.Command;
import com.nhl.bootique.command.ConfigCommand;
import com.nhl.bootique.command.DefaultCommand;
Expand All @@ -22,8 +23,7 @@
import com.nhl.bootique.jackson.DefaultJacksonService;
import com.nhl.bootique.jackson.JacksonService;
import com.nhl.bootique.jopt.Args;
import com.nhl.bootique.jopt.Options;
import com.nhl.bootique.jopt.OptionsProvider;
import com.nhl.bootique.jopt.JoptOptionsProvider;
import com.nhl.bootique.log.BootLogger;
import com.nhl.bootique.run.DefaultRunner;
import com.nhl.bootique.run.Runner;
Expand Down Expand Up @@ -52,7 +52,7 @@ public void configure(Binder binder) {
binder.bind(Runner.class).to(DefaultRunner.class).in(Singleton.class);
binder.bind(ShutdownManager.class).to(DefaultShutdownManager.class).in(Singleton.class);
binder.bind(Duration.class).annotatedWith(ShutdownTimeout.class).toInstance(shutdownTimeout);
binder.bind(Options.class).toProvider(OptionsProvider.class).in(Singleton.class);
binder.bind(Options.class).toProvider(JoptOptionsProvider.class).in(Singleton.class);
binder.bind(ConfigurationSource.class).to(CliConfigurationSource.class).in(Singleton.class);

binder.bind(ConfigurationFactory.class).to(YamlConfigurationFactory.class).in(Singleton.class);
Expand All @@ -68,6 +68,7 @@ public void configure(Binder binder) {
}

@Provides
@Singleton
public Environment createEnvironment(@EnvironmentProperties Map<String, String> diProperties) {
return new DefaultEnvironment(diProperties);
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/nhl/bootique/cli/OptionBuilder.java
@@ -0,0 +1,11 @@
package com.nhl.bootique.cli;

/**
* @since 0.12
*/
public interface OptionBuilder {

OptionBuilder requiresArgument(String description);

OptionBuilder mayTakeArgument(String description);
}
26 changes: 26 additions & 0 deletions src/main/java/com/nhl/bootique/cli/Options.java
@@ -0,0 +1,26 @@
package com.nhl.bootique.cli;

import java.io.Writer;
import java.util.Collection;

/**
* An object that represents a set of command line options passed to Booqtie
* app.
*
* @since 0.12
*/
public interface Options {

void printHelp(Writer out);

boolean hasOption(String name);

/**
* Returns a collection of String values for the specified option name.
*
* @param name
* option name
* @return a potentially empty collection of CLI values for a given option.
*/
Collection<String> stringsFor(String name);
}
11 changes: 11 additions & 0 deletions src/main/java/com/nhl/bootique/cli/OptionsBuilder.java
@@ -0,0 +1,11 @@
package com.nhl.bootique.cli;

/**
* @since 0.12
*/
public interface OptionsBuilder {

OptionBuilder add(String option, String description);

OptionBuilder addHelp(String option, String description);
}
13 changes: 6 additions & 7 deletions src/main/java/com/nhl/bootique/command/Command.java
@@ -1,8 +1,7 @@
package com.nhl.bootique.command;

import com.nhl.bootique.jopt.Options;

import joptsimple.OptionParser;
import com.nhl.bootique.cli.OptionsBuilder;
import com.nhl.bootique.cli.Options;

@FunctionalInterface
public interface Command {
Expand All @@ -15,17 +14,17 @@ public interface Command {
* @return CommandOutcome object that indicates to the caller whether
* command was successful and whether the caller needs to continue
* with command chain.
* @since 1.12
*/
CommandOutcome run(Options options);

/**
* Allows subclasses to configure visible CLI options.
*
* @param parser
* a mutable CLI parser that stores supported command line
* options.
* @param optionsBuilder
* a mutable builder of options for a given command.
*/
default void configOptions(OptionParser parser) {
default void configOptions(OptionsBuilder optionsBuilder) {
// do nothing by default...
}
}
21 changes: 4 additions & 17 deletions src/main/java/com/nhl/bootique/command/ConfigCommand.java
@@ -1,11 +1,7 @@
package com.nhl.bootique.command;

import java.util.Map;

import com.nhl.bootique.jopt.Options;

import joptsimple.OptionParser;
import joptsimple.OptionSpec;
import com.nhl.bootique.cli.Options;
import com.nhl.bootique.cli.OptionsBuilder;

public class ConfigCommand implements Command {

Expand All @@ -17,16 +13,7 @@ public CommandOutcome run(Options options) {
}

@Override
public void configOptions(OptionParser parser) {

// install framework options unless they are already defined...

Map<String, OptionSpec<?>> existing = parser.recognizedOptions();

if (!existing.containsKey(CONFIG_OPTION)) {
parser.accepts(CONFIG_OPTION, "Specifies YAML config file path.").withRequiredArg()
.describedAs("config_file");
}

public void configOptions(OptionsBuilder optionsBuilder) {
optionsBuilder.add(CONFIG_OPTION, "Specifies YAML config file path.").requiresArgument("config_file");
}
}
@@ -1,7 +1,7 @@
package com.nhl.bootique.command;

import com.google.inject.Inject;
import com.nhl.bootique.jopt.Options;
import com.nhl.bootique.cli.Options;
import com.nhl.bootique.log.BootLogger;

/**
Expand Down
27 changes: 6 additions & 21 deletions src/main/java/com/nhl/bootique/command/HelpCommand.java
@@ -1,16 +1,12 @@
package com.nhl.bootique.command;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

import com.google.inject.Inject;
import com.nhl.bootique.jopt.Options;
import com.nhl.bootique.cli.Options;
import com.nhl.bootique.cli.OptionsBuilder;
import com.nhl.bootique.log.BootLogger;

import joptsimple.OptionParser;
import joptsimple.OptionSpec;

public class HelpCommand implements Command {

protected static final String HELP_OPTION = "help";
Expand All @@ -24,31 +20,20 @@ public HelpCommand(BootLogger bootLogger) {

@Override
public CommandOutcome run(Options options) {
return options.getOptionSet().has(HELP_OPTION) ? printHelp(options) : CommandOutcome.skipped();
return options.hasOption(HELP_OPTION) ? printHelp(options) : CommandOutcome.skipped();
}

protected CommandOutcome printHelp(Options options) {
StringWriter out = new StringWriter();

try {
options.getParser().printHelpOn(out);
} catch (IOException e) {
bootLogger.stderr("Error printing help", e);
}
options.printHelp(out);

bootLogger.stdout(out.toString());
return CommandOutcome.succeeded();
}

@Override
public void configOptions(OptionParser parser) {

// install framework options unless they are already defined...
Map<String, OptionSpec<?>> existing = parser.recognizedOptions();

if (!existing.containsKey(HELP_OPTION)) {
parser.accepts(HELP_OPTION, "Prints this message.").forHelp();
}
public void configOptions(OptionsBuilder optionsBuilder) {
optionsBuilder.addHelp(HELP_OPTION, "Prints this message.");
}

}
@@ -1,6 +1,6 @@
package com.nhl.bootique.command;

import com.nhl.bootique.jopt.Options;
import com.nhl.bootique.cli.Options;

public abstract class OptionTriggeredCommand implements Command {

Expand All @@ -10,7 +10,7 @@ public final CommandOutcome run(Options options) {
}

protected boolean hasOption(Options options) {
return options.getOptionSet().has(getOption());
return options.hasOption(getOption());
}

protected abstract CommandOutcome doRun(Options options);
Expand Down
Expand Up @@ -8,8 +8,8 @@
import java.util.function.Function;

import com.google.inject.Inject;
import com.nhl.bootique.cli.Options;
import com.nhl.bootique.command.ConfigCommand;
import com.nhl.bootique.jopt.Options;
import com.nhl.bootique.log.BootLogger;

/**
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/nhl/bootique/jopt/JoptOptionBuilder.java
@@ -0,0 +1,30 @@
package com.nhl.bootique.jopt;

import com.nhl.bootique.cli.OptionBuilder;

import joptsimple.OptionSpecBuilder;

/**
* @since 0.12
*/
class JoptOptionBuilder implements OptionBuilder {

private OptionSpecBuilder optionSpecBuilder;

JoptOptionBuilder(OptionSpecBuilder optionSpecBuilder) {
this.optionSpecBuilder = optionSpecBuilder;
}

@Override
public OptionBuilder mayTakeArgument(String description) {
optionSpecBuilder.withOptionalArg().describedAs(description);
return this;
}

@Override
public OptionBuilder requiresArgument(String description) {
optionSpecBuilder.withRequiredArg().describedAs(description);
return this;
}

}
48 changes: 48 additions & 0 deletions src/main/java/com/nhl/bootique/jopt/JoptOptions.java
@@ -0,0 +1,48 @@
package com.nhl.bootique.jopt;

import static java.util.stream.Collectors.toList;

import java.io.IOException;
import java.io.Writer;
import java.util.Collection;

import com.nhl.bootique.cli.Options;
import com.nhl.bootique.log.BootLogger;

import joptsimple.OptionParser;
import joptsimple.OptionSet;

/**
* A facade to the command-line option parsing framework.
*/
public class JoptOptions implements Options {

private OptionParser parser;
private OptionSet optionSet;
private BootLogger bootLogger;

public JoptOptions(BootLogger bootLogger, OptionParser parser, OptionSet parsed) {
this.parser = parser;
this.optionSet = parsed;
this.bootLogger = bootLogger;
}

@Override
public void printHelp(Writer out) {
try {
parser.printHelpOn(out);
} catch (IOException e) {
bootLogger.stderr("Error printing help", e);
}
}

@Override
public boolean hasOption(String optionName) {
return optionSet.has(optionName);
}

@Override
public Collection<String> stringsFor(String optionName) {
return optionSet.valuesOf(optionName).stream().map(o -> String.valueOf(o)).collect(toList());
}
}

0 comments on commit 89a4eea

Please sign in to comment.