Skip to content

Commit

Permalink
Merge pull request #30368 from radcortez/env-vars
Browse files Browse the repository at this point in the history
Allow Environment variables to populate property Maps in build time Config
  • Loading branch information
radcortez authored Jan 24, 2023
2 parents baa7f5c + cd8f952 commit 675d15e
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -877,33 +877,34 @@ private Converter<?> getConverter(SmallRyeConfig config, Field field, ConverterT

/**
* We collect all properties from eligible ConfigSources, because Config#getPropertyNames exclude the active
* profiled properties, meaning that the property is written in the default config source without the profile
* prefix. This may cause issues if we run with a different profile and fallback to defaults.
* profiled properties (the property name omits the active profile prefix). If we record properties as is, we
* can have an issue when running in a different profile from the one recorded. This list includes all available
* properties in all profiles (active or not), so it is safe to fall back to different default on another
* profile.
* <br>
* We also filter the properties coming from the System with the registered roots, because we don't want to
* We also filter the properties coming from System or Env with the registered roots, because we don't want to
* record properties set by the compiling JVM (or other properties that are only related to the build).
* <br>
* Properties coming from the Environment are ignored.
*/
private Set<String> getAllProperties(final Set<String> registeredRoots) {
Set<String> properties = new HashSet<>();
for (String property : config.getPropertyNames()) {
properties.add(property);
}

for (ConfigSource configSource : config.getConfigSources()) {
// This is a BuildTimeSysPropConfigSource
if (configSource instanceof SysPropConfigSource) {
for (String propertyName : configSource.getProperties().keySet()) {
NameIterator ni = new NameIterator(propertyName);
if (configSource instanceof SysPropConfigSource || configSource instanceof EnvConfigSource) {
for (String property : configSource.getPropertyNames()) {
NameIterator ni = new NameIterator(property);
if (ni.hasNext() && PropertiesUtil.isPropertyInRoot(registeredRoots, ni)) {
properties.add(propertyName);
properties.add(property);
} else {
properties.remove(property);
}
}
} else {
// The BuildTimeEnvConfigSource returns an empty Set
properties.addAll(configSource.getPropertyNames());
}
}
for (String propertyName : config.getPropertyNames()) {
properties.add(propertyName);
}
return properties;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package io.quarkus.runtime.configuration;

import static io.smallrye.config.PropertiesConfigSourceProvider.classPathSources;
import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_LOCATIONS;
import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE;
import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE_PARENT;
import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
Expand All @@ -36,15 +31,12 @@
import io.smallrye.config.ConfigSourceInterceptorContext;
import io.smallrye.config.ConfigSourceInterceptorFactory;
import io.smallrye.config.DotEnvConfigSourceProvider;
import io.smallrye.config.EnvConfigSource;
import io.smallrye.config.FallbackConfigSourceInterceptor;
import io.smallrye.config.NameIterator;
import io.smallrye.config.Priorities;
import io.smallrye.config.RelocateConfigSourceInterceptor;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SysPropConfigSource;
import io.smallrye.config.common.utils.ConfigSourceUtil;

/**
*
Expand Down Expand Up @@ -100,24 +92,17 @@ public static SmallRyeConfigBuilder configBuilder(final boolean runTime, final b

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
builder.forClassLoader(classLoader);
builder.addDefaultSources();
builder.withSources(new ApplicationPropertiesConfigSourceLoader.InFileSystem());
builder.withSources(new ApplicationPropertiesConfigSourceLoader.InClassPath());
builder.withSources(new DotEnvConfigSourceProvider());
if (launchMode.isDevOrTest() && (runTime || bootstrap)) {
builder.withSources(new RuntimeOverrideConfigSource(classLoader));
}
if (runTime || bootstrap) {
builder.addDefaultSources();
// Validator only for runtime. We cannot use the current validator for build time (chicken / egg problem)
builder.addDiscoveredValidator();
builder.withDefaultValue(UUID_KEY, UUID.randomUUID().toString());
builder.withSources(new DotEnvConfigSourceProvider());
} else {
List<ConfigSource> sources = new ArrayList<>();
sources.addAll(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader));
sources.addAll(new BuildTimeDotEnvConfigSourceProvider().getConfigSources(classLoader));
sources.add(new BuildTimeEnvConfigSource());
sources.add(new BuildTimeSysPropConfigSource());
builder.withSources(sources);
}
if (addDiscovered) {
builder.addDiscoveredSources();
Expand Down Expand Up @@ -336,77 +321,9 @@ public static <T> Optional<T> getFirstOptionalValue(List<String> propertyNames,
return Optional.empty();
}

/**
* We override the EnvConfigSource, because we don't want the nothing back from getPropertiesNames at build time.
* The mapping is one way and there is no way to map them back.
*/
static class BuildTimeEnvConfigSource extends EnvConfigSource {
BuildTimeEnvConfigSource() {
super();
}

BuildTimeEnvConfigSource(final Map<String, String> propertyMap, final int ordinal) {
super(propertyMap, ordinal);
}

@Override
public Set<String> getPropertyNames() {
return Collections.emptySet();
}

@Override
public String getName() {
return "System environment";
}
}

/**
* Same as BuildTimeEnvConfigSource.
*/
static class BuildTimeDotEnvConfigSourceProvider extends DotEnvConfigSourceProvider {
public BuildTimeDotEnvConfigSourceProvider() {
super();
}

public BuildTimeDotEnvConfigSourceProvider(final String location) {
super(location);
}

@Override
protected ConfigSource loadConfigSource(final URL url, final int ordinal) throws IOException {
return new BuildTimeEnvConfigSource(ConfigSourceUtil.urlToMap(url), ordinal) {
@Override
public String getName() {
return super.getName() + "[source=" + url + "]";
}
};
}
}

/**
* We only want to include properties in the quarkus namespace.
*
* We removed the filter on the quarkus namespace due to the any prefix support for ConfigRoot. Filtering is now
* done in io.quarkus.deployment.configuration.BuildTimeConfigurationReader.ReadOperation#getAllProperties.
*/
static class BuildTimeSysPropConfigSource extends SysPropConfigSource {
public String getName() {
return "System properties";
}

@Override
public Set<String> getPropertyNames() {
return Collections.emptySet();
}
}

private static class ConfigBuilderComparator implements Comparator<ConfigBuilder> {

private static final ConfigBuilderComparator INSTANCE = new ConfigBuilderComparator();

private ConfigBuilderComparator() {
}

@Override
public int compare(ConfigBuilder o1, ConfigBuilder o2) {
return Integer.compare(o1.priority(), o2.priority());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import org.junit.jupiter.api.Test;

import io.smallrye.config.DotEnvConfigSourceProvider;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;

Expand All @@ -40,9 +41,7 @@ private SmallRyeConfig buildConfig(Map<String, String> configMap) throws IOExcep
}
}
}
builder.withSources(
new ConfigUtils.BuildTimeDotEnvConfigSourceProvider(dotEnv.toUri().toString())
.getConfigSources(Thread.currentThread().getContextClassLoader()));
builder.withSources(new DotEnvConfigSourceProvider(dotEnv.toUri().toString()));
final SmallRyeConfig config = builder.build();
Files.delete(dotEnv);
return config;
Expand All @@ -65,5 +64,4 @@ public void testProperties() throws IOException {
assertEquals("foo.bar", config.getValue("foo.bar", String.class));
assertTrue(config.getOptionalValue("foo.baz", String.class).isPresent());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static boolean isBuildTime() {
// We can only call this when the SmallRyeConfig is already initialized, or else we may get into a loop
Config config = ConfigProvider.getConfig();
for (ConfigSource configSource : config.getConfigSources()) {
if (configSource.getClass().getSimpleName().equals("BuildTimeEnvConfigSource")) {
if (configSource.getName().equals("PropertiesConfigSource[source=Build system]")) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ public class RestClientOverrideRuntimeConfigTest {
@Test
void overrideConfig() {
// Build time property recording
Optional<ConfigSource> specifiedDefaultValues = config
.getConfigSource("RunTime Defaults");
Optional<ConfigSource> specifiedDefaultValues = config.getConfigSource("RunTime Defaults");
assertTrue(specifiedDefaultValues.isPresent());
assertTrue(specifiedDefaultValues.get().getPropertyNames()
.contains("io.quarkus.restclient.configuration.EchoClient/mp-rest/url"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public String getValue(final String propertyName) {

boolean isBuildTime = false;
for (ConfigSource configSource : ConfigProvider.getConfig().getConfigSources()) {
if (configSource.getClass().getSimpleName().equals("BuildTimeEnvConfigSource")) {
if (configSource.getName().equals("PropertiesConfigSource[source=Build system]")) {
isBuildTime = true;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public String getValue(final String propertyName) {

boolean isBuildTime = false;
for (ConfigSource configSource : ConfigProvider.getConfig().getConfigSources()) {
if (configSource.getClass().getSimpleName().equals("BuildTimeEnvConfigSource")) {
if (configSource.getName().equals("PropertiesConfigSource[source=Build system]")) {
isBuildTime = true;
break;
}
Expand Down

0 comments on commit 675d15e

Please sign in to comment.