Skip to content

Commit

Permalink
Config CLI options #111
Browse files Browse the repository at this point in the history
* javadocs
* renaming 'configFile' to 'configResource'
  • Loading branch information
andrus committed Aug 19, 2017
1 parent 8bd3a1b commit 51e3308
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 26 deletions.
27 changes: 16 additions & 11 deletions bootique/src/main/java/io/bootique/BQCoreModuleExtender.java
Expand Up @@ -170,10 +170,11 @@ public BQCoreModuleExtender addOptions(OptionMetadata... options) {
}

/**
* Alias the CLI option value to a config path.
* Associates the CLI option with a config path. The option runtime value is assigned to the configuration property
* denoted by the path.
*
* @param configPath a dot-separated "path" that navigates through the configuration tree to the property that
* should be bound from an option. E.g. "jdbc.myds.password".
* @param configPath a dot-separated "path" that navigates configuration tree to the desired property. E.g.
* "jdbc.myds.password".
* @param name alias of an option
* @return this extender instance
* @since 0.24
Expand All @@ -188,10 +189,12 @@ public BQCoreModuleExtender addOption(String configPath, String name) {
}

/**
* Alias the CLI option value to a config path.
* Associates the CLI option with a config path. The option runtime value is assigned to the configuration property
* denoted by the path. Default value provided here will be used if the option is present, but no value is specified
* on the command line.
*
* @param configPath a dot-separated "path" that navigates through the configuration tree to the property that
* should be bound from an option. E.g. "jdbc.myds.password".
* @param configPath a dot-separated "path" that navigates configuration tree to the desired property. E.g.
* "jdbc.myds.password".
* @param defaultValue default option value
* @param name alias of an option
* @return this extender instance
Expand All @@ -208,17 +211,19 @@ public BQCoreModuleExtender addOption(String configPath, String defaultValue, St
}

/**
* Alias the CLI option value to a YAML file with config paths.
* Associates the CLI option value with a config resource. This way a single option can be used to enable a complex
* configuration.
*
* @param configFilePath path on file with config
* @param name alias of an option
* @param configResourceId a resource path compatible with {@link io.bootique.resource.ResourceFactory} denoting
* a configuration source. E.g. "a/b/my.yml", or "classpath:com/foo/another.yml".
* @param name alias of an option
* @return this extender instance
* @since 0.24
*/
public BQCoreModuleExtender addConfigFileOption(String configFilePath, String name) {
public BQCoreModuleExtender addConfigResourceOption(String configResourceId, String name) {
contributeOptions().addBinding().toInstance(
OptionMetadata.builder(name)
.configFilePath(configFilePath)
.configResource(configResourceId)
.valueOptional()
.build());
return this;
Expand Down
Expand Up @@ -21,16 +21,15 @@
import io.bootique.jackson.JacksonService;
import io.bootique.log.BootLogger;
import io.bootique.meta.application.OptionMetadata;
import io.bootique.resource.ResourceFactory;
import joptsimple.OptionSpec;

import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;
import java.util.Set;
import java.util.function.BinaryOperator;
Expand Down Expand Up @@ -84,6 +83,7 @@ protected JsonNode loadConfiguration(Map<String, String> properties, Map<String,
//options tied to config paths
HashMap<String, String> options = new HashMap<>();
for (OptionSpec<?> cliOpt : cli.detectedOptions()) {

options.putAll(optionMetadataSet.stream()
.filter(o -> o.getConfigPath() != null && cliOpt.options().contains(o.getName()))
.collect(Collectors.toMap(o -> o.getConfigPath(), o -> {
Expand All @@ -101,9 +101,8 @@ protected JsonNode loadConfiguration(Map<String, String> properties, Map<String,
List<URL> sources = new ArrayList<>();
for (OptionSpec<?> cliOpt : cli.detectedOptions()) {
List<URL> collect = optionMetadataSet.stream()
.filter(o -> o.getConfigFilePath() != null
&& cliOpt.options().contains(o.getName()))
.map(o -> new ResourceFactory(o.getConfigFilePath()).getUrl())
.filter(o -> o.getConfigResource() != null && cliOpt.options().contains(o.getName()))
.map(o -> o.getConfigResource().getUrl())
.collect(Collectors.toList());

sources.addAll(collect);
Expand Down
@@ -1,6 +1,9 @@
package io.bootique.meta.application;

import io.bootique.meta.MetadataNode;
import io.bootique.resource.ResourceFactory;

import java.util.Objects;

/**
* A descriptor of a command-line option.
Expand All @@ -15,7 +18,7 @@ public class OptionMetadata implements MetadataNode {
private OptionValueCardinality valueCardinality;
private String valueName;
private String configPath;
private String configFilePath;
private ResourceFactory configResource;
private String defaultValue;

public static Builder builder(String name) {
Expand Down Expand Up @@ -52,14 +55,34 @@ public String getValueName() {
return valueName;
}

/**
* Returns an optional configuration path associated with this option.
*
* @return null or a dot-separated "path" that navigates configuration tree to the property associated with this
* option. E.g. "jdbc.myds.password".
* @since 0.24
*/
public String getConfigPath() {
return configPath;
}

public String getConfigFilePath() {
return configFilePath;
/**
* Returns an optional resource associated with this option.
*
* @return an optional resource associated with this option.
* @since 0.24
*/
public ResourceFactory getConfigResource() {
return configResource;
}

/**
* Returns the default value for this option. I.e. the value that will be used if the option is provided on
* command line without an explicit value.
*
* @return the default value for this option.
* @since 0.24
*/
public String getDefaultValue() {
return defaultValue;
}
Expand Down Expand Up @@ -113,18 +136,43 @@ public Builder valueOptional(String valueName) {
return this;
}

/**
* Sets the configuration property path that should be associated to this option value.
*
* @param configPath a dot-separated "path" that navigates configuration tree to the desired property. E.g.
* "jdbc.myds.password".
* @return this builder instance
* @since 0.24
*/
public Builder configPath(String configPath) {
this.option.configPath = configPath;
this.option.configPath = Objects.requireNonNull(configPath);
this.option.configResource = null;
return this;
}

/**
* Sets the default value for this option.
*
* @param defaultValue a default value for the option.
* @return this builder instance
* @since 0.24
*/
public Builder defaultValue(String defaultValue) {
this.option.defaultValue = defaultValue;
return this;
}

public Builder configFilePath(String configFilePath) {
this.option.configFilePath = configFilePath;
/**
* Sets the config resource associated with this option.
*
* @param configResourceId a resource path compatible with {@link io.bootique.resource.ResourceFactory} denoting
* a configuration source. E.g. "a/b/my.yml", or "classpath:com/foo/another.yml".
* @return this builder instance
* @since 0.24
*/
public Builder configResource(String configResourceId) {
this.option.configResource = new ResourceFactory(configResourceId);
this.option.configPath = null;
return this;
}

Expand Down
8 changes: 4 additions & 4 deletions bootique/src/test/java/io/bootique/Bootique_CliOptionsIT.java
Expand Up @@ -202,7 +202,7 @@ public void testConfigOverrideOrder_PropsVarsOptionsFileOptions() {
BQRuntime runtime = runtimeFactory.app("--config=classpath:io/bootique/config/test4.yml", "--file-opt-1", "--opt-1=Option")
.module(binder -> BQCoreModule.extend(binder)
.addOption("c.m.f", "opt-1")
.addConfigFileOption("classpath:io/bootique/config/configTest4Opt1.yml", "file-opt-1")
.addConfigResourceOption("classpath:io/bootique/config/configTest4Opt1.yml", "file-opt-1")
.setVar("BQ_C_M_F", "var_c_m_f"))
.createRuntime();

Expand Down Expand Up @@ -237,7 +237,7 @@ public void testOptionWithNotMappedConfigPath() {
public void testOptionConfigFile_OverrideConfig() {
BQRuntime runtime = runtimeFactory.app("--config=classpath:io/bootique/config/test4.yml", "--file-opt")
.module(binder -> BQCoreModule.extend(binder)
.addConfigFileOption("classpath:io/bootique/config/configTest4.yml", "file-opt"))
.addConfigResourceOption("classpath:io/bootique/config/configTest4.yml", "file-opt"))
.createRuntime();
Bean1 bean1 = runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");

Expand All @@ -248,8 +248,8 @@ public void testOptionConfigFile_OverrideConfig() {
public void testMultipleOptionsConfigFiles_OverrideInCLIOrder() {
BQRuntime runtime = runtimeFactory.app("--config=classpath:io/bootique/config/test4.yml", "--file-opt-2", "--file-opt-1")
.module(binder -> BQCoreModule.extend(binder)
.addConfigFileOption("classpath:io/bootique/config/configTest4Opt1.yml", "file-opt-1")
.addConfigFileOption("classpath:io/bootique/config/configTest4Opt2.yml", "file-opt-2")
.addConfigResourceOption("classpath:io/bootique/config/configTest4Opt1.yml", "file-opt-1")
.addConfigResourceOption("classpath:io/bootique/config/configTest4Opt2.yml", "file-opt-2")
.addOption("c.m.f", "opt-1"))
.createRuntime();
Bean1 bean1 = runtime.getInstance(ConfigurationFactory.class).config(Bean1.class, "");
Expand Down

0 comments on commit 51e3308

Please sign in to comment.