Skip to content

Commit

Permalink
Limit external configuration sources parsing in native-mode
Browse files Browse the repository at this point in the history
`SmallryeConfigBuilder` tries to access properties files from various
sources, despite them not being available at run-time nor supported in
native-mode, see quarkusio#41994

This patch also avoids getting a `MissingRegistrationError` when using
`-H:+ThrowMissingRegistrationErrors` or `--exact-reachability-metadata`.

Related to quarkusio#41994 and
quarkusio#41995
  • Loading branch information
zakkak committed Dec 2, 2024
1 parent c10465e commit 0f37d9f
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import io.quarkus.deployment.builditem.StaticInitConfigBuilderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.deployment.util.ServiceUtil;
import io.quarkus.runtime.configuration.FileSystemOnlySourcesConfigBuilder;
import io.quarkus.runtime.configuration.SystemOnlySourcesConfigBuilder;
import io.quarkus.runtime.graal.InetRunTime;
import io.smallrye.config.ConfigSourceInterceptor;
Expand Down Expand Up @@ -55,13 +57,23 @@ RuntimeInitializedClassBuildItem runtimeInitializedClass() {
return new RuntimeInitializedClassBuildItem(InetRunTime.class.getName());
}

@BuildStep(onlyIf = SystemOnlySources.class)
@BuildStep(onlyIf = SystemOnlySources.class, onlyIfNot = NativeOrNativeSourcesBuild.class)
void systemOnlySources(BuildProducer<StaticInitConfigBuilderBuildItem> staticInitConfigBuilder,
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {
staticInitConfigBuilder.produce(new StaticInitConfigBuilderBuildItem(SystemOnlySourcesConfigBuilder.class.getName()));
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(SystemOnlySourcesConfigBuilder.class.getName()));
}

/**
* Limit external configuration sources parsing for native executables since they are not supported see
* https://github.com/quarkusio/quarkus/issues/41994
*/
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
void nativeNoSources(BuildProducer<StaticInitConfigBuilderBuildItem> staticInitConfigBuilder,
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(FileSystemOnlySourcesConfigBuilder.class.getName()));
}

private static class SystemOnlySources implements BooleanSupplier {
ConfigBuildTimeConfig configBuildTimeConfig;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.builditem.StaticInitConfigBuilderBuildItem;
import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.deployment.configuration.BuildTimeConfigurationReader;
Expand Down Expand Up @@ -438,6 +439,56 @@ public void watchConfigFiles(BuildProducer<HotDeploymentWatchedFileBuildItem> wa
}
}

/**
* Registers configuration files for access at runtime in native-mode. Doesn't use absolute paths.
*/
@BuildStep
public NativeImageResourceBuildItem nativeConfigFiles() {
List<String> configFiles = new ArrayList<>();

SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);

// Main files
configFiles.add("application.properties");
configFiles.add("META-INF/microprofile-config.properties");
configFiles.add(".env");
configFiles.add(Paths.get("config", "application.properties").toString());

// Profiles
for (String profile : config.getProfiles()) {
configFiles.add(String.format("application-%s.properties", profile));
configFiles.add(String.format("META-INF/microprofile-config-%s.properties", profile));
configFiles.add(String.format(".env-%s", profile));
configFiles.add(Paths.get("config", String.format("application-%s.properties", profile))
.toString());
}

Optional<List<URI>> optionalLocations = config.getOptionalValues(SMALLRYE_CONFIG_LOCATIONS, URI.class);
optionalLocations.ifPresent(locations -> {
for (URI location : locations) {
Path path = location.getScheme() != null && location.getScheme().equals("file") ? Paths.get(location)
: Paths.get(location.getPath());
// Include missing files as smallrye will still try to access them at runtime
if (Files.isRegularFile(path) || !Files.exists(path)) {
configFiles.add(path.toString());
for (String profile : config.getProfiles()) {
configFiles.add(appendProfileToFilename(path, profile));
}
} else if (Files.isDirectory(path)) {
try (DirectoryStream<Path> files = Files.newDirectoryStream(path, Files::isRegularFile)) {
for (Path file : files) {
configFiles.add(file.toString());
}
} catch (IOException e) {
// Ignore
}
}
}
});

