diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRun.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRun.java new file mode 100644 index 0000000000..527e8336c2 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRun.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.gradle.run; + +import org.gradle.api.file.SourceDirectorySet; +import org.gradle.api.tasks.JavaExec; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetOutput; + +/** + * Custom {@link JavaExec} task for running a Spring Boot application. + * + * @author Andy Wilkinson + */ +public class BootRun extends JavaExec { + + /** + * Adds the {@link SourceDirectorySet#getSrcDirs() source directories} of the given + * {@code sourceSet's} {@link SourceSet#getResources() resources} to the start of the + * classpath in place of the {@link SourceSet#getOutput output's} + * {@link SourceSetOutput#getResourcesDir() resources directory}. + * + * @param sourceSet the source set + */ + public void sourceResources(SourceSet sourceSet) { + setClasspath(getProject() + .files(sourceSet.getResources().getSrcDirs(), getClasspath()) + .filter((file) -> !file.equals(sourceSet.getOutput().getResourcesDir()))); + } + + @Override + public void exec() { + if (System.console() != null) { + // Record that the console is available here for AnsiOutput to detect later + this.getEnvironment().put("spring.output.ansi.console-available", true); + } + super.exec(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java deleted file mode 100644 index c5808cd0d1..0000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.gradle.run; - -import java.io.File; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import org.gradle.api.internal.file.collections.SimpleFileCollection; -import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSet; - -import org.springframework.boot.loader.tools.FileUtils; - -/** - * Extension of the standard 'run' task with additional Spring Boot features. - * - * @author Dave Syer - * @author Phillip Webb - * @author Andy Wilkinson - */ -public class BootRunTask extends JavaExec { - - /** - * Whether or not resources (typically in {@code src/main/resources} are added - * directly to the classpath. When enabled, this allows live in-place editing of - * resources. Duplicate resources are removed from the resource output directory to - * prevent them from appearing twice if {@code ClassLoader.getResources()} is called. - */ - private boolean addResources = false; - - public boolean getAddResources() { - return this.addResources; - } - - public void setAddResources(boolean addResources) { - this.addResources = addResources; - } - - @Override - public void exec() { - if (System.console() != null) { - // Record that the console is available here for AnsiOutput to detect later - this.getEnvironment().put("spring.output.ansi.console-available", true); - } - addResourcesIfNecessary(); - super.exec(); - } - - private void addResourcesIfNecessary() { - if (this.addResources) { - SourceSet mainSourceSet = SourceSets.findMainSourceSet(getProject()); - final File outputDir = (mainSourceSet == null ? null - : mainSourceSet.getOutput().getResourcesDir()); - final Set resources = new LinkedHashSet<>(); - if (mainSourceSet != null) { - resources.addAll(mainSourceSet.getResources().getSrcDirs()); - } - List classPath = new ArrayList<>(getClasspath().getFiles()); - classPath.addAll(0, resources); - getLogger().info("Adding classpath: " + resources); - setClasspath(new SimpleFileCollection(classPath)); - if (outputDir != null) { - for (File directory : resources) { - FileUtils.removeDuplicatesFromOutputDirectory(outputDir, directory); - } - } - } - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java index 17e243334d..0ad7034b4f 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java @@ -22,6 +22,7 @@ import java.util.concurrent.Callable; import org.gradle.api.Project; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.SourceSet; import org.springframework.boot.gradle.MainClassResolver; import org.springframework.boot.gradle.PluginFeatures; @@ -30,6 +31,7 @@ import org.springframework.boot.gradle.PluginFeatures; * {@link PluginFeatures} to add run support. * * @author Phillip Webb + * @author Andy Wilkinson */ public class RunPluginFeatures implements PluginFeatures { @@ -46,12 +48,12 @@ public class RunPluginFeatures implements PluginFeatures { final JavaPluginConvention javaConvention = project.getConvention() .getPlugin(JavaPluginConvention.class); - BootRunTask run = project.getTasks().create(RUN_APP_TASK_NAME, BootRunTask.class); + BootRun run = project.getTasks().create(RUN_APP_TASK_NAME, BootRun.class); run.setDescription("Run the project with support for " + "auto-detecting main class and reloading static resources"); run.setGroup("application"); - run.setClasspath( - javaConvention.getSourceSets().findByName("main").getRuntimeClasspath()); + run.classpath(javaConvention.getSourceSets() + .findByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath()); run.getConventionMapping().map("jvmArgs", new Callable() { @Override public Object call() throws Exception { diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/com/example/BootRunApplication.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/com/example/BootRunApplication.java new file mode 100644 index 0000000000..95cc04e06f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/com/example/BootRunApplication.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example; + +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Very basic application used for testing {@code BootRun}. + * + * @author Andy Wilkinson + */ +public class BootRunApplication { + + protected BootRunApplication() { + + } + + public static void main(String[] args) { + int i = 1; + for (URL url : ((URLClassLoader) BootRunApplication.class.getClassLoader()) + .getURLs()) { + System.out.println(i++ + ". " + url); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/run/BootRunIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/run/BootRunIntegrationTests.java new file mode 100644 index 0000000000..5945b21551 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/run/BootRunIntegrationTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.gradle.run; + +import java.io.File; +import java.io.IOException; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; +import org.springframework.util.FileSystemUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link BootRun}. + * + * @author Andy Wilkinson + */ +public class BootRunIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void basicExecution() throws IOException { + File output = new File(this.gradleBuild.getProjectDir(), + "src/main/java/com/example"); + output.mkdirs(); + FileSystemUtils.copyRecursively(new File("src/test/java/com/example"), output); + new File(this.gradleBuild.getProjectDir(), "src/main/resources").mkdirs(); + BuildResult result = this.gradleBuild.build("bootRun"); + assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("1. " + urlOf("build/classes/main")); + assertThat(result.getOutput()).contains("2. " + urlOf("build/resources/main")); + assertThat(result.getOutput()).doesNotContain(urlOf("src/main/resources")); + } + + @Test + public void sourceResourcesCanBeUsed() throws IOException { + File output = new File(this.gradleBuild.getProjectDir(), + "src/main/java/com/example"); + output.mkdirs(); + FileSystemUtils.copyRecursively(new File("src/test/java/com/example"), output); + BuildResult result = this.gradleBuild.build("bootRun"); + assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("1. " + urlOf("src/main/resources")); + assertThat(result.getOutput()).contains("2. " + urlOf("build/classes/main")); + assertThat(result.getOutput()).doesNotContain(urlOf("build/resources/main")); + } + + private String urlOf(String path) throws IOException { + return new File(this.gradleBuild.getProjectDir().getCanonicalFile(), path).toURI() + .toURL().toString(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java index 078446016d..7d5f5eb6c0 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java @@ -39,6 +39,7 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.xml.sax.InputSource; +import org.springframework.asm.ClassVisitor; import org.springframework.boot.loader.tools.LaunchScript; /** @@ -106,6 +107,7 @@ public class GradleBuild implements TestRule { return absolutePath("bin") + "," + absolutePath("build/classes/main") + "," + absolutePath("build/resources/main") + "," + pathOfJarContaining(LaunchScript.class) + "," + + pathOfJarContaining(ClassVisitor.class) + "," + pathOfJarContaining(DependencyManagementPlugin.class); } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/run/BootRunIntegrationTests-basicExecution.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/run/BootRunIntegrationTests-basicExecution.gradle new file mode 100644 index 0000000000..97d0d1c7e3 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/run/BootRunIntegrationTests-basicExecution.gradle @@ -0,0 +1,8 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle new file mode 100644 index 0000000000..47504d6d74 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle @@ -0,0 +1,12 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' + +bootRun { + sourceResources sourceSets.main +}