From cb6e30c8f5b8873db24927e53b46abefbe11d19e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 7 Oct 2015 13:52:22 -0700 Subject: [PATCH 1/3] Ignore helpmojo from Eclipse m2e config Ignore the `helpmojo` goal to save needing an additional Eclipse plugin. --- spring-boot-parent/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-parent/pom.xml b/spring-boot-parent/pom.xml index 15a7304b67f..78f2f740d87 100644 --- a/spring-boot-parent/pom.xml +++ b/spring-boot-parent/pom.xml @@ -347,6 +347,7 @@ descriptor + helpmojo From 09395f956ad223e7c0d32a8c08f670bcb5e90209 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 7 Oct 2015 09:54:44 -0700 Subject: [PATCH 2/3] Compile samples and integration tests with Java 8 Update the samples and integration tests to use Java 8. There's no specific reason to keep them on Java 6 and it helps keep Eclipse happy if we upgrade. --- spring-boot-integration-tests/pom.xml | 1 + spring-boot-samples/pom.xml | 4 +++- spring-boot-samples/spring-boot-sample-jersey/pom.xml | 1 - spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml | 1 - spring-boot-samples/spring-boot-sample-servlet/pom.xml | 1 - spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml | 1 - spring-boot-samples/spring-boot-sample-tomcat7-jsp/pom.xml | 1 - spring-boot-samples/spring-boot-sample-web-jsp/pom.xml | 1 - spring-boot-samples/spring-boot-sample-web-static/pom.xml | 1 - .../spring-boot-sample-websocket-jetty/pom.xml | 1 - .../spring-boot-sample-websocket-tomcat/pom.xml | 1 - .../spring-boot-sample-websocket-undertow/pom.xml | 1 - 12 files changed, 4 insertions(+), 11 deletions(-) diff --git a/spring-boot-integration-tests/pom.xml b/spring-boot-integration-tests/pom.xml index 8e50df99383..9c61788a593 100644 --- a/spring-boot-integration-tests/pom.xml +++ b/spring-boot-integration-tests/pom.xml @@ -18,6 +18,7 @@ ${basedir}/.. + 1.8 spring-boot-gradle-tests diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 2a56ffc3870..d77c6f55b9b 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.springframework.boot @@ -18,6 +19,7 @@ ${basedir}/.. + 1.8 spring-boot-sample-actuator diff --git a/spring-boot-samples/spring-boot-sample-jersey/pom.xml b/spring-boot-samples/spring-boot-sample-jersey/pom.xml index e219f6ebf08..320b94f9cce 100644 --- a/spring-boot-samples/spring-boot-sample-jersey/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jersey/pom.xml @@ -18,7 +18,6 @@ ${basedir}/../.. - 1.7 diff --git a/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml b/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml index 4aba3c8b5e4..e4edda40014 100644 --- a/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jta-jndi/pom.xml @@ -17,7 +17,6 @@ http://www.spring.io - 1.7 ${basedir}/../.. diff --git a/spring-boot-samples/spring-boot-sample-servlet/pom.xml b/spring-boot-samples/spring-boot-sample-servlet/pom.xml index e96dc1f047f..1d92d532d28 100644 --- a/spring-boot-samples/spring-boot-sample-servlet/pom.xml +++ b/spring-boot-samples/spring-boot-sample-servlet/pom.xml @@ -18,7 +18,6 @@ ${basedir}/../.. - 1.7 / diff --git a/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml index 655be0ae5a4..849629fbb8a 100644 --- a/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml +++ b/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml @@ -19,7 +19,6 @@ ${basedir}/../.. / - 1.7 diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat7-jsp/pom.xml index b3a608326b8..c394d83dc16 100644 --- a/spring-boot-samples/spring-boot-sample-tomcat7-jsp/pom.xml +++ b/spring-boot-samples/spring-boot-sample-tomcat7-jsp/pom.xml @@ -20,7 +20,6 @@ ${basedir}/../.. / 7.0.59 - 1.7 diff --git a/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml index 6ff960f4307..a6dc9b3c72f 100644 --- a/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml +++ b/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml @@ -18,7 +18,6 @@ ${basedir}/../.. - 1.7 / diff --git a/spring-boot-samples/spring-boot-sample-web-static/pom.xml b/spring-boot-samples/spring-boot-sample-web-static/pom.xml index 47d8d140230..3dade1d797d 100644 --- a/spring-boot-samples/spring-boot-sample-web-static/pom.xml +++ b/spring-boot-samples/spring-boot-sample-web-static/pom.xml @@ -17,7 +17,6 @@ http://www.spring.io - 1.7 ${basedir}/../.. diff --git a/spring-boot-samples/spring-boot-sample-websocket-jetty/pom.xml b/spring-boot-samples/spring-boot-sample-websocket-jetty/pom.xml index 17ff9a49637..53d5285f966 100755 --- a/spring-boot-samples/spring-boot-sample-websocket-jetty/pom.xml +++ b/spring-boot-samples/spring-boot-sample-websocket-jetty/pom.xml @@ -17,7 +17,6 @@ ${basedir}/../.. - 1.7 diff --git a/spring-boot-samples/spring-boot-sample-websocket-tomcat/pom.xml b/spring-boot-samples/spring-boot-sample-websocket-tomcat/pom.xml index 01a47ca2ee7..fa69d90100a 100755 --- a/spring-boot-samples/spring-boot-sample-websocket-tomcat/pom.xml +++ b/spring-boot-samples/spring-boot-sample-websocket-tomcat/pom.xml @@ -17,7 +17,6 @@ ${basedir}/../.. - 1.7 diff --git a/spring-boot-samples/spring-boot-sample-websocket-undertow/pom.xml b/spring-boot-samples/spring-boot-sample-websocket-undertow/pom.xml index 85c8cf8f143..bbdacfa25ab 100755 --- a/spring-boot-samples/spring-boot-sample-websocket-undertow/pom.xml +++ b/spring-boot-samples/spring-boot-sample-websocket-undertow/pom.xml @@ -17,7 +17,6 @@ ${basedir}/../.. - 1.7 From ba7c1fda72f0297027a4668005e21e88da138444 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 7 Oct 2015 20:49:47 -0700 Subject: [PATCH 3/3] Convert Gradle plugin from Groovy to Java Replace existing Groovy code with Java since the Groovy Eclipse tooling currently forces the use of an old jdt plugin which has formatter bugs. Fixes gh-4113 --- .../spring-boot-gradle-plugin/pom.xml | 24 -- .../boot/gradle/SpringBootPlugin.groovy | 66 ----- .../gradle/SpringBootPluginExtension.groovy | 133 ---------- .../boot/gradle/PluginFeatures.java | 0 .../boot/gradle/SpringBootPlugin.java | 75 ++++++ .../gradle/SpringBootPluginExtension.java | 220 ++++++++++++++++ .../gradle/VersionManagedDependencies.java | 12 +- .../gradle/agent/AgentPluginFeatures.java | 0 .../boot/gradle/agent/AgentTasksEnhancer.java | 126 +++++++++ .../gradle/exclude/ApplyExcludeRules.java | 117 +++++++++ .../gradle/exclude/ExcludePluginFeatures.java | 39 +++ .../gradle/repackage/ProjectLibraries.java | 243 ++++++++++++++++++ .../repackage/RepackagePluginFeatures.java | 161 ++++++++++++ .../boot/gradle/repackage/RepackageTask.java | 236 +++++++++++++++++ .../gradle/resolve/ResolvePluginFeatures.java | 43 ++++ .../resolve/SpringBootResolutionStrategy.java | 79 ++++++ .../boot/gradle/run/BootRunTask.java | 82 ++++++ .../boot/gradle/run/FindMainClassTask.java | 102 ++++++++ .../boot/gradle/run/RunPluginFeatures.java | 85 ++++++ .../boot/gradle/run/SourceSets.java | 51 ++++ 20 files changed, 1665 insertions(+), 229 deletions(-) delete mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.groovy delete mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy rename spring-boot-tools/spring-boot-gradle-plugin/src/main/{groovy => java}/org/springframework/boot/gradle/PluginFeatures.java (100%) create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPlugin.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java rename spring-boot-tools/spring-boot-gradle-plugin/src/main/{groovy => java}/org/springframework/boot/gradle/VersionManagedDependencies.java (91%) rename spring-boot-tools/spring-boot-gradle-plugin/src/main/{groovy => java}/org/springframework/boot/gradle/agent/AgentPluginFeatures.java (100%) create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ApplyExcludeRules.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ExcludePluginFeatures.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/resolve/ResolvePluginFeatures.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java create mode 100644 spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/SourceSets.java diff --git a/spring-boot-tools/spring-boot-gradle-plugin/pom.xml b/spring-boot-tools/spring-boot-gradle-plugin/pom.xml index 29f58c0ec3b..6fbd3f3b042 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/pom.xml +++ b/spring-boot-tools/spring-boot-gradle-plugin/pom.xml @@ -54,30 +54,6 @@ provided - - src/main/groovy - - - org.apache.maven.plugins - maven-compiler-plugin - - groovy-eclipse-compiler - - - - org.codehaus.groovy - groovy-eclipse-compiler - 2.8.0-01 - - - org.codehaus.groovy - groovy-eclipse-batch - 2.1.8-01 - - - - - gradle diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.groovy b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.groovy deleted file mode 100644 index 8c95630de66..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.groovy +++ /dev/null @@ -1,66 +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 - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.plugins.ApplicationPlugin -import org.gradle.api.plugins.BasePlugin -import org.gradle.api.plugins.JavaPlugin -import org.springframework.boot.gradle.agent.AgentPluginFeatures -import org.springframework.boot.gradle.exclude.ExcludePluginFeatures -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}. - * - * @author Phillip Webb - * @author Dave Syer - */ -class SpringBootPlugin implements Plugin { - - @Override - void apply(Project project) { - project.getPlugins().apply(BasePlugin) - - project.getExtensions().create("springBoot", SpringBootPluginExtension) - project.getConfigurations().create(VersionManagedDependencies.CONFIGURATION); - - project.getPlugins().apply(JavaPlugin) - project.getPlugins().apply(ApplicationPlugin) - new AgentPluginFeatures().apply(project) - new RepackagePluginFeatures().apply(project) - new RunPluginFeatures().apply(project) - new ResolvePluginFeatures().apply(project) - new ExcludePluginFeatures().apply(project) - - useUtf8Encoding(project) - } - - private useUtf8Encoding(Project project) { - project.tasks.withType(org.gradle.api.tasks.compile.JavaCompile).all { - it.doFirst { - if(!it.options.encoding) { - it.options.encoding = 'UTF-8' - } - } - } - } -} 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 deleted file mode 100644 index 86abbc3a745..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy +++ /dev/null @@ -1,133 +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 - -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 - * or two of them. E.g. - * - *
- *     apply plugin: "spring-boot"
- *     springBoot {
- *         mainClass = 'org.demo.Application'
- *         layout = 'ZIP'
- *     }
- * 
- * - * @author Phillip Webb - * @author Dave Syer - */ -public class SpringBootPluginExtension { - - static enum LayoutType { - - JAR(new Layouts.Jar()), - - WAR(new Layouts.War()), - - ZIP(new Layouts.Expanded()), - - DIR(new Layouts.Expanded()), - - MODULE(new Layouts.Module()), - - NONE(new Layouts.None()); - - Layout layout; - - private LayoutType(Layout layout) { - this.layout = layout; - } - } - - /** - * The main class that should be run. Instead of setting this explicitly you can use the - * 'mainClassName' of the project or the 'main' of the 'run' task. 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. - */ - String mainClass - - /** - * The classifier (file name part before the extension). Instead of setting this explicitly - * you can use the 'classifier' property of the 'bootRepackage' task. If not specified the archive - * will be replaced instead of renamed. - */ - String classifier - - /** - * The name of the ivy configuration name to treat as 'provided' (when packaging - * those dependencies in a separate path). If not specified 'providedRuntime' will - * be used. - */ - String providedConfiguration - - /** - * The name of the custom configuration to use. - */ - String customConfiguration - - /** - * If the original source archive should be backed-up before being repackaged. - */ - boolean backupSource = true; - - /** - * The layout of the archive if it can't be derived from the file extension. - * Valid values are JAR, WAR, ZIP, DIR (for exploded zip file). ZIP and DIR - * are actually synonymous, and should be used if there is no MANIFEST.MF - * available, or if you want the MANIFEST.MF 'Main-Class' to be - * PropertiesLauncher. Gradle will coerce literal String values to the - * correct type. - */ - LayoutType layout; - - /** - * Convenience method for use in a custom task. - * @return the Layout to use or null if not explicitly set - */ - Layout convertLayout() { - (layout == null ? null : layout.layout) - } - - /** - * Libraries that must be unpacked from fat jars in order to run. Use Strings in the - * form {@literal groupId:artifactId}. - */ - Set requiresUnpack; - - /** - * Location of an agent jar to attach to the VM when running the application with runJar task. - */ - File agent; - - /** - * Flag to indicate that the agent requires -noverify (and the plugin will refuse to start if it is not set) - */ - Boolean noverify; - - /** - * If exclude rules should be applied to dependencies based on the spring-dependencies-bom - */ - boolean applyExcludeRules = true; - -} 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/java/org/springframework/boot/gradle/PluginFeatures.java similarity index 100% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/PluginFeatures.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/PluginFeatures.java diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPlugin.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPlugin.java new file mode 100644 index 00000000000..2064b438222 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPlugin.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2015 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.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.ApplicationPlugin; +import org.gradle.api.plugins.BasePlugin; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.tasks.compile.JavaCompile; +import org.springframework.boot.gradle.agent.AgentPluginFeatures; +import org.springframework.boot.gradle.exclude.ExcludePluginFeatures; +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}. + * + * @author Phillip Webb + * @author Dave Syer + */ +class SpringBootPlugin implements Plugin { + + @Override + public void apply(Project project) { + project.getPlugins().apply(BasePlugin.class); + project.getExtensions().create("springBoot", SpringBootPluginExtension.class); + project.getConfigurations().create(VersionManagedDependencies.CONFIGURATION); + project.getPlugins().apply(JavaPlugin.class); + project.getPlugins().apply(ApplicationPlugin.class); + new AgentPluginFeatures().apply(project); + new RepackagePluginFeatures().apply(project); + new RunPluginFeatures().apply(project); + new ResolvePluginFeatures().apply(project); + new ExcludePluginFeatures().apply(project); + project.getTasks().withType(JavaCompile.class).all(new SetUtf8EncodingAction()); + } + + private static class SetUtf8EncodingAction implements Action { + + @Override + public void execute(final JavaCompile compile) { + compile.doFirst(new Action() { + + @Override + @SuppressWarnings("deprecation") + public void execute(Task t) { + if (compile.getOptions().getEncoding() == null) { + compile.getOptions().setEncoding("UTF-8"); + } + } + + }); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java new file mode 100644 index 00000000000..ec80ec4a4db --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java @@ -0,0 +1,220 @@ +/* + * Copyright 2012-2015 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 java.io.File; +import java.util.Set; + +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 or + * two of them. E.g. + * + *
+ *     apply plugin: "spring-boot"
+ *     springBoot {
+ *         mainClass = 'org.demo.Application'
+ *         layout = 'ZIP'
+ *     }
+ * 
+ * + * @author Phillip Webb + * @author Dave Syer + */ +public class SpringBootPluginExtension { + + /** + * The main class that should be run. Instead of setting this explicitly you can use + * the 'mainClassName' of the project or the 'main' of the 'run' task. 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. + */ + private String mainClass; + + /** + * The classifier (file name part before the extension). Instead of setting this + * explicitly you can use the 'classifier' property of the 'bootRepackage' task. If + * not specified the archive will be replaced instead of renamed. + */ + private String classifier; + + /** + * The name of the ivy configuration name to treat as 'provided' (when packaging those + * dependencies in a separate path). If not specified 'providedRuntime' will be used. + */ + private String providedConfiguration; + + /** + * The name of the custom configuration to use. + */ + private String customConfiguration; + + /** + * If the original source archive should be backed-up before being repackaged. + */ + private boolean backupSource = true; + + /** + * The layout of the archive if it can't be derived from the file extension. Valid + * values are JAR, WAR, ZIP, DIR (for exploded zip file). ZIP and DIR are actually + * synonymous, and should be used if there is no MANIFEST.MF available, or if you want + * the MANIFEST.MF 'Main-Class' to be PropertiesLauncher. Gradle will coerce literal + * String values to the correct type. + */ + private LayoutType layout; + + /** + * Libraries that must be unpacked from fat jars in order to run. Use Strings in the + * form {@literal groupId:artifactId}. + */ + private Set requiresUnpack; + + /** + * Location of an agent jar to attach to the VM when running the application with + * runJar task. + */ + private File agent; + + /** + * Flag to indicate that the agent requires -noverify (and the plugin will refuse to + * start if it is not set) + */ + private Boolean noverify; + + /** + * If exclude rules should be applied to dependencies based on the + * spring-dependencies-bom + */ + private boolean applyExcludeRules = true; + + /** + * Convenience method for use in a custom task. + * @return the Layout to use or null if not explicitly set + */ + public Layout convertLayout() { + return (this.layout == null ? null : this.layout.layout); + } + + public String getMainClass() { + return this.mainClass; + } + + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + public String getClassifier() { + return this.classifier; + } + + public void setClassifier(String classifier) { + this.classifier = classifier; + } + + public String getProvidedConfiguration() { + return this.providedConfiguration; + } + + public void setProvidedConfiguration(String providedConfiguration) { + this.providedConfiguration = providedConfiguration; + } + + public String getCustomConfiguration() { + return this.customConfiguration; + } + + public void setCustomConfiguration(String customConfiguration) { + this.customConfiguration = customConfiguration; + } + + public boolean isBackupSource() { + return this.backupSource; + } + + public void setBackupSource(boolean backupSource) { + this.backupSource = backupSource; + } + + public LayoutType getLayout() { + return this.layout; + } + + public void setLayout(LayoutType layout) { + this.layout = layout; + } + + public Set getRequiresUnpack() { + return this.requiresUnpack; + } + + public void setRequiresUnpack(Set requiresUnpack) { + this.requiresUnpack = requiresUnpack; + } + + public File getAgent() { + return this.agent; + } + + public void setAgent(File agent) { + this.agent = agent; + } + + public Boolean getNoverify() { + return this.noverify; + } + + public void setNoverify(Boolean noverify) { + this.noverify = noverify; + } + + public boolean isApplyExcludeRules() { + return this.applyExcludeRules; + } + + public void setApplyExcludeRules(boolean applyExcludeRules) { + this.applyExcludeRules = applyExcludeRules; + } + + /** + * Layout types. + */ + static enum LayoutType { + + JAR(new Layouts.Jar()), + + WAR(new Layouts.War()), + + ZIP(new Layouts.Expanded()), + + DIR(new Layouts.Expanded()), + + MODULE(new Layouts.Module()), + + NONE(new Layouts.None()); + + Layout layout; + + LayoutType(Layout layout) { + this.layout = layout; + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/VersionManagedDependencies.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/VersionManagedDependencies.java similarity index 91% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/VersionManagedDependencies.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/VersionManagedDependencies.java index 51dd654cc70..b42eada7207 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/VersionManagedDependencies.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/VersionManagedDependencies.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -47,8 +47,8 @@ public class VersionManagedDependencies { private ManagedDependencies managedDependencies; public VersionManagedDependencies(Project project) { - this.versionManagementConfiguration = project.getConfigurations().getByName( - CONFIGURATION); + this.versionManagementConfiguration = project.getConfigurations() + .getByName(CONFIGURATION); } public ManagedDependencies getManagedDependencies() { @@ -60,15 +60,15 @@ public class VersionManagedDependencies { } private Collection getVersionManagedDependencies() { - if (versionManagedDependencies == null) { - Set files = versionManagementConfiguration.resolve(); + if (this.versionManagedDependencies == null) { + Set files = this.versionManagementConfiguration.resolve(); List dependencies = new ArrayList(files.size()); for (File file : files) { dependencies.add(getPropertiesFileManagedDependencies(file)); } this.versionManagedDependencies = dependencies; } - return versionManagedDependencies; + return this.versionManagedDependencies; } private Dependencies getPropertiesFileManagedDependencies(File file) { 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/java/org/springframework/boot/gradle/agent/AgentPluginFeatures.java similarity index 100% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/agent/AgentPluginFeatures.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentPluginFeatures.java diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java new file mode 100644 index 00000000000..1ca136ac105 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java @@ -0,0 +1,126 @@ +/* + * 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.net.URISyntaxException; +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) { + try { + return new File(source.getLocation().toURI()); + } + catch (URISyntaxException ex) { + return new File(source.getLocation().getPath()); + } + } + } + } + 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"); + } + Iterable defaultJvmArgs = exec.getConventionMapping() + .getConventionValue(null, "jvmArgs", false); + if (defaultJvmArgs != null) { + exec.jvmArgs(defaultJvmArgs); + } + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ApplyExcludeRules.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ApplyExcludeRules.java new file mode 100644 index 00000000000..f5bd0d1d8ce --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ApplyExcludeRules.java @@ -0,0 +1,117 @@ +/* + * 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.exclude; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ModuleDependency; +import org.gradle.api.artifacts.ResolvableDependencies; +import org.gradle.api.internal.artifacts.DefaultExcludeRule; +import org.gradle.api.logging.Logger; +import org.springframework.boot.dependency.tools.Dependency.Exclusion; +import org.springframework.boot.dependency.tools.ManagedDependencies; +import org.springframework.boot.gradle.VersionManagedDependencies; + +/** + * {@link Action} to apply exclude rules. + * + * @author Phillip Webb + */ +public class ApplyExcludeRules implements Action { + + private final Logger logger; + + private final VersionManagedDependencies versionManagedDependencies; + + public ApplyExcludeRules(Project project) { + this.logger = project.getLogger(); + this.versionManagedDependencies = new VersionManagedDependencies(project); + } + + @Override + public void execute(Configuration configuration) { + if (!VersionManagedDependencies.CONFIGURATION.equals(configuration.getName())) { + configuration.getIncoming() + .beforeResolve(new Action() { + @Override + public void execute( + ResolvableDependencies resolvableDependencies) { + resolvableDependencies.getDependencies() + .all(new Action() { + @Override + public void execute(Dependency dependency) { + applyExcludeRules(dependency); + } + }); + } + }); + } + } + + private void applyExcludeRules(Dependency dependency) { + if (dependency instanceof ModuleDependency) { + applyExcludeRules((ModuleDependency) dependency); + } + } + + private void applyExcludeRules(ModuleDependency dependency) { + ManagedDependencies managedDependencies = this.versionManagedDependencies + .getManagedDependencies(); + // flat directory repositories do not have groups + if (dependency.getGroup() != null) { + org.springframework.boot.dependency.tools.Dependency managedDependency = managedDependencies + .find(dependency.getGroup(), dependency.getName()); + if (managedDependency != null) { + for (Exclusion exclusion : managedDependency.getExclusions()) { + addExcludeRule(dependency, exclusion); + } + addImplicitExcludeRules(dependency); + return; + } + } + this.logger.debug( + "No exclusions rules applied for non-managed dependency " + dependency); + } + + private void addExcludeRule(ModuleDependency dependency, Exclusion exclusion) { + this.logger + .info("Adding managed exclusion rule " + exclusion + " to " + dependency); + DefaultExcludeRule rule = new DefaultExcludeRule(exclusion.getGroupId(), + exclusion.getArtifactId()); + dependency.getExcludeRules().add(rule); + } + + private void addImplicitExcludeRules(ModuleDependency dependency) { + if (isStarter(dependency)) { + this.logger.info( + "Adding implicit managed exclusion rules to starter " + dependency); + dependency.getExcludeRules() + .add(new DefaultExcludeRule("commons-logging", "commons-logging")); + dependency.getExcludeRules().add( + new DefaultExcludeRule("commons-logging", "commons-logging-api")); + } + } + + private boolean isStarter(ModuleDependency dependency) { + return (dependency.getGroup() != null + && dependency.getGroup().equals("org.springframework.boot") + && dependency.getName().startsWith("spring-boot-starter")); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ExcludePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ExcludePluginFeatures.java new file mode 100644 index 00000000000..04253842d26 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/exclude/ExcludePluginFeatures.java @@ -0,0 +1,39 @@ +/* + * 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.exclude; + +import org.gradle.api.Project; +import org.springframework.boot.gradle.PluginFeatures; +import org.springframework.boot.gradle.SpringBootPluginExtension; + +/** + * {@link PluginFeatures} to apply exclusion rules. + * + * @author Phillip Webb + */ +public class ExcludePluginFeatures implements PluginFeatures { + + @Override + public void apply(Project project) { + SpringBootPluginExtension extension = project.getExtensions() + .getByType(SpringBootPluginExtension.class); + if (extension.isApplyExcludeRules()) { + project.getConfigurations().all(new ApplyExcludeRules(project)); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java new file mode 100644 index 00000000000..331ca33f5b6 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java @@ -0,0 +1,243 @@ +/* + * 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 java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.FileCollectionDependency; +import org.gradle.api.artifacts.ModuleVersionIdentifier; +import org.gradle.api.artifacts.ProjectDependency; +import org.gradle.api.artifacts.ResolvedArtifact; +import org.springframework.boot.gradle.SpringBootPluginExtension; +import org.springframework.boot.loader.tools.Libraries; +import org.springframework.boot.loader.tools.Library; +import org.springframework.boot.loader.tools.LibraryCallback; +import org.springframework.boot.loader.tools.LibraryScope; + +/** + * Expose Gradle {@link Configuration}s as {@link Libraries}. + * + * @author Phillip Webb + * @author Andy Wilkinson + */ +class ProjectLibraries implements Libraries { + + private final Project project; + + private final SpringBootPluginExtension extension; + + private String providedConfigurationName = "providedRuntime"; + + private String customConfigurationName = null; + + /** + * Create a new {@link ProjectLibraries} instance of the specified {@link Project} . + * @param project the gradle project + * @param extension the extension + */ + public ProjectLibraries(Project project, SpringBootPluginExtension extension) { + this.project = project; + this.extension = extension; + } + + /** + * Set the name of the provided configuration. Defaults to 'providedRuntime'. + * @param providedConfigurationName the providedConfigurationName to set + */ + public void setProvidedConfigurationName(String providedConfigurationName) { + this.providedConfigurationName = providedConfigurationName; + } + + public void setCustomConfigurationName(String customConfigurationName) { + this.customConfigurationName = customConfigurationName; + } + + @Override + public void doWithLibraries(LibraryCallback callback) throws IOException { + Set custom = getLibraries(this.customConfigurationName, + LibraryScope.CUSTOM); + if (custom != null) { + libraries(custom, callback); + } + else { + Set compile = getLibraries("compile", LibraryScope.COMPILE); + Set runtime = getLibraries("runtime", LibraryScope.RUNTIME); + runtime = minus(runtime, compile); + Set provided = getLibraries(this.providedConfigurationName, + LibraryScope.PROVIDED); + if (provided != null) { + compile = minus(compile, provided); + runtime = minus(runtime, provided); + } + libraries(compile, callback); + libraries(runtime, callback); + libraries(provided, callback); + } + } + + private Set getLibraries(String configurationName, + LibraryScope scope) { + Configuration configuration = (configurationName == null ? null + : this.project.getConfigurations().findByName(configurationName)); + if (configuration == null) { + return null; + } + Set libraries = new LinkedHashSet(); + for (ResolvedArtifact artifact : configuration.getResolvedConfiguration() + .getResolvedArtifacts()) { + libraries.add(new ResolvedArtifactLibrary(artifact, scope)); + } + libraries.addAll(getLibrariesForFileDependencies(configuration, scope)); + return libraries; + } + + private Set getLibrariesForFileDependencies( + Configuration configuration, LibraryScope scope) { + Set libraries = new LinkedHashSet(); + for (Dependency dependency : configuration.getIncoming().getDependencies()) { + if (dependency instanceof FileCollectionDependency) { + FileCollectionDependency fileDependency = (FileCollectionDependency) dependency; + for (File file : fileDependency.resolve()) { + libraries.add( + new GradleLibrary(fileDependency.getGroup(), file, scope)); + } + } + else if (dependency instanceof ProjectDependency) { + ProjectDependency projectDependency = (ProjectDependency) dependency; + libraries.addAll(getLibrariesForFileDependencies( + projectDependency.getProjectConfiguration(), scope)); + } + } + return libraries; + } + + private Set minus(Set source, + Set toRemove) { + if (source == null || toRemove == null) { + return source; + } + Set filesToRemove = new HashSet(); + for (GradleLibrary library : toRemove) { + filesToRemove.add(library.getFile()); + } + Set result = new LinkedHashSet(); + for (GradleLibrary library : source) { + if (!filesToRemove.contains(library.getFile())) { + result.add(library); + } + } + return result; + } + + private void libraries(Set libraries, LibraryCallback callback) + throws IOException { + if (libraries != null) { + Set duplicates = getDuplicates(libraries); + for (GradleLibrary library : libraries) { + library.setIncludeGroupName(duplicates.contains(library.getName())); + callback.library(library); + } + } + } + + private Set getDuplicates(Set libraries) { + Set duplicates = new HashSet(); + Set seen = new HashSet(); + for (GradleLibrary library : libraries) { + if (library.getFile() != null && !seen.add(library.getFile().getName())) { + duplicates.add(library.getFile().getName()); + } + } + return duplicates; + } + + private class GradleLibrary extends Library { + + private final String group; + + private boolean includeGroupName; + + public GradleLibrary(String group, File file, LibraryScope scope) { + super(file, scope); + this.group = group; + } + + public void setIncludeGroupName(boolean includeGroupName) { + this.includeGroupName = includeGroupName; + } + + @Override + public String getName() { + String name = super.getName(); + if (this.includeGroupName && this.group != null) { + name = this.group + "-" + name; + } + return name; + } + + @Override + public int hashCode() { + return getFile().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GradleLibrary) { + return getFile().equals(((GradleLibrary) obj).getFile()); + } + return false; + } + + @Override + public String toString() { + return getFile().getAbsolutePath(); + } + } + + /** + * Adapts a {@link ResolvedArtifact} to a {@link Library}. + */ + private class ResolvedArtifactLibrary extends GradleLibrary { + + private final ResolvedArtifact artifact; + + public ResolvedArtifactLibrary(ResolvedArtifact artifact, LibraryScope scope) { + super(artifact.getModuleVersion().getId().getGroup(), artifact.getFile(), + scope); + this.artifact = artifact; + } + + @Override + public boolean isUnpackRequired() { + if (ProjectLibraries.this.extension.getRequiresUnpack() != null) { + ModuleVersionIdentifier id = this.artifact.getModuleVersion().getId(); + return ProjectLibraries.this.extension.getRequiresUnpack() + .contains(id.getGroup() + ":" + id.getName()); + } + return false; + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java new file mode 100644 index 00000000000..f6e00efc9eb --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java @@ -0,0 +1,161 @@ +/* + * Copyright 2012-2015 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 java.io.File; +import java.io.IOException; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.logging.Logger; +import org.gradle.api.plugins.BasePlugin; +import org.gradle.api.plugins.JavaPlugin; +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.loader.tools.Library; +import org.springframework.boot.loader.tools.LibraryCallback; +import org.springframework.util.StringUtils; + +/** + * {@link PluginFeatures} to add repackage support. + * + * @author Phillip Webb + * @author Dave Syer + * @author Andy Wilkinson + */ +public class RepackagePluginFeatures implements PluginFeatures { + + public 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); + Configuration runtimeConfiguration = project.getConfigurations() + .getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME); + TaskDependency runtimeProjectDependencyJarTasks = runtimeConfiguration + .getTaskDependencyFromProjectDependency(true, JavaPlugin.JAR_TASK_NAME); + task.dependsOn( + project.getConfigurations().getByName(Dependency.ARCHIVES_CONFIGURATION) + .getAllArtifacts().getBuildDependencies(), + runtimeProjectDependencyJarTasks); + registerOutput(project, task); + ensureTaskRunsOnAssembly(project, task); + } + + private void registerOutput(Project project, final RepackageTask task) { + project.afterEvaluate(new Action() { + @Override + public void execute(Project project) { + project.getTasks().withType(Jar.class, + new RegisterInputsOutputsAction(task)); + Object withJar = task.getWithJarTask(); + if (withJar != null) { + task.dependsOn(withJar); + } + } + }); + } + + 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); + } + + /** + * Register task input/outputs when classifiers are used + */ + private static class RegisterInputsOutputsAction implements Action { + + private final RepackageTask task; + + private final Project project; + + public RegisterInputsOutputsAction(RepackageTask task) { + this.task = task; + this.project = task.getProject(); + } + + @Override + public void execute(Jar jarTask) { + if ("".equals(jarTask.getClassifier())) { + String classifier = this.task.getClassifier(); + if (classifier == null) { + SpringBootPluginExtension extension = this.project.getExtensions() + .getByType(SpringBootPluginExtension.class); + classifier = extension.getClassifier(); + this.task.setClassifier(classifier); + } + if (classifier != null) { + setupInputOutputs(jarTask, classifier); + } + } + } + + private void setupInputOutputs(Jar jarTask, String classifier) { + Logger logger = this.project.getLogger(); + logger.debug("Using classifier: " + classifier + " for task " + + this.task.getName()); + File inputFile = jarTask.getArchivePath(); + String outputName = inputFile.getName(); + outputName = StringUtils.stripFilenameExtension(outputName) + "-" + classifier + + "." + StringUtils.getFilenameExtension(outputName); + File outputFile = new File(inputFile.getParentFile(), outputName); + this.task.getInputs().file(jarTask); + addLibraryDependencies(this.task); + this.task.getOutputs().file(outputFile); + this.task.setOutputFile(outputFile); + } + + private void addLibraryDependencies(final RepackageTask task) { + try { + task.getLibraries().doWithLibraries(new LibraryCallback() { + @Override + public void library(Library library) throws IOException { + task.getInputs().file(library.getFile()); + } + }); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java new file mode 100644 index 00000000000..5e71239fbf9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java @@ -0,0 +1,236 @@ +/* + * 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 java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +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.TaskAction; +import org.gradle.api.tasks.bundling.Jar; +import org.springframework.boot.gradle.SpringBootPluginExtension; +import org.springframework.boot.loader.tools.Repackager; +import org.springframework.util.FileCopyUtils; + +/** + * Repackage task. + * + * @author Phillip Webb + * @author Janne Valkealahti + * @author Andy Wilkinson + */ +public class RepackageTask extends DefaultTask { + + private static final long FIND_WARNING_TIMEOUT = TimeUnit.SECONDS.toMillis(10); + + private String customConfiguration; + + private Object withJarTask; + + private String mainClass; + + private String classifier; + + private File outputFile; + + public void setCustomConfiguration(String customConfiguration) { + this.customConfiguration = customConfiguration; + } + + public Object getWithJarTask() { + return this.withJarTask; + } + + public void setWithJarTask(Object withJarTask) { + this.withJarTask = withJarTask; + } + + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + public String getMainClass() { + return this.mainClass; + } + + public String getClassifier() { + return this.classifier; + } + + public void setClassifier(String classifier) { + this.classifier = classifier; + } + + @TaskAction + public void repackage() { + Project project = getProject(); + SpringBootPluginExtension extension = project.getExtensions() + .getByType(SpringBootPluginExtension.class); + ProjectLibraries libraries = getLibraries(); + project.getTasks().withType(Jar.class, new RepackageAction(extension, libraries)); + } + + public ProjectLibraries getLibraries() { + Project project = getProject(); + SpringBootPluginExtension extension = project.getExtensions() + .getByType(SpringBootPluginExtension.class); + ProjectLibraries libraries = new ProjectLibraries(project, extension); + if (extension.getProvidedConfiguration() != null) { + libraries.setProvidedConfigurationName(extension.getProvidedConfiguration()); + } + if (this.customConfiguration != null) { + libraries.setCustomConfigurationName(this.customConfiguration); + } + else if (extension.getCustomConfiguration() != null) { + libraries.setCustomConfigurationName(extension.getCustomConfiguration()); + } + return libraries; + } + + /** + * Action to repackage JARs. + */ + private class RepackageAction implements Action { + + private final SpringBootPluginExtension extension; + + private final ProjectLibraries libraries; + + public RepackageAction(SpringBootPluginExtension extension, + ProjectLibraries libraries) { + this.extension = extension; + this.libraries = libraries; + } + + @Override + public void execute(Jar jarTask) { + if (!RepackageTask.this.isEnabled()) { + getLogger().info("Repackage disabled"); + return; + } + Object withJarTask = RepackageTask.this.withJarTask; + if (!isTaskMatch(jarTask, withJarTask)) { + getLogger().info( + "Jar task not repackaged (didn't match withJarTask): " + jarTask); + return; + } + File file = jarTask.getArchivePath(); + if (file.exists()) { + repackage(file); + } + } + + private boolean isTaskMatch(Jar task, Object withJarTask) { + if (withJarTask == null) { + if ("".equals(task.getClassifier())) { + Set tasksWithCustomRepackaging = new HashSet(); + for (RepackageTask repackageTask : RepackageTask.this.getProject() + .getTasks().withType(RepackageTask.class)) { + if (repackageTask.getWithJarTask() != null) { + tasksWithCustomRepackaging + .add(repackageTask.getWithJarTask()); + } + } + return !tasksWithCustomRepackaging.contains(task); + } + return false; + } + return task.equals(withJarTask) || task.getName().equals(withJarTask); + } + + private void repackage(File file) { + File outputFile = RepackageTask.this.outputFile; + if (outputFile != null && !file.equals(outputFile)) { + copy(file, outputFile); + file = outputFile; + } + Repackager repackager = new LoggingRepackager(file); + setMainClass(repackager); + if (this.extension.convertLayout() != null) { + repackager.setLayout(this.extension.convertLayout()); + } + repackager.setBackupSource(this.extension.isBackupSource()); + try { + repackager.repackage(file, this.libraries); + } + catch (IOException ex) { + throw new IllegalStateException(ex.getMessage(), ex); + } + } + + private void copy(File source, File dest) { + try { + FileCopyUtils.copy(source, dest); + } + catch (IOException ex) { + throw new IllegalStateException(ex.getMessage(), ex); + } + } + + private void setMainClass(Repackager repackager) { + String mainClass = (String) getProject().property("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"); + } + getLogger().info("Setting mainClass: " + mainClass); + repackager.setMainClass(mainClass); + } + } + + /** + * {@link Repackager} that also logs when searching takes too long. + */ + private class LoggingRepackager extends Repackager { + + public LoggingRepackager(File source) { + super(source); + } + + @Override + protected String findMainMethod(java.util.jar.JarFile source) throws IOException { + long startTime = System.currentTimeMillis(); + try { + return super.findMainMethod(source); + } + finally { + long duration = System.currentTimeMillis() - startTime; + if (duration > FIND_WARNING_TIMEOUT) { + getLogger().warn("Searching for the main-class is taking " + + "some time, consider using setting " + + "'springBoot.mainClass'"); + } + } + } + } + + void setOutputFile(File file) { + this.outputFile = file; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/resolve/ResolvePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/resolve/ResolvePluginFeatures.java new file mode 100644 index 00000000000..0aa37180706 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/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().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/java/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java new file mode 100644 index 00000000000..739d0eb1647 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/resolve/SpringBootResolutionStrategy.java @@ -0,0 +1,79 @@ +/* + * 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.gradle.api.artifacts.DependencyResolveDetails; +import org.gradle.api.artifacts.ModuleVersionSelector; +import org.springframework.boot.dependency.tools.Dependency; +import org.springframework.boot.dependency.tools.ManagedDependencies; +import org.springframework.boot.gradle.VersionManagedDependencies; + +/** + * A resolution strategy to resolve missing version numbers using the + * 'spring-boot-dependencies' POM. + * + * @author Phillip Webb + */ +public class SpringBootResolutionStrategy { + + private static final String SPRING_BOOT_GROUP = "org.springframework.boot"; + + public static void applyToConfiguration(final Project project, + Configuration configuration) { + if (VersionManagedDependencies.CONFIGURATION.equals(configuration.getName())) { + return; + } + VersionResolver versionResolver = new VersionResolver(project); + configuration.getResolutionStrategy().eachDependency(versionResolver); + } + + private static class VersionResolver implements Action { + + private final VersionManagedDependencies versionManagedDependencies; + + public VersionResolver(Project project) { + this.versionManagedDependencies = new VersionManagedDependencies(project); + } + + @Override + public void execute(DependencyResolveDetails resolveDetails) { + String version = resolveDetails.getTarget().getVersion(); + if (version == null || version.trim().length() == 0) { + resolve(resolveDetails); + } + } + + private void resolve(DependencyResolveDetails resolveDetails) { + ManagedDependencies dependencies = this.versionManagedDependencies + .getManagedDependencies(); + ModuleVersionSelector target = resolveDetails.getTarget(); + if (SPRING_BOOT_GROUP.equals(target.getGroup())) { + resolveDetails.useVersion(dependencies.getSpringBootVersion()); + return; + } + Dependency dependency = dependencies.find(target.getGroup(), + target.getName()); + if (dependency != null) { + resolveDetails.useVersion(dependency.getVersion()); + } + } + + } +} 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 new file mode 100644 index 00000000000..05c9d52fff7 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2015 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 { + + /** + * Whether or not resources (typically in {@code src/main/resources} are added + * directly to the classpath. When enabled (the default), 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 = true; + + public boolean getAddResources() { + return this.addResources; + } + + public void setAddResources(boolean addResources) { + this.addResources = addResources; + } + + @Override + public void exec() { + 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/FindMainClassTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java new file mode 100644 index 00000000000..00f553b5ea9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java @@ -0,0 +1,102 @@ +/* + * 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.IOException; + +import org.gradle.api.DefaultTask; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.ApplicationPluginConvention; +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(); + + String mainClass = null; + + // Try the SpringBoot extension setting + SpringBootPluginExtension bootExtension = project.getExtensions() + .getByType(SpringBootPluginExtension.class); + if (bootExtension.getMainClass() != null) { + mainClass = bootExtension.getMainClass(); + } + + ApplicationPluginConvention application = (ApplicationPluginConvention) project + .getConvention().getPlugins().get("application"); + // Try the Application extension setting + if (mainClass == null && application.getMainClassName() != null) { + mainClass = application.getMainClassName(); + } + + Task runTask = getProject().getTasks().getByName("run"); + if (mainClass == null && runTask.hasProperty("main")) { + mainClass = (String) runTask.property("main"); + } + + if (mainClass == null) { + // Search + SourceSet mainSourceSet = SourceSets.findMainSourceSet(project); + if (mainSourceSet != null) { + project.getLogger().debug("Looking for main in: " + + mainSourceSet.getOutput().getClassesDir()); + try { + mainClass = MainClassFinder.findSingleMainClass( + mainSourceSet.getOutput().getClassesDir()); + project.getLogger().info("Computed main class: " + mainClass); + } + catch (IOException ex) { + throw new IllegalStateException("Cannot find main class", ex); + } + } + } + + project.getLogger().info("Found main: " + mainClass); + + if (bootExtension.getMainClass() == null) { + bootExtension.setMainClass(mainClass); + } + if (application.getMainClassName() == null) { + application.setMainClassName(mainClass); + } + if (!runTask.hasProperty("main")) { + runTask.setProperty("main", mainClass); + } + + return mainClass; + } +} 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 new file mode 100644 index 00000000000..40f8e34c54f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java @@ -0,0 +1,85 @@ +/* + * 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 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.gradle.api.tasks.application.CreateStartScripts; +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 instanceof CreateStartScripts) { + 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 { + if (project.hasProperty("applicationDefaultJvmArgs")) { + return project.property("applicationDefaultJvmArgs"); + } + return Collections.emptyList(); + } + }); + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/SourceSets.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/SourceSets.java new file mode 100644 index 00000000000..b7c020d2b31 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/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(); + } + +}