diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java index f99844fd6b38e..aa2d4edd6f9fa 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java @@ -25,6 +25,7 @@ import org.gradle.api.artifacts.ExternalModuleDependency; import org.gradle.api.artifacts.ProjectDependency; import org.gradle.api.file.FileCollection; +import org.gradle.api.java.archives.Attributes; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.provider.Property; @@ -212,14 +213,15 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { QuarkusGenerateCode.class, LaunchMode.NORMAL, SourceSet.MAIN_SOURCE_SET_NAME, quarkusExt.getCodeGenerationInputs().get()); quarkusGenerateCode.configure(task -> configureGenerateCodeTask(task, quarkusGenerateAppModelTask, - QuarkusGenerateCode.QUARKUS_GENERATED_SOURCES)); + QuarkusGenerateCode.QUARKUS_GENERATED_SOURCES, quarkusExt)); // quarkusGenerateCodeDev TaskProvider quarkusGenerateCodeDev = tasks.register(QUARKUS_GENERATE_CODE_DEV_TASK_NAME, QuarkusGenerateCode.class, LaunchMode.DEVELOPMENT, SourceSet.MAIN_SOURCE_SET_NAME, quarkusExt.getCodeGenerationInputs().get()); quarkusGenerateCodeDev.configure(task -> { task.dependsOn(quarkusGenerateCode); - configureGenerateCodeTask(task, quarkusGenerateDevAppModelTask, QuarkusGenerateCode.QUARKUS_GENERATED_SOURCES); + configureGenerateCodeTask(task, quarkusGenerateDevAppModelTask, QuarkusGenerateCode.QUARKUS_GENERATED_SOURCES, + quarkusExt); }); // quarkusGenerateCodeTests TaskProvider quarkusGenerateCodeTests = tasks.register(QUARKUS_GENERATE_CODE_TESTS_TASK_NAME, @@ -228,7 +230,7 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { quarkusGenerateCodeTests.configure(task -> { task.dependsOn("compileQuarkusTestGeneratedSourcesJava"); configureGenerateCodeTask(task, quarkusGenerateTestAppModelTask, - QuarkusGenerateCode.QUARKUS_TEST_GENERATED_SOURCES); + QuarkusGenerateCode.QUARKUS_TEST_GENERATED_SOURCES, quarkusExt); }); TaskProvider quarkusBuildAppModelTask = tasks.register("quarkusBuildAppModel", @@ -240,14 +242,14 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { }); tasks.register(QUARKUS_SHOW_EFFECTIVE_CONFIG_TASK_NAME, QuarkusShowEffectiveConfig.class, task -> { - configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider, quarkusExt); task.setDescription("Show effective Quarkus build configuration."); }); TaskProvider quarkusBuildDependencies = tasks.register(QUARKUS_BUILD_DEP_TASK_NAME, QuarkusBuildDependencies.class, task -> { - configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider, quarkusExt); task.getOutputs().doNotCacheIf("Dependencies are never cached", t -> true); }); project.afterEvaluate(evaluated -> addDependencyOnJandexIfConfigured(evaluated, quarkusBuildDependencies)); @@ -257,7 +259,7 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { TaskProvider quarkusBuildCacheableAppParts = tasks.register( QUARKUS_BUILD_APP_PARTS_TASK_NAME, QuarkusBuildCacheableAppParts.class, task -> { - configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider, quarkusExt); task.dependsOn(quarkusGenerateCode); task.getOutputs().doNotCacheIf( "Not adding uber-jars, native binaries and mutable-jar package type to Gradle " + @@ -273,7 +275,7 @@ public boolean isSatisfiedBy(Task t) { }); TaskProvider quarkusBuild = tasks.register(QUARKUS_BUILD_TASK_NAME, QuarkusBuild.class, build -> { - configureQuarkusBuildTask(project, build, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, build, quarkusBuildAppModelTask, serviceProvider, quarkusExt); build.dependsOn(quarkusBuildDependencies, quarkusBuildCacheableAppParts); build.getOutputs().doNotCacheIf( "Only collects and combines the outputs of " + QUARKUS_BUILD_APP_PARTS_TASK_NAME + " and " @@ -297,20 +299,20 @@ public boolean isSatisfiedBy(Task t) { tasks.register(IMAGE_BUILD_TASK_NAME, ImageBuild.class, task -> { task.dependsOn(quarkusRequiredExtension); - configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider, quarkusExt); task.getBuilderName().set(quarkusRequiredExtension.flatMap(ImageCheckRequirementsTask::getOutputFile)); task.finalizedBy(quarkusBuild); }); tasks.register(IMAGE_PUSH_TASK_NAME, ImagePush.class, task -> { task.dependsOn(quarkusRequiredExtension); - configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider, quarkusExt); task.getBuilderName().set(quarkusRequiredExtension.flatMap(ImageCheckRequirementsTask::getOutputFile)); task.finalizedBy(quarkusBuild); }); tasks.register(DEPLOY_TASK_NAME, Deploy.class, task -> { - configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, task, quarkusBuildAppModelTask, serviceProvider, quarkusExt); task.finalizedBy(quarkusBuild); }); @@ -318,7 +320,7 @@ public boolean isSatisfiedBy(Task t) { quarkusExt); TaskProvider quarkusRun = tasks.register(QUARKUS_RUN_TASK_NAME, QuarkusRun.class, build -> { - configureQuarkusBuildTask(project, build, quarkusBuildAppModelTask, serviceProvider); + configureQuarkusBuildTask(project, build, quarkusBuildAppModelTask, serviceProvider, quarkusExt); build.dependsOn(quarkusBuild); }); @@ -471,7 +473,11 @@ public boolean isSatisfiedBy(Task t) { quarkusGenerateTestAppModelTask.flatMap(QuarkusApplicationModelTask::getApplicationModel), quarkusBuild.map(QuarkusBuild::getNativeRunner), mainSourceSet.getOutput().getClassesDirs(), - project.getObjects().newInstance(QuarkusPluginExtensionView.class, quarkusExt))); + project.getObjects().newInstance(QuarkusPluginExtensionView.class, quarkusExt), + project.getObjects().mapProperty(String.class, Object.class) + .convention(quarkusExt.manifest().getAttributes()), + project.getObjects().mapProperty(String.class, Attributes.class) + .convention(quarkusExt.getAttributes()))); // also make each task use the JUnit platform since it's the only supported test environment t.useJUnitPlatform(); @@ -523,7 +529,8 @@ private static void configureApplicationModelTask(Project project, QuarkusApplic private static void configureQuarkusBuildTask(Project project, QuarkusBuildTask task, TaskProvider quarkusGenerateAppModelTask, - Provider serviceProvider) { + Provider serviceProvider, + QuarkusPluginExtension quarkusExt) { task.getApplicationModel().set(quarkusGenerateAppModelTask.flatMap(QuarkusApplicationModelTask::getApplicationModel)); SourceSet mainSourceSet = getSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME); task.getAdditionalForcedProperties().set(serviceProvider); @@ -531,10 +538,26 @@ private static void configureQuarkusBuildTask(Project project, QuarkusBuildTask task.setCompileClasspath(mainSourceSet.getCompileClasspath().plus(mainSourceSet.getRuntimeClasspath()) .plus(mainSourceSet.getAnnotationProcessorPath()) .plus(mainSourceSet.getResources())); + task.getCachingRelevantInput().set(quarkusExt + .cachingRelevantProperties(quarkusExt.getCachingRelevantProperties().get())); + task.getJarEnabled().set(quarkusExt.packageConfig().jar().enabled()); + task.getNativeEnabled().set(quarkusExt.nativeConfig().enabled()); + task.getNativeSourcesOnly().set(quarkusExt.nativeConfig().sourcesOnly()); + task.getRunnerSuffix().set(quarkusExt.packageConfig().computedRunnerSuffix()); + task.getRunnerName().set( + quarkusExt.packageConfig().outputName().orElseGet(quarkusExt::finalName)); + task.getOutputDirectory() + .set(Path.of(quarkusExt.packageConfig().outputDirectory().map(Path::toString) + .orElse(QuarkusPlugin.DEFAULT_OUTPUT_DIRECTORY))); + task.getJarType().set(quarkusExt.packageConfig().jar().type()); + task.getManifestAttributes().set(quarkusExt.manifest().getAttributes()); + task.getManifestSections().set(quarkusExt.manifest().getSections()); + } private static void configureGenerateCodeTask(QuarkusGenerateCode task, - TaskProvider applicationModelTaskTaskProvider, String generateSourcesDir) { + TaskProvider applicationModelTaskTaskProvider, String generateSourcesDir, + QuarkusPluginExtension quarkusExt) { SourceSet generatedSources = getSourceSet(task.getProject(), generateSourcesDir); Set sourceSetOutput = generatedSources.getOutput().filter(f -> f.getName().equals(generateSourcesDir)).getFiles(); if (sourceSetOutput.isEmpty()) { @@ -544,6 +567,10 @@ private static void configureGenerateCodeTask(QuarkusGenerateCode task, task.getApplicationModel() .set(applicationModelTaskTaskProvider.flatMap(QuarkusApplicationModelTask::getApplicationModel)); task.getGeneratedOutputDirectory().set(generatedSources.getJava().getClassesDirectory()); + task.getCachingRelevantInput() + .set(quarkusExt.cachingRelevantProperties(quarkusExt.getCachingRelevantProperties().get())); + task.getManifestAttributes().set(quarkusExt.manifest().getAttributes()); + task.getManifestSections().set(quarkusExt.manifest().getSections()); } private void createSourceSets(Project project) { diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/actions/BeforeTestAction.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/actions/BeforeTestAction.java index 72b52e29731a9..df90d4295485b 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/actions/BeforeTestAction.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/actions/BeforeTestAction.java @@ -14,11 +14,14 @@ import org.gradle.api.Task; import org.gradle.api.file.FileCollection; import org.gradle.api.file.RegularFile; +import org.gradle.api.java.archives.Attributes; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.testing.Test; import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.gradle.tasks.EffectiveConfigProvider; import io.quarkus.gradle.tasks.QuarkusPluginExtensionView; import io.quarkus.gradle.tooling.ToolingUtils; import io.smallrye.config.SmallRyeConfig; @@ -31,17 +34,23 @@ public class BeforeTestAction implements Action { private final Provider nativeRunnerPath; private final FileCollection mainSourceSetClassesDir; private final QuarkusPluginExtensionView extensionView; + private final MapProperty manifestAttributes; + private final MapProperty manifestSections; public BeforeTestAction(File projectDir, FileCollection combinedOutputSourceDirs, Provider applicationModelPath, Provider nativeRunnerPath, FileCollection mainSourceSetClassesDir, - QuarkusPluginExtensionView extensionView) { + QuarkusPluginExtensionView extensionView, + MapProperty manifestAttributes, + MapProperty manifestSections) { this.projectDir = projectDir; this.combinedOutputSourceDirs = combinedOutputSourceDirs; this.applicationModelPath = applicationModelPath; this.nativeRunnerPath = nativeRunnerPath; this.mainSourceSetClassesDir = mainSourceSetClassesDir; this.extensionView = extensionView; + this.manifestAttributes = manifestAttributes; + this.manifestSections = manifestSections; } @@ -54,7 +63,8 @@ public void execute(Task t) { ApplicationModel applicationModel = ToolingUtils .deserializeAppModel(applicationModelPath.get().getAsFile().toPath()); - SmallRyeConfig config = extensionView.buildEffectiveConfiguration(applicationModel, new HashMap<>()).getConfig(); + SmallRyeConfig config = effectiveProvider().buildEffectiveConfiguration(applicationModel, new HashMap<>()) + .getConfig(); config.getOptionalValue(TEST.getProfileKey(), String.class) .ifPresent(value -> props.put(TEST.getProfileKey(), value)); @@ -88,4 +98,19 @@ public void execute(Task t) { throw new IllegalStateException("Failed to resolve deployment classpath", e); } } + + private EffectiveConfigProvider effectiveProvider() { + return new EffectiveConfigProvider( + extensionView.getIgnoredEntries(), + extensionView.getMainResources(), + extensionView.getForcedProperties(), + extensionView.getProjectProperties(), + extensionView.getQuarkusBuildProperties(), + extensionView.getQuarkusRelevantProjectProperties(), + manifestAttributes, + manifestSections, + extensionView.getNativeBuild(), + extensionView.getQuarkusProfileSystemVariable(), + extensionView.getQuarkusProfileEnvVariable()); + } } diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/AbstractQuarkusExtension.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/AbstractQuarkusExtension.java index 81301d6c807ad..c099fcc0bdb5f 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/AbstractQuarkusExtension.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/AbstractQuarkusExtension.java @@ -28,6 +28,8 @@ import org.gradle.process.JavaForkOptions; import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.deployment.pkg.NativeConfig; +import io.quarkus.deployment.pkg.PackageConfig; import io.quarkus.gradle.dsl.Manifest; import io.quarkus.maven.dependency.ResolvedDependency; import io.smallrye.common.expression.Expression; @@ -97,7 +99,7 @@ private BaseConfig buildBaseConfig() { return new BaseConfig(effectiveConfig); } - protected BaseConfig baseConfig() { + public BaseConfig baseConfig() { this.baseConfig.finalizeValue(); return this.baseConfig.get(); } @@ -114,10 +116,26 @@ protected FileCollection classpath() { return classpath; } - protected Manifest manifest() { + public Manifest manifest() { return baseConfig().manifest(); } + public Map getAttributes() { + return manifest().getSections(); + } + + public PackageConfig packageConfig() { + return baseConfig().packageConfig(); + } + + public Map cachingRelevantProperties(List propertyPatterns) { + return baseConfig().cachingRelevantProperties(propertyPatterns); + } + + public NativeConfig nativeConfig() { + return baseConfig().nativeConfig(); + } + protected EffectiveConfig buildEffectiveConfiguration(ApplicationModel appModel) { ResolvedDependency appArtifact = appModel.getAppArtifact(); diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/EffectiveConfigProvider.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/EffectiveConfigProvider.java new file mode 100644 index 0000000000000..bfed014fcee82 --- /dev/null +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/EffectiveConfigProvider.java @@ -0,0 +1,131 @@ +package io.quarkus.gradle.tasks; + +import static io.quarkus.gradle.tasks.AbstractQuarkusExtension.QUARKUS_PROFILE; +import static io.quarkus.gradle.tasks.AbstractQuarkusExtension.toManifestAttributeKey; +import static io.quarkus.gradle.tasks.AbstractQuarkusExtension.toManifestSectionAttributeKey; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.java.archives.Attributes; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; + +import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.maven.dependency.ResolvedDependency; + +public class EffectiveConfigProvider { + final ListProperty ignoredEntries; + final ConfigurableFileCollection mainResources; + final MapProperty forcedProperties; + final MapProperty projectProperties; + final MapProperty quarkusBuildProperties; + final MapProperty quarkusRelevantProjectProperties; + final MapProperty manifestAttributes; + final MapProperty manifestSections; + final Property nativeBuild; + final Property quarkusProfileSystemVariable; + final Property quarkusProfileEnvVariable; + + public EffectiveConfigProvider(ListProperty ignoredEntries, + ConfigurableFileCollection mainResources, + MapProperty forcedProperties, + MapProperty projectProperties, + MapProperty quarkusBuildProperties, + MapProperty quarkusRelevantProjectProperties, + MapProperty manifestAttributes, + MapProperty manifestSections, + Property nativeBuild, + Property quarkusProfileSystemVariable, + Property quarkusProfileEnvVariable) { + this.ignoredEntries = ignoredEntries; + this.mainResources = mainResources; + this.forcedProperties = forcedProperties; + this.projectProperties = projectProperties; + this.quarkusBuildProperties = quarkusBuildProperties; + this.quarkusRelevantProjectProperties = quarkusRelevantProjectProperties; + this.manifestAttributes = manifestAttributes; + this.manifestSections = manifestSections; + this.nativeBuild = nativeBuild; + this.quarkusProfileSystemVariable = quarkusProfileSystemVariable; + this.quarkusProfileEnvVariable = quarkusProfileEnvVariable; + } + + public EffectiveConfig buildEffectiveConfiguration(ApplicationModel appModel, + Map additionalForcedProperties) { + ResolvedDependency appArtifact = appModel.getAppArtifact(); + + Map properties = new HashMap<>(); + exportCustomManifestProperties(properties); + + Map defaultProperties = new HashMap<>(); + String userIgnoredEntries = String.join(",", ignoredEntries.get()); + if (!userIgnoredEntries.isEmpty()) { + defaultProperties.put("quarkus.package.jar.user-configured-ignored-entries", userIgnoredEntries); + } + Set resourcesDirs = mainResources.getFiles(); + defaultProperties.putIfAbsent("quarkus.application.name", appArtifact.getArtifactId()); + defaultProperties.putIfAbsent("quarkus.application.version", appArtifact.getVersion()); + + Map forced = new HashMap<>(forcedProperties.get()); + projectProperties.get().forEach((k, v) -> { + forced.put(k, v.toString()); + + }); + additionalForcedProperties.forEach((k, v) -> { + forced.put(k, v.toString()); + }); + if (nativeBuild.get()) { + forced.put("quarkus.native.enabled", "true"); + } + return EffectiveConfig.builder() + .withPlatformProperties(appModel.getPlatformProperties()) + .withForcedProperties(forced) + .withTaskProperties(properties) + .withBuildProperties(quarkusBuildProperties.get()) + .withProjectProperties(quarkusRelevantProjectProperties.get()) + .withDefaultProperties(defaultProperties) + .withSourceDirectories(resourcesDirs) + .withProfile(getQuarkusProfile()) + .build(); + } + + private void exportCustomManifestProperties(Map properties) { + for (Map.Entry attribute : manifestAttributes.get().entrySet()) { + properties.put(toManifestAttributeKey(attribute.getKey()), + attribute.getValue()); + } + + for (Map.Entry section : manifestSections.get().entrySet()) { + for (Map.Entry attribute : section.getValue().entrySet()) { + properties + .put(toManifestSectionAttributeKey(section.getKey(), attribute.getKey()), attribute.getValue()); + } + } + } + + private String getQuarkusProfile() { + String profile = quarkusProfileSystemVariable.getOrNull(); + if (profile == null) { + profile = quarkusProfileEnvVariable.getOrNull(); + } + if (profile == null) { + profile = quarkusBuildProperties.get().get(QUARKUS_PROFILE); + } + if (profile == null) { + Object p = quarkusRelevantProjectProperties.get().get(QUARKUS_PROFILE); + if (p != null) { + profile = p.toString(); + } + } + if (profile == null) { + profile = "prod"; + } + return profile; + } + +} diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildDependencies.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildDependencies.java index 7885ce37c0d1d..06d9e7a975a8d 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildDependencies.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildDependencies.java @@ -144,7 +144,7 @@ private void jarDependencies(Path libBoot, Path libMain) { } ApplicationModel appModel = resolveAppModelForBuild(); - SmallRyeConfig config = getExtensionView() + SmallRyeConfig config = effectiveProvider() .buildEffectiveConfiguration(appModel, new HashMap<>()) .getConfig(); diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildTask.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildTask.java index 39eae2b51e20b..939739a49ccd2 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildTask.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuildTask.java @@ -1,11 +1,18 @@ package io.quarkus.gradle.tasks; +import static io.smallrye.common.expression.Expression.Flag.DOUBLE_COLON; +import static io.smallrye.common.expression.Expression.Flag.LENIENT_SYNTAX; +import static io.smallrye.common.expression.Expression.Flag.NO_SMART_BRACES; +import static io.smallrye.common.expression.Expression.Flag.NO_TRIM; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; @@ -16,12 +23,12 @@ import org.gradle.api.file.FileSystemOperations; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.logging.LogLevel; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.StopExecutionException; @@ -33,35 +40,27 @@ import io.quarkus.gradle.tasks.services.ForcedPropertieBuildService; import io.quarkus.gradle.tasks.worker.BuildWorker; import io.quarkus.gradle.tooling.ToolingUtils; +import io.quarkus.maven.dependency.ResolvedDependency; +import io.smallrye.common.expression.Expression; import io.smallrye.config.Expressions; import io.smallrye.config.SmallRyeConfig; /** * Base class for the {@link QuarkusBuildDependencies}, {@link QuarkusBuildCacheableAppParts}, {@link QuarkusBuild} tasks */ -public abstract class QuarkusBuildTask extends QuarkusTask { +public abstract class QuarkusBuildTask extends QuarkusTaskWithExtensionView { private static final String QUARKUS_BUILD_DIR = "quarkus-build"; private static final String QUARKUS_BUILD_GEN_DIR = QUARKUS_BUILD_DIR + "/gen"; private static final String QUARKUS_BUILD_APP_DIR = QUARKUS_BUILD_DIR + "/app"; private static final String QUARKUS_BUILD_DEP_DIR = QUARKUS_BUILD_DIR + "/dep"; static final String QUARKUS_ARTIFACT_PROPERTIES = "quarkus-artifact.properties"; static final String NATIVE_SOURCES = "native-sources"; - private final QuarkusPluginExtensionView extensionView; @Internal public abstract Property getAdditionalForcedProperties(); QuarkusBuildTask(String description, boolean compatible) { super(description, compatible); - this.extensionView = getProject().getObjects().newInstance(QuarkusPluginExtensionView.class, extension()); - } - - /** - * Returns a view of the Quarkus extension that is compatible with the configuration cache. - */ - @Nested - protected QuarkusPluginExtensionView getExtensionView() { - return extensionView; } @Inject @@ -79,24 +78,43 @@ public void setCompileClasspath(FileCollection compileClasspath) { } @Input - public Map getCachingRelevantInput() { - return getExtensionView().getCachingRelevantInput().get(); - } + public abstract MapProperty getCachingRelevantInput(); + + @Input + public abstract Property getJarEnabled(); + + @Input + public abstract Property getNativeEnabled(); + + @Input + public abstract Property getNativeSourcesOnly(); + + @Internal + public abstract Property getRunnerSuffix(); + + @Internal + public abstract Property getRunnerName(); + + @Internal + public abstract Property getOutputDirectory(); + + @Input + public abstract Property getJarType(); PackageConfig.JarConfig.JarType jarType() { - return getExtensionView().getJarType().get(); + return getJarType().get(); } boolean jarEnabled() { - return getExtensionView().getJarEnabled().get(); + return getJarEnabled().get(); } boolean nativeEnabled() { - return getExtensionView().getNativeEnabled().get(); + return getNativeEnabled().get(); } boolean nativeSourcesOnly() { - return getExtensionView().getNativeSourcesOnly().get(); + return getNativeSourcesOnly().get(); } Path gradleBuildDir() { @@ -161,15 +179,15 @@ String nativeImageSourceJarDirName() { } String runnerBaseName() { - return getExtensionView().getRunnerName().get(); + return getRunnerName().get(); } String outputDirectory() { - return getExtensionView().getOutputDirectory().get().toString(); + return getOutputDirectory().get().toString(); } private String runnerSuffix() { - return getExtensionView().getRunnerSuffix().get(); + return getRunnerSuffix().get(); } @@ -243,7 +261,7 @@ void generateBuild() { }); ApplicationModel appModel = resolveAppModelForBuild(); - SmallRyeConfig config = getExtensionView() + SmallRyeConfig config = effectiveProvider() .buildEffectiveConfiguration(appModel, getAdditionalForcedProperties().get().getProperties()) .getConfig(); Map quarkusProperties = Expressions.withoutExpansion(() -> { @@ -278,8 +296,7 @@ void generateBuild() { WorkQueue workQueue = workQueue(quarkusProperties, getExtensionView().getBuildForkOptions().get()); workQueue.submit(BuildWorker.class, params -> { - params.getBuildSystemProperties() - .putAll(getExtensionView().buildSystemProperties(appModel.getAppArtifact(), quarkusProperties)); + params.getBuildSystemProperties().putAll(buildSystemProperties(appModel.getAppArtifact(), quarkusProperties)); params.getBaseName().set(getExtensionView().getFinalName()); params.getTargetDirectory().set(buildDir.toFile()); params.getAppModel().set(appModel); @@ -363,4 +380,53 @@ protected static void deleteFileIfExists(Path file) { throw new RuntimeException(e); } } + + private Map buildSystemProperties(ResolvedDependency appArtifact, Map quarkusProperties) { + Map buildSystemProperties = new HashMap<>(); + buildSystemProperties.putIfAbsent("quarkus.application.name", appArtifact.getArtifactId()); + buildSystemProperties.putIfAbsent("quarkus.application.version", appArtifact.getVersion()); + + for (Map.Entry entry : getExtensionView().getForcedProperties().get().entrySet()) { + if (entry.getKey().startsWith("quarkus.") || entry.getKey().startsWith("platform.quarkus.")) { + buildSystemProperties.put(entry.getKey(), entry.getValue()); + } + } + for (Map.Entry entry : getExtensionView().getQuarkusBuildProperties().get().entrySet()) { + if (entry.getKey().startsWith("quarkus.") || entry.getKey().startsWith("platform.quarkus.")) { + buildSystemProperties.put(entry.getKey(), entry.getValue()); + } + } + for (Map.Entry entry : getExtensionView().getProjectProperties().get().entrySet()) { + if ((entry.getKey().startsWith("quarkus.") || entry.getKey().startsWith("platform.quarkus.")) + && entry.getValue() != null) { + buildSystemProperties.put(entry.getKey(), entry.getValue().toString()); + } + } + + Set quarkusValues = new HashSet<>(); + quarkusValues.addAll(quarkusProperties.values()); + quarkusValues.addAll(buildSystemProperties.values()); + + for (String value : quarkusValues) { + Expression expression = Expression.compile(value, LENIENT_SYNTAX, NO_TRIM, NO_SMART_BRACES, DOUBLE_COLON); + for (String reference : expression.getReferencedStrings()) { + String expanded = getExtensionView().getForcedProperties().get().get(reference); + if (expanded != null) { + buildSystemProperties.put(reference, expanded); + continue; + } + + expanded = getExtensionView().getQuarkusBuildProperties().get().get(reference); + if (expanded != null) { + buildSystemProperties.put(reference, expanded); + continue; + } + expanded = (String) getExtensionView().getProjectProperties().get().get(reference); + if (expanded != null) { + buildSystemProperties.put(reference, expanded); + } + } + } + return buildSystemProperties; + } } diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusGenerateCode.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusGenerateCode.java index 02960f536b33a..4360114e897a8 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusGenerateCode.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusGenerateCode.java @@ -24,7 +24,6 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.InputFiles; -import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; @@ -38,7 +37,7 @@ import io.quarkus.runtime.LaunchMode; @CacheableTask -public abstract class QuarkusGenerateCode extends QuarkusTask { +public abstract class QuarkusGenerateCode extends QuarkusTaskWithExtensionView { public static final String QUARKUS_GENERATED_SOURCES = "quarkus-generated-sources"; public static final String QUARKUS_TEST_GENERATED_SOURCES = "quarkus-test-generated-sources"; @@ -49,7 +48,6 @@ public abstract class QuarkusGenerateCode extends QuarkusTask { private final LaunchMode launchMode; private final String inputSourceSetName; - private final QuarkusPluginExtensionView extensionView; private final List codeGenInput; @Inject @@ -57,16 +55,10 @@ public QuarkusGenerateCode(LaunchMode launchMode, String inputSourceSetName, Lis super("Performs Quarkus pre-build preparations, such as sources generation", true); this.launchMode = launchMode; this.inputSourceSetName = inputSourceSetName; - this.extensionView = getProject().getObjects().newInstance(QuarkusPluginExtensionView.class, extension()); this.codeGenInput = codeGenInput; } - @Nested - protected QuarkusPluginExtensionView getExtensionView() { - return extensionView; - } - /** * Create a dependency on classpath resolution. This makes sure included build are build this task runs. * @@ -118,7 +110,7 @@ public Set getInputDirectory() { @TaskAction public void generateCode() throws IOException { ApplicationModel appModel = ToolingUtils.deserializeAppModel(getApplicationModel().get().getAsFile().toPath()); - Map configMap = getExtensionView() + Map configMap = effectiveProvider() .buildEffectiveConfiguration(appModel, new HashMap<>()).getValues(); File outputPath = getGeneratedOutputDirectory().get().getAsFile(); diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusPluginExtensionView.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusPluginExtensionView.java index 5738aabdea8b9..500f6e0c5b7ba 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusPluginExtensionView.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusPluginExtensionView.java @@ -3,20 +3,10 @@ import static io.quarkus.gradle.QuarkusPlugin.BUILD_NATIVE_TASK_NAME; import static io.quarkus.gradle.QuarkusPlugin.TEST_NATIVE_TASK_NAME; import static io.quarkus.gradle.tasks.AbstractQuarkusExtension.QUARKUS_PROFILE; -import static io.quarkus.gradle.tasks.AbstractQuarkusExtension.toManifestAttributeKey; -import static io.quarkus.gradle.tasks.AbstractQuarkusExtension.toManifestSectionAttributeKey; -import static io.smallrye.common.expression.Expression.Flag.DOUBLE_COLON; -import static io.smallrye.common.expression.Expression.Flag.LENIENT_SYNTAX; -import static io.smallrye.common.expression.Expression.Flag.NO_SMART_BRACES; -import static io.smallrye.common.expression.Expression.Flag.NO_TRIM; import static org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME; -import java.io.File; -import java.nio.file.Path; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; @@ -24,7 +14,6 @@ import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.java.archives.Attributes; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; @@ -38,13 +27,7 @@ import org.gradle.process.JavaForkOptions; import org.gradle.util.GradleVersion; -import io.quarkus.bootstrap.model.ApplicationModel; -import io.quarkus.deployment.pkg.PackageConfig; -import io.quarkus.gradle.QuarkusPlugin; -import io.quarkus.gradle.dsl.Manifest; import io.quarkus.gradle.extension.QuarkusPluginExtension; -import io.quarkus.maven.dependency.ResolvedDependency; -import io.smallrye.common.expression.Expression; /** * Configuration cache compatible view of Quarkus extension @@ -73,8 +56,7 @@ public QuarkusPluginExtensionView(Project project, QuarkusPluginExtension extens getQuarkusRelevantProjectProperties().set(getQuarkusRelevantProjectProperties(project)); getQuarkusProfileSystemVariable().set(getProviderFactory().systemProperty(QUARKUS_PROFILE)); getQuarkusProfileEnvVariable().set(getProviderFactory().environmentVariable("QUARKUS_PROFILE")); - getCachingRelevantInput() - .set(extension.baseConfig().cachingRelevantProperties(extension.getCachingRelevantProperties().get())); + getCachingRelevantProperties().set(extension.getCachingRelevantProperties()); getForcedProperties().set(extension.forcedPropertiesProperty()); Map projectProperties = new HashMap<>(); for (Map.Entry entry : project.getProperties().entrySet()) { @@ -83,16 +65,6 @@ public QuarkusPluginExtensionView(Project project, QuarkusPluginExtension extens } } getProjectProperties().set(projectProperties); - getJarEnabled().set(extension.baseConfig().packageConfig().jar().enabled()); - getManifestAttributes().set(extension.manifest().getAttributes()); - getManifestSections().set(extension.manifest().getSections()); - getNativeEnabled().set(extension.baseConfig().nativeConfig().enabled()); - getNativeSourcesOnly().set(extension.baseConfig().nativeConfig().sourcesOnly()); - getRunnerSuffix().set(extension.baseConfig().packageConfig().computedRunnerSuffix()); - getRunnerName().set(extension.baseConfig().packageConfig().outputName().orElseGet(extension::finalName)); - getOutputDirectory().set(Path.of(extension.baseConfig().packageConfig().outputDirectory().map(Path::toString) - .orElse(QuarkusPlugin.DEFAULT_OUTPUT_DIRECTORY))); - getJarType().set(extension.baseConfig().jarType()); } private Provider> getQuarkusRelevantProjectProperties(Project project) { @@ -117,6 +89,9 @@ private Provider> getQuarkusRelevantProjectProperties(Projec @Input public abstract Property getCacheLargeArtifacts(); + @Input + public abstract ListProperty getCachingRelevantProperties(); + @Input public abstract Property getCleanupBuildOutput(); @@ -132,22 +107,6 @@ private Provider> getQuarkusRelevantProjectProperties(Projec @Nested public abstract ListProperty> getBuildForkOptions(); - @Input - @Optional - public abstract Property getJarEnabled(); - - @Input - @Optional - public abstract Property getNativeEnabled(); - - @Input - @Optional - public abstract Property getManifest(); - - @Input - @Optional - public abstract Property getNativeSourcesOnly(); - @Input public abstract ListProperty getIgnoredEntries(); @@ -160,18 +119,6 @@ private Provider> getQuarkusRelevantProjectProperties(Projec @Internal public abstract ConfigurableFileCollection getMainResources(); - @Internal - public abstract Property getRunnerSuffix(); - - @Internal - public abstract Property getRunnerName(); - - @Internal - public abstract Property getOutputDirectory(); - - @Input - public abstract Property getJarType(); - @Input @Optional public abstract Property getQuarkusProfileSystemVariable(); @@ -180,141 +127,8 @@ private Provider> getQuarkusRelevantProjectProperties(Projec @Optional public abstract Property getQuarkusProfileEnvVariable(); - @Input - @Optional - public abstract MapProperty getCachingRelevantInput(); - @Input @Optional public abstract MapProperty getForcedProperties(); - @Input - @Optional - public abstract MapProperty getManifestAttributes(); - - @Input - @Optional - public abstract MapProperty getManifestSections(); - - private void exportCustomManifestProperties(Map properties) { - for (Map.Entry attribute : getManifestAttributes().get().entrySet()) { - properties.put(toManifestAttributeKey(attribute.getKey()), - attribute.getValue()); - } - - for (Map.Entry section : getManifestSections().get().entrySet()) { - for (Map.Entry attribute : section.getValue().entrySet()) { - properties - .put(toManifestSectionAttributeKey(section.getKey(), attribute.getKey()), attribute.getValue()); - } - } - } - - public EffectiveConfig buildEffectiveConfiguration(ApplicationModel appModel, - Map additionalForcedProperties) { - ResolvedDependency appArtifact = appModel.getAppArtifact(); - - Map properties = new HashMap<>(); - exportCustomManifestProperties(properties); - - Map defaultProperties = new HashMap<>(); - String userIgnoredEntries = String.join(",", getIgnoredEntries().get()); - if (!userIgnoredEntries.isEmpty()) { - defaultProperties.put("quarkus.package.jar.user-configured-ignored-entries", userIgnoredEntries); - } - Set resourcesDirs = getMainResources().getFiles(); - defaultProperties.putIfAbsent("quarkus.application.name", appArtifact.getArtifactId()); - defaultProperties.putIfAbsent("quarkus.application.version", appArtifact.getVersion()); - - Map forced = new HashMap<>(getForcedProperties().get()); - getProjectProperties().get().forEach((k, v) -> { - forced.put(k, v.toString()); - - }); - additionalForcedProperties.forEach((k, v) -> { - forced.put(k, v.toString()); - }); - if (getNativeBuild().get()) { - forced.put("quarkus.native.enabled", "true"); - } - return EffectiveConfig.builder() - .withPlatformProperties(appModel.getPlatformProperties()) - .withForcedProperties(forced) - .withTaskProperties(properties) - .withBuildProperties(getQuarkusBuildProperties().get()) - .withProjectProperties(getQuarkusRelevantProjectProperties().get()) - .withDefaultProperties(defaultProperties) - .withSourceDirectories(resourcesDirs) - .withProfile(getQuarkusProfile()) - .build(); - } - - protected Map buildSystemProperties(ResolvedDependency appArtifact, Map quarkusProperties) { - Map buildSystemProperties = new HashMap<>(); - buildSystemProperties.putIfAbsent("quarkus.application.name", appArtifact.getArtifactId()); - buildSystemProperties.putIfAbsent("quarkus.application.version", appArtifact.getVersion()); - - for (Map.Entry entry : getForcedProperties().get().entrySet()) { - if (entry.getKey().startsWith("quarkus.") || entry.getKey().startsWith("platform.quarkus.")) { - buildSystemProperties.put(entry.getKey(), entry.getValue()); - } - } - for (Map.Entry entry : getQuarkusBuildProperties().get().entrySet()) { - if (entry.getKey().startsWith("quarkus.") || entry.getKey().startsWith("platform.quarkus.")) { - buildSystemProperties.put(entry.getKey(), entry.getValue()); - } - } - for (Map.Entry entry : getProjectProperties().get().entrySet()) { - if ((entry.getKey().startsWith("quarkus.") || entry.getKey().startsWith("platform.quarkus.")) - && entry.getValue() != null) { - buildSystemProperties.put(entry.getKey(), entry.getValue().toString()); - } - } - - Set quarkusValues = new HashSet<>(); - quarkusValues.addAll(quarkusProperties.values()); - quarkusValues.addAll(buildSystemProperties.values()); - - for (String value : quarkusValues) { - Expression expression = Expression.compile(value, LENIENT_SYNTAX, NO_TRIM, NO_SMART_BRACES, DOUBLE_COLON); - for (String reference : expression.getReferencedStrings()) { - String expanded = getForcedProperties().get().get(reference); - if (expanded != null) { - buildSystemProperties.put(reference, expanded); - continue; - } - - expanded = getQuarkusBuildProperties().get().get(reference); - if (expanded != null) { - buildSystemProperties.put(reference, expanded); - continue; - } - expanded = (String) getProjectProperties().get().get(reference); - if (expanded != null) { - buildSystemProperties.put(reference, expanded); - } - } - } - return buildSystemProperties; - } - - private String getQuarkusProfile() { - String profile = getQuarkusProfileSystemVariable().getOrNull(); - if (profile == null) { - profile = getQuarkusProfileEnvVariable().getOrNull(); - } - if (profile == null) { - profile = getQuarkusBuildProperties().get().get(QUARKUS_PROFILE); - } - if (profile == null) { - Object p = getQuarkusRelevantProjectProperties().get().get(QUARKUS_PROFILE); - if (p != null) { - profile = p.toString(); - } - } - if (profile == null) { - profile = "prod"; - } - return profile; - } } diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusShowEffectiveConfig.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusShowEffectiveConfig.java index 6d5af8ef63caa..46cc30e58dba6 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusShowEffectiveConfig.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusShowEffectiveConfig.java @@ -48,7 +48,7 @@ public Property getSaveConfigProperties() { public void dumpEffectiveConfiguration() { try { ApplicationModel appModel = resolveAppModelForBuild(); - EffectiveConfig effectiveConfig = getExtensionView() + EffectiveConfig effectiveConfig = effectiveProvider() .buildEffectiveConfiguration(appModel, getAdditionalForcedProperties().get().getProperties()); SmallRyeConfig config = effectiveConfig.getConfig(); diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTaskWithExtensionView.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTaskWithExtensionView.java new file mode 100644 index 0000000000000..776f94e723b8a --- /dev/null +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTaskWithExtensionView.java @@ -0,0 +1,63 @@ +package io.quarkus.gradle.tasks; + +import org.gradle.api.java.archives.Attributes; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; + +/** + * Quarkus task providing inputs compatible with the configuration cache, used by the {@link QuarkusGenerateCode} + * and {@link QuarkusBuildTask} tasks. + *

