diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java index efd857e3cd593..1c80ea39bc502 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigBuildSteps.java @@ -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; @@ -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 staticInitConfigBuilder, BuildProducer 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 staticInitConfigBuilder, + BuildProducer runTimeConfigBuilder) { + runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(FileSystemOnlySourcesConfigBuilder.class.getName())); + } + private static class SystemOnlySources implements BooleanSupplier { ConfigBuildTimeConfig configBuildTimeConfig; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java index 2a9ce52ff6a43..d62a38f443692 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java @@ -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; @@ -438,6 +439,56 @@ public void watchConfigFiles(BuildProducer wa } } + /** + * Registers configuration files for access at runtime in native-mode. Doesn't use absolute paths. + */ + @BuildStep + public NativeImageResourceBuildItem nativeConfigFiles() { + List 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> 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 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( @@ -676,7 +727,6 @@ private static Set 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; diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/FileSystemOnlySourcesConfigBuilder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/FileSystemOnlySourcesConfigBuilder.java new file mode 100644 index 0000000000000..2940b3b80af44 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/FileSystemOnlySourcesConfigBuilder.java @@ -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; + } + +} diff --git a/extensions/config-yaml/deployment/src/main/java/io/quarkus/config/yaml/deployment/ConfigYamlProcessor.java b/extensions/config-yaml/deployment/src/main/java/io/quarkus/config/yaml/deployment/ConfigYamlProcessor.java index c25fab1f0f91a..cd76caa618fb6 100644 --- a/extensions/config-yaml/deployment/src/main/java/io/quarkus/config/yaml/deployment/ConfigYamlProcessor.java +++ b/extensions/config-yaml/deployment/src/main/java/io/quarkus/config/yaml/deployment/ConfigYamlProcessor.java @@ -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; @@ -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 { @@ -23,7 +26,7 @@ public FeatureBuildItem feature() { return new FeatureBuildItem(Feature.CONFIG_YAML); } - @BuildStep + @BuildStep(onlyIfNot = NativeOrNativeSourcesBuild.class) public void yamlConfig( BuildProducer staticInitConfigBuilder, BuildProducer runTimeConfigBuilder) { @@ -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 runTimeConfigBuilder) { + runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(NativeYamlConfigBuilder.class)); + } + @BuildStep void watchYamlConfig(BuildProducer watchedFiles) { List 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()); @@ -58,4 +72,31 @@ void watchYamlConfig(BuildProducer 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 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); + } } diff --git a/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/NativeYamlConfigBuilder.java b/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/NativeYamlConfigBuilder.java new file mode 100644 index 0000000000000..3b8dd069511d7 --- /dev/null +++ b/extensions/config-yaml/runtime/src/main/java/io/quarkus/config/yaml/runtime/NativeYamlConfigBuilder.java @@ -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()); + } +}