mirror of
https://github.com/lightbend/config.git
synced 2025-02-06 01:20:08 +08:00
Env variables resolution moved to defaultOverrides
This commit is contained in:
parent
30b65568eb
commit
7fe47888d2
12
build.sbt
12
build.sbt
@ -85,7 +85,17 @@ lazy val configLib = Project("config", file("config"))
|
||||
Test/ run / fork := true
|
||||
|
||||
//env vars for tests
|
||||
Test / envVars ++= Map("testList.0" -> "0", "testList.1" -> "1")
|
||||
Test / envVars ++= Map("testList.0" -> "0",
|
||||
"testList.1" -> "1",
|
||||
"CONFIG_FORCE_b" -> "5",
|
||||
"CONFIG_FORCE_testList_0" -> "10",
|
||||
"CONFIG_FORCE_testList_1" -> "11",
|
||||
"CONFIG_FORCE_42___a" -> "1",
|
||||
"CONFIG_FORCE_a_b_c" -> "2",
|
||||
"CONFIG_FORCE_a__c" -> "3",
|
||||
"CONFIG_FORCE_a___c" -> "4",
|
||||
"CONFIG_FORCE_akka_version" -> "foo",
|
||||
"CONFIG_FORCE_akka_event__handler__dispatcher_max__pool__size" -> "10")
|
||||
|
||||
OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl")
|
||||
publish := sys.error("use publishSigned instead of plain publish")
|
||||
|
@ -36,6 +36,7 @@ import java.util.concurrent.Callable;
|
||||
*/
|
||||
public final class ConfigFactory {
|
||||
private static final String STRATEGY_PROPERTY_NAME = "config.strategy";
|
||||
private static final String OVERRIDE_WITH_ENV_PROPERTY_NAME = "config.override_with_env_vars";
|
||||
|
||||
private ConfigFactory() {
|
||||
}
|
||||
@ -383,7 +384,11 @@ public final class ConfigFactory {
|
||||
* @return the default override configuration
|
||||
*/
|
||||
public static Config defaultOverrides() {
|
||||
if (!getOverrideWithEnv()) {
|
||||
return systemProperties();
|
||||
} else {
|
||||
return systemEnvironmentOverrides().withFallback(systemProperties());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -394,7 +399,7 @@ public final class ConfigFactory {
|
||||
* @return the default override configuration
|
||||
*/
|
||||
public static Config defaultOverrides(ClassLoader loader) {
|
||||
return systemProperties();
|
||||
return defaultOverrides();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -549,6 +554,50 @@ public final class ConfigFactory {
|
||||
return ConfigImpl.systemPropertiesAsConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a <code>Config</code> containing the system's environment variables
|
||||
* used to override configuration keys.
|
||||
* Environment variables taken in considerations are starting with
|
||||
* {@code CONFIG_FORCE_}
|
||||
*
|
||||
* <p>
|
||||
* Environment variables are mangled in the following way after stripping the prefix "CONFIG_FORCE_":
|
||||
* <table border="1">
|
||||
* <tr>
|
||||
* <th bgcolor="silver">Env Var</th>
|
||||
* <th bgcolor="silver">Config</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>_ [1 underscore]</td>
|
||||
* <td>. [dot]</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>__ [2 underscore]</td>
|
||||
* <td>- [dash]</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>___ [3 underscore]</td>
|
||||
* <td>_ [underscore]</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* A variable like: {@code CONFIG_FORCE_a_b__c___d}
|
||||
* is translated to a config key: {@code a.b-c_d}
|
||||
*
|
||||
* <p>
|
||||
* This method can return a global immutable singleton, so it's preferred
|
||||
* over parsing system properties yourself.
|
||||
* <p>
|
||||
* {@link #defaultOverrides} will include the system system environment variables as
|
||||
* overrides if `config.override_with_env_vars` is set to `true`.
|
||||
*
|
||||
* @return system environment variable overrides parsed into a <code>Config</code>
|
||||
*/
|
||||
public static Config systemEnvironmentOverrides() {
|
||||
return ConfigImpl.envVariablesOverridesAsConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a <code>Config</code> containing the system's environment variables.
|
||||
* This method can return a global immutable singleton.
|
||||
@ -1063,4 +1112,10 @@ public final class ConfigFactory {
|
||||
return new DefaultConfigLoadingStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean getOverrideWithEnv() {
|
||||
String overrideWithEnv = System.getProperties().getProperty(OVERRIDE_WITH_ENV_PROPERTY_NAME);
|
||||
|
||||
return Boolean.parseBoolean(overrideWithEnv);
|
||||
}
|
||||
}
|
||||
|
@ -1,79 +0,0 @@
|
||||
package com.typesafe.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Environment variables first config loading strategy. Able to load environment variables first and fallback to {@link DefaultConfigLoadingStrategy}
|
||||
*
|
||||
* <p>
|
||||
* Environment variables are mangled in the following way after stripping the prefix:
|
||||
* <table border="1">
|
||||
* <tr>
|
||||
* <th bgcolor="silver">Env Var</th>
|
||||
* <th bgcolor="silver">Config</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>_ [1 underscore]</td>
|
||||
* <td>. [dot]</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>__ [2 underscore]</td>
|
||||
* <td>- [dash]</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>___ [3 underscore]</td>
|
||||
* <td>_ [underscore]</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* A variable like: {@code CONFIG_a_b__c___d}
|
||||
* is translated to a config key: {@code a.b-c_d}
|
||||
*
|
||||
* <p>
|
||||
* The prefix may be altered by defining the VM property {@code config.env_var_prefix}
|
||||
*/
|
||||
public class EnvFirstConfigLoadingStrategy extends DefaultConfigLoadingStrategy {
|
||||
|
||||
protected static Map<String, String> env = new HashMap(System.getenv());
|
||||
|
||||
@Override
|
||||
public Config parseApplicationConfig(ConfigParseOptions parseOptions) {
|
||||
String envVarPrefix = System.getProperty("config.env_var_prefix");
|
||||
if (envVarPrefix == null) // fallback to default
|
||||
envVarPrefix = "CONFIG_";
|
||||
|
||||
Map<String, String> defaultsFromEnv = new HashMap();
|
||||
for (String key : env.keySet()) {
|
||||
if (key.startsWith(envVarPrefix)) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
String strippedPrefix = key.substring(envVarPrefix.length(), key.length());
|
||||
|
||||
int underscores = 0;
|
||||
for (char c : strippedPrefix.toCharArray()) {
|
||||
if (c == '_') {
|
||||
underscores++;
|
||||
} else {
|
||||
switch (underscores) {
|
||||
case 1: builder.append('.');
|
||||
break;
|
||||
case 2: builder.append('-');
|
||||
break;
|
||||
case 3: builder.append('_');
|
||||
break;
|
||||
}
|
||||
underscores = 0;
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String propertyKey = builder.toString();
|
||||
defaultsFromEnv.put(propertyKey, env.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return ConfigFactory.parseMap(defaultsFromEnv).withFallback(super.parseApplicationConfig(parseOptions));
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ import com.typesafe.config.impl.SimpleIncluder.NameSource;
|
||||
* For use only by the {@link com.typesafe.config} package.
|
||||
*/
|
||||
public class ConfigImpl {
|
||||
private static final String ENV_VAR_OVERRIDE_PREFIX = "CONFIG_FORCE_";
|
||||
|
||||
private static class LoaderCache {
|
||||
private Config currentSystemProperties;
|
||||
@ -360,6 +361,57 @@ public class ConfigImpl {
|
||||
EnvVariablesHolder.envVariables = loadEnvVariables();
|
||||
}
|
||||
|
||||
private static AbstractConfigObject loadEnvVariablesOverrides() {
|
||||
Map<String, String> env = new HashMap(System.getenv());
|
||||
Map<String, String> result = new HashMap(System.getenv());
|
||||
for (String key : env.keySet()) {
|
||||
if (key.startsWith(ENV_VAR_OVERRIDE_PREFIX)) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
String strippedPrefix = key.substring(ENV_VAR_OVERRIDE_PREFIX.length(), key.length());
|
||||
|
||||
int underscores = 0;
|
||||
for (char c : strippedPrefix.toCharArray()) {
|
||||
if (c == '_') {
|
||||
underscores++;
|
||||
} else {
|
||||
switch (underscores) {
|
||||
case 1: builder.append('.');
|
||||
break;
|
||||
case 2: builder.append('-');
|
||||
break;
|
||||
case 3: builder.append('_');
|
||||
break;
|
||||
}
|
||||
underscores = 0;
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String propertyKey = builder.toString();
|
||||
result.put(propertyKey, env.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return PropertiesParser.fromStringMap(newSimpleOrigin("env variables overrides"), result);
|
||||
}
|
||||
|
||||
private static class EnvVariablesOverridesHolder {
|
||||
static volatile AbstractConfigObject envVariables = loadEnvVariablesOverrides();
|
||||
}
|
||||
|
||||
static AbstractConfigObject envVariablesOverridesAsConfigObject() {
|
||||
try {
|
||||
return EnvVariablesOverridesHolder.envVariables;
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
throw ConfigImplUtil.extractInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Config envVariablesOverridesAsConfig() {
|
||||
return envVariablesOverridesAsConfigObject().toConfig();
|
||||
}
|
||||
|
||||
public static Config defaultReference(final ClassLoader loader) {
|
||||
return computeCachedConfig(loader, "defaultReference", new Callable<Config>() {
|
||||
@Override
|
||||
|
@ -1092,15 +1092,7 @@ class ConfigTest extends TestUtils {
|
||||
|
||||
@Test
|
||||
def testLoadWithEnvSubstitutions() {
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_42___a", "1")
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_a_b_c", "2")
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_a__c", "3")
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_a___c", "4")
|
||||
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_akka_version", "foo")
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_akka_event__handler__dispatcher_max__pool__size", "10")
|
||||
|
||||
System.setProperty("config.strategy", classOf[EnvFirstConfigLoadingStrategy].getCanonicalName)
|
||||
System.setProperty("config.override_with_env_vars", "true")
|
||||
|
||||
try {
|
||||
val loader02 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||
@ -1125,15 +1117,7 @@ class ConfigTest extends TestUtils {
|
||||
assertEquals("foo", conf04.getString("akka.version"))
|
||||
assertEquals(10, conf04.getInt("akka.event-handler-dispatcher.max-pool-size"))
|
||||
} finally {
|
||||
System.clearProperty("config.strategy")
|
||||
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_42___a")
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_a_b_c")
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_a__c")
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_a___c")
|
||||
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_akka_version")
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_akka_event__handler__dispatcher_max__pool__size")
|
||||
System.clearProperty("config.override_with_env_vars")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -654,24 +654,22 @@ class PublicApiTest extends TestUtils {
|
||||
}
|
||||
|
||||
@Test
|
||||
def supportsEnvFirstConfigLoadingStrategy(): Unit = {
|
||||
assertEquals("config.strategy is not set", null, System.getProperty("config.strategy"))
|
||||
def loadEnvironmentVariablesOverridesIfConfigured(): Unit = {
|
||||
assertEquals("config.override_with_env_vars is not set", null, System.getProperty("config.override_with_env_vars"))
|
||||
|
||||
TestEnvFirstStrategy.putEnvVar("CONFIG_a", "5")
|
||||
System.setProperty("config.strategy", classOf[EnvFirstConfigLoadingStrategy].getCanonicalName)
|
||||
System.setProperty("config.override_with_env_vars", "true")
|
||||
|
||||
try {
|
||||
val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||
Map("reference.conf" -> resourceFile("a_1.conf").toURI.toURL()))
|
||||
val loaderB2 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||
Map("reference.conf" -> resourceFile("b_2.conf").toURI.toURL()))
|
||||
|
||||
val configA1 = withContextClassLoader(loaderA1) {
|
||||
val configB2 = withContextClassLoader(loaderB2) {
|
||||
ConfigFactory.load()
|
||||
}
|
||||
|
||||
assertEquals(5, configA1.getInt("a"))
|
||||
assertEquals(5, configB2.getInt("b"))
|
||||
} finally {
|
||||
System.clearProperty("config.strategy")
|
||||
TestEnvFirstStrategy.removeEnvVar("CONFIG_a")
|
||||
System.clearProperty("config.override_with_env_vars")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1168,10 +1166,3 @@ object TestStrategy {
|
||||
def getIncovations() = invocations
|
||||
def increment() = invocations += 1
|
||||
}
|
||||
|
||||
object TestEnvFirstStrategy extends EnvFirstConfigLoadingStrategy {
|
||||
def putEnvVar(key: String, value: String) =
|
||||
EnvFirstConfigLoadingStrategy.env.put(key, value)
|
||||
def removeEnvVar(key: String) =
|
||||
EnvFirstConfigLoadingStrategy.env.remove(key)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user