+ * Most inputs are provided by the {@link QuarkusPluginExtensionView}. This includes those required by both tasks, + * and additional inputs that require initialization of the {@link BaseConfig} object. + *

+ *

+ * Additionally, this class provides an {@link EffectiveConfigProvider}, which is used by dependent tasks + * to access the inputs defined in this task. + *

+ */ +public abstract class QuarkusTaskWithExtensionView extends QuarkusTask { + + private final QuarkusPluginExtensionView extensionView; + + @Input + @Optional + public abstract MapProperty getManifestAttributes(); + + @Input + @Optional + public abstract MapProperty getManifestSections(); + + @Input + public abstract MapProperty getCachingRelevantInput(); + + public QuarkusTaskWithExtensionView(String description, boolean compatible) { + super(description, compatible); + this.extensionView = getProject().getObjects().newInstance(QuarkusPluginExtensionView.class, extension()); + } + + public EffectiveConfigProvider effectiveProvider() { + return new EffectiveConfigProvider( + getExtensionView().getIgnoredEntries(), + getExtensionView().getMainResources(), + getExtensionView().getForcedProperties(), + getExtensionView().getProjectProperties(), + getExtensionView().getQuarkusBuildProperties(), + getExtensionView().getQuarkusRelevantProjectProperties(), + getManifestAttributes(), + getManifestSections(), + getExtensionView().getNativeBuild(), + getExtensionView().getQuarkusProfileSystemVariable(), + getExtensionView().getQuarkusProfileEnvVariable()); + } + + /** + * Returns a view of the Quarkus extension that is compatible with the configuration cache. + */ + @Nested + protected QuarkusPluginExtensionView getExtensionView() { + return extensionView; + } +} diff --git a/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/tasks/EagerResolutionTaskTest.java b/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/tasks/EagerResolutionTaskTest.java new file mode 100644 index 0000000000000..84c17c8c7eaa6 --- /dev/null +++ b/devtools/gradle/gradle-application-plugin/src/test/java/io/quarkus/gradle/tasks/EagerResolutionTaskTest.java @@ -0,0 +1,82 @@ +package io.quarkus.gradle.tasks; + +import static io.quarkus.gradle.QuarkusPlugin.QUARKUS_BUILD_TASK_NAME; +import static io.quarkus.gradle.QuarkusPlugin.QUARKUS_GENERATE_CODE_TASK_NAME; +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.stream.Stream; + +import org.apache.commons.io.FileUtils; +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.GradleRunner; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class EagerResolutionTaskTest { + + @TempDir + Path testProjectDir; + + private static Stream tasksToTest() { + return Stream.of( + QUARKUS_GENERATE_CODE_TASK_NAME, + QUARKUS_BUILD_TASK_NAME, + "build", + "classes"); + } + + @ParameterizedTest + @MethodSource("tasksToTest") + public void eagerResolutionConfigurationBuildsSuccessfully(String taskName) throws IOException, URISyntaxException { + URL url = getClass().getClassLoader().getResource("io/quarkus/gradle/tasks/crypto/main"); + FileUtils.copyDirectory(new File(url.toURI()), testProjectDir.toFile()); + FileUtils.copyFile(new File("../gradle.properties"), testProjectDir.resolve("gradle.properties").toFile()); + + File projectDir = new File(testProjectDir + "/build.gradle.kts"); + + String addingQuarkusExtension = """ + quarkus { + cachingRelevantProperties.add("FOO_ENV_VAR") + quarkusBuildProperties.put("quarkus.package.type", "fast-jar") + quarkusBuildProperties.putAll( + provider { + tasks + .named("jar", Jar::class.java) + .get() + .manifest + .attributes + .map { e -> "quarkus.package.jar.manifest.attributes.\\"${e.key}\\"" to e.value.toString() } + .toMap() + } + ) + } + + """; + try { + Files.write(projectDir.toPath(), addingQuarkusExtension.getBytes(), StandardOpenOption.APPEND); + } catch (IOException e) { + e.printStackTrace(); + } + + BuildResult firstBuild = buildResult(taskName); + assertEquals(SUCCESS, firstBuild.task(":quarkusGenerateCode").getOutcome()); + + } + + private BuildResult buildResult(String task) { + return GradleRunner.create() + .withPluginClasspath() + .withProjectDir(testProjectDir.toFile()) + .withArguments(task, "--info", "--stacktrace", "--build-cache") + .build(); + } +}