diff --git a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc index 2b58543f463..607ea8ce6fd 100644 --- a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc +++ b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc @@ -400,8 +400,9 @@ The following configuration options are available: |Name |Description |`mainClass` -|The main class that should be run. If not specified the value from the manifest will be - used, or if no manifest entry is the archive will be searched for a suitable class. +|The main class that should be run. If not specified the `mainClassName` project property + will be used or, if the no `mainClassName` id defined the archive will be searched for a + suitable class. |`providedConfiguration` |The name of the provided configuration (defaults to `providedRuntime`). diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/PluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/PluginFeatures.java new file mode 100644 index 00000000000..acc51a57c95 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/PluginFeatures.java @@ -0,0 +1,35 @@ +/* + * Copyright 2012-2014 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; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; + +/** + * A specific set of {@link Plugin} features applied via the {@link SpringBootPlugin}. + * + * @author Phillip Webb + */ +public interface PluginFeatures { + + /** + * Apply the features to the specified project. + * @param project the project to apply features to + */ + public void apply(Project project); + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java index 53ec8d3ab50..2c05560cdac 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java @@ -16,19 +16,15 @@ package org.springframework.boot.gradle; -import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; import org.gradle.api.plugins.ApplicationPlugin; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.JavaExec; -import org.springframework.boot.gradle.task.ComputeMain; -import org.springframework.boot.gradle.task.Repackage; -import org.springframework.boot.gradle.task.RunApp; -import org.springframework.boot.gradle.task.RunWithAgent; +import org.springframework.boot.gradle.agent.AgentPluginFeatures; +import org.springframework.boot.gradle.repackage.RepackagePluginFeatures; +import org.springframework.boot.gradle.resolve.ResolvePluginFeatures; +import org.springframework.boot.gradle.run.RunPluginFeatures; /** * Gradle 'Spring Boot' {@link Plugin}. @@ -38,91 +34,18 @@ import org.springframework.boot.gradle.task.RunWithAgent; */ public class SpringBootPlugin implements Plugin { - private static final String REPACKAGE_TASK_NAME = "bootRepackage"; - - private static final String RUN_APP_TASK_NAME = "bootRun"; - @Override public void apply(Project project) { - - project.getConfigurations().create( - SpringBootResolutionStrategy.VERSION_MANAGEMENT_CONFIGURATION); - - applyRepackage(project); - applyRun(project); - project.getPlugins().apply(BasePlugin.class); project.getPlugins().apply(JavaPlugin.class); - project.getExtensions().create("springBoot", SpringBootPluginExtension.class); - - applyResolutionStrategy(project); - - } - - private void applyRepackage(Project project) { - Repackage packageTask = addRepackageTask(project); - ensureTaskRunsOnAssembly(project, packageTask); - // register BootRepackage so that we can use task foo(type: BootRepackage) {} - project.getExtensions().getExtraProperties() - .set("BootRepackage", Repackage.class); - } + project.getPlugins().apply(ApplicationPlugin.class); - private void applyRun(Project project) { - enhanceRunTask(project); - addRunAppTask(project); - if (project.getTasks().withType(JavaExec.class).isEmpty()) { - // Add the ApplicationPlugin so that a JavaExec task is available (run) to - // enhance - project.getPlugins().apply(ApplicationPlugin.class); - } - } - - private void enhanceRunTask(Project project) { - project.getLogger().debug("Enhancing run tasks"); - project.getTasks().whenTaskAdded(new RunWithAgent(project)); - project.getTasks().whenTaskAdded(new ComputeMain(project)); - } - - private void applyResolutionStrategy(final Project project) { - project.getConfigurations().all(new Action() { - - @Override - public void execute(Configuration configuration) { - SpringBootResolutionStrategy.apply(project, configuration); - } - - }); - } - - private Repackage addRepackageTask(Project project) { - Repackage packageTask = project.getTasks().create(REPACKAGE_TASK_NAME, - Repackage.class); - packageTask.setDescription("Repackage existing JAR and WAR " - + "archives so that they can be executed from the command " - + "line using 'java -jar'"); - packageTask.setGroup(BasePlugin.BUILD_GROUP); - packageTask.dependsOn(project.getConfigurations() - .getByName(Dependency.ARCHIVES_CONFIGURATION).getAllArtifacts() - .getBuildDependencies()); - return packageTask; - } + project.getExtensions().create("springBoot", SpringBootPluginExtension.class); - private void addRunAppTask(Project project) { - RunApp runJarTask = project.getTasks().create(RUN_APP_TASK_NAME, RunApp.class); - runJarTask.setDescription("Run the project with support for " - + "auto-detecting main class and reloading static resources"); - runJarTask.setGroup("Execution"); - if (!project.getTasksByName("compileJava", false).isEmpty()) { - if (!project.getTasksByName("compileGroovy", false).isEmpty()) { - runJarTask.dependsOn("compileJava", "compileGroovy"); - } - else { - runJarTask.dependsOn("compileJava"); - } - } + new AgentPluginFeatures().apply(project); + new ResolvePluginFeatures().apply(project); + new RepackagePluginFeatures().apply(project); + new RunPluginFeatures().apply(project); } - private void ensureTaskRunsOnAssembly(Project project, Repackage task) { - project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(task); - } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy index 7636721c99a..ab2436c6d75 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy @@ -19,6 +19,7 @@ package org.springframework.boot.gradle import org.springframework.boot.loader.tools.Layout import org.springframework.boot.loader.tools.Layouts + /** * Gradle DSL Extension for 'Spring Boot'. Most of the time Spring Boot can guess the * settings in this extension, but occasionally you might need to explicitly set one diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentPluginFeatures.java new file mode 100644 index 00000000000..efca5a3ee66 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentPluginFeatures.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2014 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.agent; + +import org.gradle.api.Project; +import org.springframework.boot.gradle.PluginFeatures; + +/** + * {@link PluginFeatures} to add Java Agent support. + * + * @author Phillip Webb + */ +public class AgentPluginFeatures implements PluginFeatures { + + @Override + public void apply(Project project) { + project.afterEvaluate(new AgentTasksEnhancer()); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java new file mode 100644 index 00000000000..b830cd9c64a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2014 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.agent; + +import java.io.File; +import java.security.CodeSource; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.tasks.JavaExec; +import org.springframework.boot.gradle.SpringBootPluginExtension; + +/** + * Add a java agent to the "run" task if configured. You can add an agent in 3 ways (4 if + * you want to use native gradle features as well): + * + *
    + *
  1. Use "-Prun.agent=[path-to-jar]" on the gradle command line
  2. + *
  3. Add an "agent" property (jar file) to the "springBoot" extension in build.gradle
  4. + *
  5. As a special case springloaded is detected as a build script dependency
  6. + *
+ * + * @author Dave Syer + * @author Phillip Webb + */ +public class AgentTasksEnhancer implements Action { + + private static final String SPRING_LOADED_AGENT_CLASSNAME = "org.springsource.loaded.agent.SpringLoadedAgent"; + + private File agent; + + private Boolean noverify; + + @Override + public void execute(Project project) { + setup(project); + if (this.agent != null) { + for (Task task : project.getTasks()) { + addAgent(project, task); + } + } + } + + private void setup(Project project) { + project.getLogger().info("Configuring agent"); + SpringBootPluginExtension extension = project.getExtensions().getByType( + SpringBootPluginExtension.class); + this.noverify = extension.getNoverify(); + this.agent = getAgent(project, extension); + if (this.agent == null) { + this.agent = getSpringLoadedAgent(); + if (this.noverify == null) { + this.noverify = true; + } + } + project.getLogger().debug("Agent: " + this.agent); + } + + private File getAgent(Project project, SpringBootPluginExtension extension) { + if (project.hasProperty("run.agent")) { + return project.file(project.property("run.agent")); + } + return extension.getAgent(); + } + + private File getSpringLoadedAgent() { + try { + Class loaded = Class.forName(SPRING_LOADED_AGENT_CLASSNAME); + if (loaded != null) { + CodeSource source = loaded.getProtectionDomain().getCodeSource(); + if (source != null) { + return new File(source.getLocation().getFile()); + } + } + } + catch (ClassNotFoundException ex) { + // ignore; + } + return null; + } + + private void addAgent(Project project, Task task) { + if (task instanceof JavaExec) { + addAgent(project, (JavaExec) task); + } + } + + private void addAgent(Project project, JavaExec exec) { + project.getLogger().debug("Attaching to: " + exec); + if (this.agent != null) { + project.getLogger().info("Attaching agent: " + this.agent); + exec.jvmArgs("-javaagent:" + this.agent.getAbsolutePath()); + if (this.noverify != null && this.noverify) { + exec.jvmArgs("-noverify"); + } + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/ProjectLibraries.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java similarity index 98% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/ProjectLibraries.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java index e3ebfd1b9af..0f9caf9b65b 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/ProjectLibraries.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.gradle.task; +package org.springframework.boot.gradle.repackage; import java.io.File; import java.io.IOException; 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 new file mode 100644 index 00000000000..4f0e341d10b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2014 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.repackage; + +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.plugins.BasePlugin; +import org.springframework.boot.gradle.PluginFeatures; + +/** + * {@link PluginFeatures} to add repackage support. + * + * @author Phillip Webb + */ +public class RepackagePluginFeatures implements PluginFeatures { + + private static final String REPACKAGE_TASK_NAME = "bootRepackage"; + + @Override + public void apply(Project project) { + addRepackageTask(project); + registerRepackageTaskProperty(project); + } + + private void addRepackageTask(Project project) { + RepackageTask task = project.getTasks().create(REPACKAGE_TASK_NAME, + RepackageTask.class); + task.setDescription("Repackage existing JAR and WAR " + + "archives so that they can be executed from the command " + + "line using 'java -jar'"); + task.setGroup(BasePlugin.BUILD_GROUP); + task.dependsOn(project.getConfigurations() + .getByName(Dependency.ARCHIVES_CONFIGURATION).getAllArtifacts() + .getBuildDependencies()); + ensureTaskRunsOnAssembly(project, task); + } + + private void ensureTaskRunsOnAssembly(Project project, Task task) { + project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(task); + } + + /** + * Register BootRepackage so that we can use task {@code foo(type: BootRepackage)}. + */ + private void registerRepackageTaskProperty(Project project) { + project.getExtensions().getExtraProperties() + .set("BootRepackage", RepackageTask.class); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/Repackage.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java similarity index 86% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/Repackage.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java index 4209a39e01e..fe5b047c6ba 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/Repackage.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.gradle.task; +package org.springframework.boot.gradle.repackage; import java.io.File; import java.io.IOException; @@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit; import org.gradle.api.Action; import org.gradle.api.DefaultTask; import org.gradle.api.Project; -import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.bundling.Jar; import org.springframework.boot.gradle.SpringBootPluginExtension; @@ -31,11 +30,11 @@ import org.springframework.boot.loader.tools.Repackager; /** * Repackage task. - * + * * @author Phillip Webb * @author Janne Valkealahti */ -public class Repackage extends DefaultTask { +public class RepackageTask extends DefaultTask { private static final long FIND_WARNING_TIMEOUT = TimeUnit.SECONDS.toMillis(10); @@ -72,11 +71,6 @@ public class Repackage extends DefaultTask { else if (extension.getCustomConfiguration() != null) { libraries.setCustomConfigurationName(extension.getCustomConfiguration()); } - JavaExec runner = (JavaExec) project.getTasks().findByName("run"); - if (runner != null && this.mainClass == null) { - getLogger().info("Found main in run task: " + runner.getMain()); - setMainClass(runner.getMain()); - } project.getTasks().withType(Jar.class, new RepackageAction(extension, libraries)); } @@ -95,8 +89,8 @@ public class Repackage extends DefaultTask { @Override public void execute(Jar archive) { // if withJarTask is set, compare tasks and bail out if we didn't match - if (Repackage.this.withJarTask != null - && !archive.equals(Repackage.this.withJarTask)) { + if (RepackageTask.this.withJarTask != null + && !archive.equals(RepackageTask.this.withJarTask)) { return; } @@ -104,10 +98,7 @@ public class Repackage extends DefaultTask { File file = archive.getArchivePath(); if (file.exists()) { Repackager repackager = new LoggingRepackager(file); - repackager.setMainClass(this.extension.getMainClass()); - if (Repackage.this.mainClass != null) { - repackager.setMainClass(Repackage.this.mainClass); - } + setMainClass(repackager); if (this.extension.convertLayout() != null) { repackager.setLayout(this.extension.convertLayout()); } @@ -121,6 +112,16 @@ public class Repackage extends DefaultTask { } } } + + private void setMainClass(Repackager repackager) { + repackager.setMainClass((String) getProject().property("mainClassName")); + if (this.extension.getMainClass() != null) { + repackager.setMainClass(this.extension.getMainClass()); + } + if (RepackageTask.this.mainClass != null) { + repackager.setMainClass(RepackageTask.this.mainClass); + } + } } private class LoggingRepackager extends Repackager { diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/ResolvePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/ResolvePluginFeatures.java new file mode 100644 index 00000000000..99888131036 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/ResolvePluginFeatures.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2014 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.resolve; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.springframework.boot.gradle.PluginFeatures; + +/** + * {@link PluginFeatures} to add version resolution support. + * + * @author Phillip Webb + */ +public class ResolvePluginFeatures implements PluginFeatures { + + @Override + public void apply(final Project project) { + project.getConfigurations().create( + SpringBootResolutionStrategy.VERSION_MANAGEMENT_CONFIGURATION); + project.getConfigurations().all(new Action() { + @Override + public void execute(Configuration configuration) { + SpringBootResolutionStrategy.applyToConfiguration(project, configuration); + } + }); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java similarity index 81% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java index ce6753185e8..474209f2ffb 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java @@ -1,5 +1,20 @@ +/* + * Copyright 2012-2014 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; +package org.springframework.boot.gradle.resolve; import java.io.File; import java.io.FileInputStream; @@ -31,7 +46,7 @@ public class SpringBootResolutionStrategy { private static final String SPRING_BOOT_GROUP = "org.springframework.boot"; - public static void apply(final Project project, Configuration configuration) { + public static void applyToConfiguration(final Project project, Configuration configuration) { if (VERSION_MANAGEMENT_CONFIGURATION.equals(configuration.getName())) { return; } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/BootRunTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/BootRunTask.java new file mode 100644 index 00000000000..104a2aacf1b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/BootRunTask.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2014 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 + */ +public class BootRunTask extends JavaExec { + + @Override + public void exec() { + 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); + } + } + super.exec(); + } + +} 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 new file mode 100644 index 00000000000..674cb359642 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/FindMainClassTask.java @@ -0,0 +1,56 @@ +package org.springframework.boot.gradle.run; + +import java.io.IOException; + +import org.gradle.api.DefaultTask; +import org.gradle.api.Project; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.TaskAction; +import org.springframework.boot.gradle.SpringBootPluginExtension; +import org.springframework.boot.loader.tools.MainClassFinder; + +/** + * Task to find and set the 'mainClassName' convention when it's missing by searching the + * main source code. + * + * @author Dave Syer + * @author Phillip Webb + */ +public class FindMainClassTask extends DefaultTask { + + @TaskAction + public void setMainClassNameProperty() { + Project project = getProject(); + if (project.property("mainClassName") == null) { + project.setProperty("mainClassName", findMainClass()); + } + } + + private String findMainClass() { + Project project = getProject(); + + // Try the SpringBoot extension setting + SpringBootPluginExtension bootExtension = project.getExtensions().getByType( + SpringBootPluginExtension.class); + if(bootExtension.getMainClass() != null) { + return bootExtension.getMainClass(); + } + + // Search + SourceSet mainSourceSet = SourceSets.findMainSourceSet(project); + if (mainSourceSet == null) { + return null; + } + project.getLogger().debug( + "Looking for main in: " + mainSourceSet.getOutput().getClassesDir()); + try { + String mainClass = MainClassFinder.findSingleMainClass(mainSourceSet + .getOutput().getClassesDir()); + project.getLogger().info("Computed main class: " + mainClass); + return mainClass; + } + catch (IOException ex) { + throw new IllegalStateException("Cannot find main class", 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 new file mode 100644 index 00000000000..e9b0f87ab56 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/RunPluginFeatures.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2014 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.util.concurrent.Callable; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.JavaExec; +import org.springframework.boot.gradle.PluginFeatures; + +/** + * {@link PluginFeatures} to add run support. + * + * @author Phillip Webb + */ +public class RunPluginFeatures implements PluginFeatures { + + private static final String FIND_MAIN_CLASS_TASK_NAME = "findMainClass"; + + private static final String RUN_APP_TASK_NAME = "bootRun"; + + @Override + public void apply(Project project) { + mainClassNameFinder(project); + addBootRunTask(project); + } + + private void mainClassNameFinder(Project project) { + project.getTasks().create(FIND_MAIN_CLASS_TASK_NAME, FindMainClassTask.class); + project.getTasks().all(new Action() { + @Override + public void execute(Task task) { + if(task instanceof JavaExec) { + task.dependsOn(FIND_MAIN_CLASS_TASK_NAME); + } + } + }); + } + + private void addBootRunTask(final Project project) { + final JavaPluginConvention javaConvention = project.getConvention().getPlugin( + JavaPluginConvention.class); + + BootRunTask run = project.getTasks().create(RUN_APP_TASK_NAME, BootRunTask.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.getConventionMapping().map("main", new Callable() { + @Override + public Object call() throws Exception { + return project.property("mainClassName"); + } + }); + run.getConventionMapping().map("jvmArgs", new Callable() { + @Override + public Object call() throws Exception { + return project.property("applicationDefaultJvmArgs"); + } + }); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/SourceSets.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/SourceSets.java new file mode 100644 index 00000000000..b648a728bb8 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/run/SourceSets.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2014 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.util.Collections; + +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.SourceSet; + +/** + * Utilities for working with {@link SourceSet}s. + * + * @author Dave Syer + * @author Phillip Webb + */ +class SourceSets { + + public static SourceSet findMainSourceSet(Project project) { + for (SourceSet sourceSet : getJavaSourceSets(project)) { + if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) { + return sourceSet; + } + } + return null; + } + + private static Iterable getJavaSourceSets(Project project) { + JavaPluginConvention plugin = project.getConvention().getPlugin( + JavaPluginConvention.class); + if(plugin == null) { + return Collections.emptyList(); + } + return plugin.getSourceSets(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/ComputeMain.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/ComputeMain.java deleted file mode 100644 index 653c76edb7f..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/ComputeMain.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2012-2014 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.task; - -import java.io.IOException; -import java.util.concurrent.atomic.AtomicReference; - -import org.gradle.api.Action; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSet; -import org.springframework.boot.loader.tools.MainClassFinder; - -/** - * Add a main class if one is missing from the build - * - * @author Dave Syer - */ -public class ComputeMain implements Action { - - private Project project; - - public ComputeMain(Project project) { - this.project = project; - } - - @Override - public void execute(Task task) { - if (task instanceof JavaExec) { - final JavaExec exec = (JavaExec) task; - this.project.afterEvaluate(new Action() { - @Override - public void execute(Project project) { - addMain(exec); - } - }); - } - } - - private void addMain(JavaExec exec) { - if (exec.getMain() == null) { - this.project.getLogger().debug("Computing main for: " + exec); - this.project.setProperty("mainClassName", findMainClass(this.project)); - } - } - - private String findMainClass(Project project) { - SourceSet main = findMainSourceSet(project); - if (main == null) { - return null; - } - project.getLogger().debug( - "Looking for main in: " + main.getOutput().getClassesDir()); - try { - String mainClass = MainClassFinder.findSingleMainClass(main.getOutput() - .getClassesDir()); - project.getLogger().info("Computed main class: " + mainClass); - return mainClass; - } - catch (IOException ex) { - throw new IllegalStateException("Cannot find main class", ex); - } - } - - public static SourceSet findMainSourceSet(Project project) { - final AtomicReference main = new AtomicReference(); - JavaPluginConvention javaConvention = project.getConvention().getPlugin( - JavaPluginConvention.class); - javaConvention.getSourceSets().all(new Action() { - - @Override - public void execute(SourceSet set) { - if (SourceSet.MAIN_SOURCE_SET_NAME.equals(set.getName())) { - main.set(set); - } - }; - - }); - return main.get(); - } -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/RunApp.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/RunApp.java deleted file mode 100644 index 748704c0a69..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/RunApp.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2014 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.task; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.Callable; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.internal.file.collections.SimpleFileCollection; -import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.TaskAction; -import org.springframework.boot.loader.tools.FileUtils; -import org.springframework.boot.loader.tools.MainClassFinder; - -/** - * Run the project from Gradle. - * - * @author Dave Syer - */ -public class RunApp extends DefaultTask { - - @TaskAction - public void runApp() { - - final Project project = getProject(); - final SourceSet main = ComputeMain.findMainSourceSet(project); - final File outputDir = (main == null ? null : main.getOutput().getResourcesDir()); - final Set allResources = new LinkedHashSet(); - if (main != null) { - allResources.addAll(main.getResources().getSrcDirs()); - } - - project.getTasks().withType(JavaExec.class, new Action() { - - @Override - public void execute(JavaExec exec) { - ArrayList files = new ArrayList(exec.getClasspath() - .getFiles()); - files.addAll(0, allResources); - getLogger().info("Adding classpath: " + allResources); - exec.setClasspath(new SimpleFileCollection(files)); - if (exec.getMain() == null) { - final String mainClass = findMainClass(main); - exec.setMain(mainClass); - exec.getConventionMapping().map("main", new Callable() { - - @Override - public String call() throws Exception { - return mainClass; - } - - }); - getLogger().info("Found main: " + mainClass); - } - if (outputDir != null) { - for (File directory : allResources) { - FileUtils.removeDuplicatesFromOutputDirectory(outputDir, directory); - } - } - exec.exec(); - } - - }); - - } - - private String findMainClass(SourceSet main) { - if (main == null) { - return null; - } - getLogger().info("Looking for main in: " + main.getOutput().getClassesDir()); - try { - return MainClassFinder.findSingleMainClass(main.getOutput().getClassesDir()); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot find main class", ex); - } - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/RunWithAgent.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/RunWithAgent.java deleted file mode 100644 index 195f6a25817..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/task/RunWithAgent.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2012-2014 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.task; - -import java.io.File; -import java.security.CodeSource; - -import org.gradle.api.Action; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.tasks.JavaExec; -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.loader.tools.AgentAttacher; -import org.springframework.core.task.TaskRejectedException; - -/** - * Add a java agent to the "run" task if configured. You can add an agent in 3 ways (4 if - * you want to use native gradle features as well): - * - *
    - *
  1. Use "-Prun.agent=[path-to-jar]" on the gradle command line
  2. - *
  3. Add an "agent" property (jar file) to the "springBoot" extension in build.gradle
  4. - *
  5. As a special case springloaded is detected as a build script dependency
  6. - *
- * - * @author Dave Syer - */ -public class RunWithAgent implements Action { - - private static final String SPRING_LOADED_AGENT_CLASSNAME = "org.springsource.loaded.agent.SpringLoadedAgent"; - - private File agent; - - private Project project; - - private Boolean noverify; - - public RunWithAgent(Project project) { - this.project = project; - } - - @Override - public void execute(final Task task) { - if (task instanceof JavaExec) { - this.project.afterEvaluate(new Action() { - @Override - public void execute(Project project) { - addAgent((JavaExec) task); - } - }); - } - if (task instanceof RunApp) { - this.project.beforeEvaluate(new Action() { - @Override - public void execute(Project project) { - addAgent((RunApp) task); - } - }); - } - } - - private void addAgent(RunApp exec) { - this.project.getLogger().debug("Attaching to: " + exec); - findAgent(this.project.getExtensions().getByType(SpringBootPluginExtension.class)); - if (this.agent != null) { - exec.doFirst(new Action() { - @Override - public void execute(Task task) { - RunWithAgent.this.project.getLogger().info( - "Attaching agent: " + RunWithAgent.this.agent); - if (RunWithAgent.this.noverify != null && RunWithAgent.this.noverify - && !AgentAttacher.hasNoVerify()) { - throw new TaskRejectedException( - "The JVM must be started with -noverify for this " - + "agent to work. You can use JAVA_OPTS " - + "to add that flag."); - } - AgentAttacher.attach(RunWithAgent.this.agent); - } - }); - } - } - - private void addAgent(JavaExec exec) { - this.project.getLogger().debug("Attaching to: " + exec); - findAgent(this.project.getExtensions().getByType(SpringBootPluginExtension.class)); - if (this.agent != null) { - this.project.getLogger().info("Attaching agent: " + this.agent); - exec.jvmArgs("-javaagent:" + this.agent.getAbsolutePath()); - if (this.noverify != null && this.noverify) { - exec.jvmArgs("-noverify"); - } - } - } - - private void findAgent(SpringBootPluginExtension extension) { - if (this.agent != null) { - return; - } - this.noverify = this.project.getExtensions() - .getByType(SpringBootPluginExtension.class).getNoverify(); - this.project.getLogger().info("Finding agent"); - if (this.project.hasProperty("run.agent")) { - this.agent = this.project.file(this.project.property("run.agent")); - } - else if (extension.getAgent() != null) { - this.agent = extension.getAgent(); - } - if (this.agent == null) { - try { - Class loaded = Class.forName(SPRING_LOADED_AGENT_CLASSNAME); - if (this.agent == null && loaded != null) { - if (this.noverify == null) { - this.noverify = true; - } - CodeSource source = loaded.getProtectionDomain().getCodeSource(); - if (source != null) { - this.agent = new File(source.getLocation().getFile()); - } - } - } - catch (ClassNotFoundException ex) { - // ignore; - } - } - this.project.getLogger().debug("Agent: " + this.agent); - } - -}