return new NativeImageResourceBuildItem(configFiles);
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void unknownConfigFiles(
Expand Down Expand Up @@ -676,7 +727,6 @@ private static Set<String> discoverService(
// The discovery includes deployment modules, so we only include services available at runtime
if (QuarkusClassLoader.isClassPresentAtRuntime(service)) {
services.add(service);
reflectiveClass.produce(ReflectiveClassBuildItem.builder(service).build());
}
}
return services;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.runtime.configuration;

import static io.smallrye.config.PropertiesConfigSourceLoader.inFileSystem;

import java.nio.file.Paths;

import io.smallrye.config.SmallRyeConfigBuilder;

public class FileSystemOnlySourcesConfigBuilder implements ConfigBuilder {
@Override
public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) {
return builder.setAddDefaultSources(false).addSystemSources().withSources(
inFileSystem(Paths.get(System.getProperty("user.dir"), "config", "application.properties").toUri().toString(),
260, builder.getClassLoader()));
}

@Override
public int priority() {
return Integer.MAX_VALUE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import org.eclipse.microprofile.config.ConfigProvider;

import io.quarkus.config.yaml.runtime.NativeYamlConfigBuilder;
import io.quarkus.config.yaml.runtime.YamlConfigBuilder;
import io.quarkus.deployment.Feature;
import io.quarkus.deployment.annotations.BuildProducer;
Expand All @@ -14,6 +15,8 @@
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem;
import io.quarkus.deployment.builditem.StaticInitConfigBuilderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.smallrye.config.SmallRyeConfig;

public final class ConfigYamlProcessor {
Expand All @@ -23,7 +26,7 @@ public FeatureBuildItem feature() {
return new FeatureBuildItem(Feature.CONFIG_YAML);
}

@BuildStep
@BuildStep(onlyIfNot = NativeOrNativeSourcesBuild.class)
public void yamlConfig(
BuildProducer<StaticInitConfigBuilderBuildItem> staticInitConfigBuilder,
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {
Expand All @@ -32,12 +35,23 @@ public void yamlConfig(
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(YamlConfigBuilder.class));
}

/**
* Limit external configuration sources parsing for native executables since they are not supported see
* https://github.com/quarkusio/quarkus/issues/41994
*/
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
void nativeNoSources(BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(NativeYamlConfigBuilder.class));
}

@BuildStep
void watchYamlConfig(BuildProducer<HotDeploymentWatchedFileBuildItem> watchedFiles) {
List<String> configWatchedFiles = new ArrayList<>();
String userDir = System.getProperty("user.dir");

// Main files
configWatchedFiles.add("META-INF/microprofile-config.yaml");
configWatchedFiles.add("META-INF/microprofile-config.yml");
configWatchedFiles.add("application.yaml");
configWatchedFiles.add("application.yml");
configWatchedFiles.add(Paths.get(userDir, "config", "application.yaml").toAbsolutePath().toString());
Expand All @@ -58,4 +72,31 @@ void watchYamlConfig(BuildProducer<HotDeploymentWatchedFileBuildItem> watchedFil
watchedFiles.produce(new HotDeploymentWatchedFileBuildItem(configWatchedFile));
}
}

/**
* Registers configuration files for access at runtime in native-mode. Doesn't use absolute paths.
*/
@BuildStep
NativeImageResourceBuildItem nativeYamlConfig() {
List<String> configFiles = new ArrayList<>();

// Main files
configFiles.add("META-INF/microprofile-config.yaml");
configFiles.add("META-INF/microprofile-config.yml");
configFiles.add("application.yaml");
configFiles.add("application.yml");
configFiles.add(Paths.get("config", "application.yaml").toString());
configFiles.add(Paths.get("config", "application.yml").toString());

// Profiles
SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);
for (String profile : config.getProfiles()) {
configFiles.add(String.format("application-%s.yaml", profile));
configFiles.add(String.format("application-%s.yml", profile));
configFiles.add(Paths.get("config", String.format("application-%s.yaml", profile)).toString());
configFiles.add(Paths.get("config", String.format("application-%s.yml", profile)).toString());
}

return new NativeImageResourceBuildItem(configFiles);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.config.yaml.runtime;

import io.quarkus.runtime.configuration.ConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.source.yaml.YamlConfigSourceLoader;

public class NativeYamlConfigBuilder implements ConfigBuilder {
@Override
public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) {
return builder.withSources(new YamlConfigSourceLoader.InFileSystem());
}
}

0 comments on commit 0f37d9f

Please sign in to comment.