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 19afbb24559..cd36bc8592c 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 @@ -16,13 +16,35 @@ 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'. + * 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()); + Layout layout; + private LayoutType(Layout layout) { + this.layout = layout; + } + } + /** * 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 @@ -31,7 +53,8 @@ public class SpringBootPluginExtension { String mainClass /** - * The name of the provided configuration. If not specified 'providedRuntime' will + * 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 @@ -40,4 +63,23 @@ public class SpringBootPluginExtension { * 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 + } } 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/task/Repackage.java index 9b455ae0775..521a936e184 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/task/Repackage.java @@ -50,11 +50,13 @@ public class Repackage extends DefaultTask { if (file.exists()) { Repackager repackager = new Repackager(file); repackager.setMainClass(extension.getMainClass()); + if (extension.convertLayout() != null) { + repackager.setLayout(extension.convertLayout()); + } repackager.setBackupSource(extension.isBackupSource()); try { repackager.repackage(libraries); - } - catch (IOException ex) { + } catch (IOException ex) { throw new IllegalStateException(ex.getMessage(), ex); } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/org/springframework/boot/git.properties b/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/org/springframework/boot/git.properties index 4c71ec6a6bc..ec98f87d954 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/org/springframework/boot/git.properties +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/org/springframework/boot/git.properties @@ -1,13 +1,13 @@ #Generated by Git-Commit-Id-Plugin -#Tue Oct 15 11:07:38 EDT 2013 -git.commit.id.abbrev=d3fa609 +#Tue Oct 15 11:35:18 EDT 2013 +git.commit.id.abbrev=ea11daf git.commit.user.email=dsyer@gopivotal.com git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n -git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312 +git.commit.id=ea11dafcbd951b3b23257585bce1f479ca9faa73 git.commit.message.short=Extend PropertiesLauncher to load nested archives git.commit.user.name=Dave Syer git.build.user.name=Dave Syer git.build.user.email=dsyer@gopivotal.com git.branch=master -git.commit.time=2013-10-15T10\:51\:03-0400 -git.build.time=2013-10-15T11\:07\:38-0400 +git.commit.time=2013-10-15T11\:08\:45-0400 +git.build.time=2013-10-15T11\:35\:18-0400 diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java index b3e2d3becf8..32ac121f60a 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java @@ -43,6 +43,9 @@ public class Layouts { if (file.getName().toLowerCase().endsWith(".war")) { return new War(); } + if (file.isDirectory() || file.getName().toLowerCase().endsWith(".zip")) { + return new Expanded(); + } throw new IllegalStateException("Unable to deduce layout for '" + file + "'"); } @@ -67,6 +70,18 @@ public class Layouts { } } + /** + * Executable expanded archive layout. + */ + public static class Expanded extends Jar { + + @Override + public String getLauncherClassName() { + return "org.springframework.boot.loader.PropertiesLauncher"; + } + + } + /** * Executable WAR layout. */ diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/git.properties b/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/git.properties index c284d0a7ad7..7cea85057ff 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/git.properties +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/git.properties @@ -1,13 +1,13 @@ #Generated by Git-Commit-Id-Plugin -#Tue Oct 15 11:07:33 EDT 2013 -git.commit.id.abbrev=d3fa609 +#Wed Oct 16 08:14:33 EDT 2013 +git.commit.id.abbrev=a7ba9ba git.commit.user.email=dsyer@gopivotal.com -git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n -git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312 -git.commit.message.short=Extend PropertiesLauncher to load nested archives +git.commit.message.full=Tooling for PropertiesLauncher\n +git.commit.id=a7ba9ba5cd47a924f9c7668a772957fc05ffa058 +git.commit.message.short=Tooling for PropertiesLauncher git.commit.user.name=Dave Syer git.build.user.name=Dave Syer git.build.user.email=dsyer@gopivotal.com -git.branch=master -git.commit.time=2013-10-15T10\:51\:03-0400 -git.build.time=2013-10-15T11\:07\:33-0400 +git.branch=feature/proptool +git.commit.time=2013-10-15T16\:54\:14-0400 +git.build.time=2013-10-16T08\:14\:33-0400 diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/Archive.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/Archive.java index 8bc7acbcc36..fd28fe63c53 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/Archive.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/Archive.java @@ -47,9 +47,21 @@ public abstract class Archive { * @throws Exception */ public String getMainClass() throws Exception { - String mainClass = getManifest().getMainAttributes().getValue("Start-Class"); + Manifest manifest = getManifest(); + String mainClass = null; + if (manifest != null) { + mainClass = manifest.getMainAttributes().getValue("Start-Class"); + } if (mainClass == null) { - throw new IllegalStateException("No 'Start-Class' manifest entry specified"); + String url = "UNKNOWN"; + try { + url = getUrl().toString(); + } + catch (Exception e) { + // ignore + } + throw new IllegalStateException( + "No 'Start-Class' manifest entry specified in " + url); } return mainClass; } diff --git a/spring-boot-tools/spring-boot-loader/src/main/resources/org/springframework/boot/git.properties b/spring-boot-tools/spring-boot-loader/src/main/resources/org/springframework/boot/git.properties index 35fc5e979aa..10e364fba2c 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/resources/org/springframework/boot/git.properties +++ b/spring-boot-tools/spring-boot-loader/src/main/resources/org/springframework/boot/git.properties @@ -1,13 +1,13 @@ #Generated by Git-Commit-Id-Plugin -#Tue Oct 15 11:07:32 EDT 2013 -git.commit.id.abbrev=d3fa609 +#Wed Oct 16 08:17:37 EDT 2013 +git.commit.id.abbrev=a7ba9ba git.commit.user.email=dsyer@gopivotal.com -git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n -git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312 -git.commit.message.short=Extend PropertiesLauncher to load nested archives +git.commit.message.full=Tooling for PropertiesLauncher\n +git.commit.id=a7ba9ba5cd47a924f9c7668a772957fc05ffa058 +git.commit.message.short=Tooling for PropertiesLauncher git.commit.user.name=Dave Syer git.build.user.name=Dave Syer git.build.user.email=dsyer@gopivotal.com -git.branch=master -git.commit.time=2013-10-15T10\:51\:03-0400 -git.build.time=2013-10-15T11\:07\:32-0400 +git.branch=feature/proptool +git.commit.time=2013-10-15T16\:54\:14-0400 +git.build.time=2013-10-16T08\:17\:37-0400 diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml new file mode 100644 index 00000000000..56b0b7cd6c3 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar + 0.0.1.BUILD-SNAPSHOT + jar + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + ZIP + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + Foo + + + + + + + + + org.springframework + spring-context + 3.2.3.RELEASE + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/src/main/java/org/test/SampleApplication.java b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..0b3b431677d --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,8 @@ +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/verify.groovy new file mode 100644 index 00000000000..c0017946271 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/prop/verify.groovy @@ -0,0 +1,7 @@ +import java.io.*; +import org.springframework.boot.maven.*; + +Verify.verifyZip( + new File( basedir, "target/jar-0.0.1.BUILD-SNAPSHOT.jar" ) +); + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index a5770f1649d..aa020b47c4d 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -29,6 +29,8 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectHelper; +import org.springframework.boot.loader.tools.Layout; +import org.springframework.boot.loader.tools.Layouts; import org.springframework.boot.loader.tools.Libraries; import org.springframework.boot.loader.tools.Repackager; @@ -81,12 +83,22 @@ public class RepackageMojo extends AbstractMojo { @Parameter private String mainClass; + /** + * The layout to use (JAR, WAR, ZIP, DIR) in case it cannot be inferred. + */ + @Parameter + private LayoutType layout; + @Override public void execute() throws MojoExecutionException, MojoFailureException { File source = this.project.getArtifact().getFile(); File target = getTargetFile(); Repackager repackager = new Repackager(source); repackager.setMainClass(this.mainClass); + if (this.layout != null) { + getLog().info("Layout: " + this.layout); + repackager.setLayout(this.layout.layout()); + } Libraries libraries = new ArtifactsLibraries(this.project.getArtifacts()); try { repackager.repackage(target, libraries); @@ -112,4 +124,18 @@ public class RepackageMojo extends AbstractMojo { + this.project.getPackaging()); } + public static enum LayoutType { + JAR(new Layouts.Jar()), WAR(new Layouts.War()), ZIP(new Layouts.Expanded()), DIR( + new Layouts.Expanded()); + private Layout layout; + + public Layout layout() { + return this.layout; + } + + private LayoutType(Layout layout) { + this.layout = layout; + } + } + } diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/resources/org/springframework/boot/git.properties b/spring-boot-tools/spring-boot-maven-plugin/src/main/resources/org/springframework/boot/git.properties index 1bd00a35e83..6b11be6bc0e 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/resources/org/springframework/boot/git.properties +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/resources/org/springframework/boot/git.properties @@ -1,13 +1,13 @@ #Generated by Git-Commit-Id-Plugin -#Tue Oct 15 11:07:34 EDT 2013 -git.commit.id.abbrev=d3fa609 +#Wed Oct 16 08:42:05 EDT 2013 +git.commit.id.abbrev=a7ba9ba git.commit.user.email=dsyer@gopivotal.com -git.commit.message.full=Extend PropertiesLauncher to load nested archives\n\nPropertiesLauncher can now be used to run an executable jar, and by\ndefault it will pick up nested archives in lib/ (where the Boot\ntools puts them). User can provide loader.path (colon-separated)\nto change the nested path.\n\n[\#58837492] [bs-330] Add tooling for PropertiesLauncher\n -git.commit.id=d3fa60955b06fe78bbf0c914928d794661aca312 -git.commit.message.short=Extend PropertiesLauncher to load nested archives +git.commit.message.full=Tooling for PropertiesLauncher\n +git.commit.id=a7ba9ba5cd47a924f9c7668a772957fc05ffa058 +git.commit.message.short=Tooling for PropertiesLauncher git.commit.user.name=Dave Syer git.build.user.name=Dave Syer git.build.user.email=dsyer@gopivotal.com -git.branch=master -git.commit.time=2013-10-15T10\:51\:03-0400 -git.build.time=2013-10-15T11\:07\:34-0400 +git.branch=feature/proptool +git.commit.time=2013-10-15T16\:54\:14-0400 +git.build.time=2013-10-16T08\:42\:05-0400 diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java index 2e71889855b..dd7e879cb2c 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java @@ -46,6 +46,10 @@ public class Verify { new WarArchiveVerification(file).verify(); } + public static void verifyZip(File file) throws Exception { + new ZipArchiveVerification(file).verify(); + } + private static abstract class AbstractArchiveVerification { private File file; @@ -154,4 +158,20 @@ public class Verify { } } + private static class ZipArchiveVerification extends AbstractArchiveVerification { + + public ZipArchiveVerification(File file) { + super(file); + } + + @Override + protected void verifyManifest(Manifest manifest) throws Exception { + assertEquals("org.springframework.boot.loader.PropertiesLauncher", manifest + .getMainAttributes().getValue("Main-Class")); + assertEquals("org.test.SampleApplication", manifest.getMainAttributes() + .getValue("Start-Class")); + assertEquals("Foo", manifest.getMainAttributes().getValue("Not-Used")); + } + } + }