From 434f528e0a5810755d73be8d83e9927976ad8f97 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 22 Jul 2015 13:47:24 +0100 Subject: [PATCH] Fix Gradle plugin task dependencies broken by removal of app plugin 8673250 updated the plugin so that the application plugin is no longer applied by default. This exposed three problems: 1. bootRepackage may run before findMainClass has run, leaving it with an unknown main class. 2. findMainClass may run before the classes have been built, making it unable to find the main class by examining the class files 3. The project's mainClassName property was still being used as a convention for the bootRun task's main property. If the application plugin has not be applied, then this property does not exist. The first problem has been addressed by configuring bootRepackage to depend on findMainClass. The second problem has been addressed by configuring the main source set's output as an input of findMainClass, and configuring findMainClass to depend on the tasks that build the output. The third problem has been addressed by only using the mainClassName property if it exists and its value is not null. We then fallback to using the mainClassName property on the project's extra properties in the same way. See gh-2679 --- .../boot/gradle/InstallTests.java | 3 +- .../boot/gradle/MainClassTests.java | 6 ++-- .../src/test/resources/flatdir.gradle | 2 +- .../src/test/resources/install-app.gradle | 3 +- ...-in-run.gradle => main-in-boot-run.gradle} | 2 +- .../repackage/RepackagePluginFeatures.java | 6 ++++ .../boot/gradle/repackage/RepackageTask.java | 23 +++++++++++---- .../boot/gradle/run/FindMainClassTask.java | 28 +++++++++++++++---- .../boot/gradle/run/RunPluginFeatures.java | 21 ++++++++++++-- 9 files changed, 73 insertions(+), 21 deletions(-) rename spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/{main-in-run.gradle => main-in-boot-run.gradle} (97%) diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java index 6ab58ae0ea..1725c955a0 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java @@ -43,8 +43,7 @@ public class InstallTests { // "install" from the application plugin was renamed "installApp" in Gradle // 1.0 this.project.newBuild().forTasks("installApp") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace", "--info") - .run(); + .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace").run(); } } diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java index c006e871b7..7712e91fdc 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java @@ -23,7 +23,7 @@ import org.junit.BeforeClass; import org.junit.Test; /** - * Tests for using the Gradle plugin's support for installing artifacts + * Tests for configuring a project's main class * * @author Dave Syer */ @@ -35,11 +35,11 @@ public class MainClassTests { @BeforeClass public static void createProject() throws IOException { - project = new ProjectCreator().createProject("main-in-run"); + project = new ProjectCreator().createProject("main-in-boot-run"); } @Test - public void buildFromRunTask() { + public void mainFromBootRun() { project.newBuild().forTasks("build") .withArguments("-PbootVersion=" + BOOT_VERSION, "--info").run(); } diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle index 7f4bdde011..fdb8314972 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle @@ -12,7 +12,7 @@ apply plugin: 'spring-boot' group = 'flatdir' version = '0.0.0' -run { +bootRun { main = 'Foo' } diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle index fce05a8137..88a966b098 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle @@ -10,11 +10,12 @@ buildscript { apply plugin: 'java' apply plugin: 'maven' apply plugin: 'spring-boot' +apply plugin: 'application' group = 'installer' version = '0.0.0' -run { +bootRun { main = 'org.springframework.boot.SpringApplication' } diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-in-run.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-in-boot-run.gradle similarity index 97% rename from spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-in-run.gradle rename to spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-in-boot-run.gradle index a0a7b94c54..ad06027a0f 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-in-run.gradle +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-in-boot-run.gradle @@ -14,7 +14,7 @@ apply plugin: 'spring-boot' group = 'installer' version = '0.0.0' -run { +bootRun { main = 'org.springframework.boot.SpringApplication' } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java index c4679f64d0..fa78610c44 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java @@ -31,6 +31,7 @@ import org.gradle.api.tasks.TaskDependency; import org.gradle.api.tasks.bundling.Jar; import org.springframework.boot.gradle.PluginFeatures; import org.springframework.boot.gradle.SpringBootPluginExtension; +import org.springframework.boot.gradle.run.FindMainClassTask; import org.springframework.boot.loader.tools.Library; import org.springframework.boot.loader.tools.LibraryCallback; import org.springframework.util.StringUtils; @@ -69,6 +70,7 @@ public class RepackagePluginFeatures implements PluginFeatures { runtimeProjectDependencyJarTasks); registerOutput(project, task); ensureTaskRunsOnAssembly(project, task); + ensureMainClassHasBeenFound(project, task); } private void registerOutput(Project project, final RepackageTask task) { @@ -89,6 +91,10 @@ public class RepackagePluginFeatures implements PluginFeatures { project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(task); } + private void ensureMainClassHasBeenFound(Project project, Task task) { + task.dependsOn(project.getTasks().withType(FindMainClassTask.class)); + } + /** * Register BootRepackage so that we can use task {@code foo(type: BootRepackage)}. */ diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java index 34fcc41f9d..af1b1b9b6d 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java @@ -25,6 +25,8 @@ import java.util.concurrent.TimeUnit; import org.gradle.api.Action; import org.gradle.api.DefaultTask; import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.ExtraPropertiesExtension; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.bundling.Jar; import org.springframework.boot.gradle.SpringBootPluginExtension; @@ -194,16 +196,27 @@ public class RepackageTask extends DefaultTask { } private void setMainClass(Repackager repackager) { - String mainClass = (String) getProject().property("mainClassName"); + String mainClass; + if (getProject().hasProperty("mainClassName")) { + mainClass = (String) getProject().property("mainClassName"); + } + else { + ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) getProject() + .getExtensions().getByName("ext"); + mainClass = (String) extraProperties.get("mainClassName"); + } if (RepackageTask.this.mainClass != null) { mainClass = RepackageTask.this.mainClass; } else if (this.extension.getMainClass() != null) { mainClass = this.extension.getMainClass(); } - else if (getProject().getTasks().getByName("run").hasProperty("main")) { - mainClass = (String) getProject().getTasks().getByName("run") - .property("main"); + else { + Task runTask = getProject().getTasks().findByName("run"); + if (runTask != null && runTask.hasProperty("main")) { + mainClass = (String) getProject().getTasks().getByName("run") + .property("main"); + } } getLogger().info("Setting mainClass: " + mainClass); repackager.setMainClass(mainClass); @@ -211,7 +224,7 @@ public class RepackageTask extends DefaultTask { private LaunchScript getLaunchScript() throws IOException { if (this.extension.isExecutable() - || extension.getEmbeddedLaunchScript() != null) { + || this.extension.getEmbeddedLaunchScript() != null) { return new DefaultLaunchScript(this.extension.getEmbeddedLaunchScript(), this.extension.getEmbeddedLaunchScriptProperties()); } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/FindMainClassTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/FindMainClassTask.java index cb0b1fea96..dfc557ace2 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/FindMainClassTask.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/FindMainClassTask.java @@ -23,7 +23,8 @@ import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.plugins.ApplicationPluginConvention; import org.gradle.api.plugins.ExtraPropertiesExtension; -import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.SourceSetOutput; import org.gradle.api.tasks.TaskAction; import org.springframework.boot.gradle.SpringBootPluginExtension; import org.springframework.boot.loader.tools.MainClassFinder; @@ -38,6 +39,14 @@ import org.springframework.boot.loader.tools.MainClassFinder; */ public class FindMainClassTask extends DefaultTask { + @Input + private SourceSetOutput mainClassSourceSetOutput; + + public void setMainClassSourceSetOutput(SourceSetOutput sourceSetOutput) { + this.mainClassSourceSetOutput = sourceSetOutput; + this.dependsOn(this.mainClassSourceSetOutput.getBuildDependencies()); + } + @TaskAction public void setMainClassNameProperty() { Project project = getProject(); @@ -80,16 +89,23 @@ public class FindMainClassTask extends DefaultTask { mainClass = (String) runTask.property("main"); } + if (mainClass == null) { + Task bootRunTask = project.getTasks().findByName("bootRun"); + if (bootRunTask != null) { + mainClass = (String) bootRunTask.property("main"); + } + } + if (mainClass == null) { // Search - SourceSet mainSourceSet = SourceSets.findMainSourceSet(project); - if (mainSourceSet != null) { + if (this.mainClassSourceSetOutput != null) { project.getLogger().debug( "Looking for main in: " - + mainSourceSet.getOutput().getClassesDir()); + + this.mainClassSourceSetOutput.getClassesDir()); try { - mainClass = MainClassFinder.findSingleMainClass(mainSourceSet - .getOutput().getClassesDir()); + mainClass = MainClassFinder + .findSingleMainClass(this.mainClassSourceSetOutput + .getClassesDir()); project.getLogger().info("Computed main class: " + mainClass); } catch (IOException ex) { diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/RunPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/RunPluginFeatures.java index 181f185433..8e6754e6b6 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/RunPluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/RunPluginFeatures.java @@ -22,8 +22,10 @@ import java.util.concurrent.Callable; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.Task; +import org.gradle.api.plugins.ExtraPropertiesExtension; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.JavaExec; +import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.application.CreateStartScripts; import org.springframework.boot.gradle.PluginFeatures; @@ -45,7 +47,12 @@ public class RunPluginFeatures implements PluginFeatures { } private void mainClassNameFinder(Project project) { - project.getTasks().create(FIND_MAIN_CLASS_TASK_NAME, FindMainClassTask.class); + FindMainClassTask findMainClassTask = project.getTasks().create( + FIND_MAIN_CLASS_TASK_NAME, FindMainClassTask.class); + SourceSet mainSourceSet = SourceSets.findMainSourceSet(project); + if (mainSourceSet != null) { + findMainClassTask.setMainClassSourceSetOutput(mainSourceSet.getOutput()); + } project.getTasks().all(new Action() { @Override public void execute(Task task) { @@ -69,7 +76,17 @@ public class RunPluginFeatures implements PluginFeatures { run.getConventionMapping().map("main", new Callable() { @Override public Object call() throws Exception { - return project.property("mainClassName"); + if (project.hasProperty("mainClassName") + && project.property("mainClassName") != null) { + return project.property("mainClassName"); + } + ExtraPropertiesExtension extraPropertiesExtension = (ExtraPropertiesExtension) project + .getExtensions().getByName("ext"); + if (extraPropertiesExtension.has("mainClassName") + && extraPropertiesExtension.get("mainClassName") != null) { + return extraPropertiesExtension.get("mainClassName"); + } + return null; } }); run.getConventionMapping().map("jvmArgs", new Callable() {