Support embedded jar initialization scripts
Update the Maven and Gradle plugin to generate fully executable jar files on Unix like machines. A launcher bash script is added to the front of the jar file which handles execution. The default execution script will either launch the application or handle init.d service operations (start/stop/restart) depending on if the application is executed directly, or via a symlink to init.d. See gh-1117
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>@project.groupId@</groupId>
|
||||
<artifactId>@project.artifactId@</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<embeddedLaunchScript>${basedir}/src/launcher/custom.script</embeddedLaunchScript>
|
||||
<embeddedLaunchScriptProperties>
|
||||
<name>world</name>
|
||||
</embeddedLaunchScriptProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>some.random.Main</mainClass>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Not-Used>Foo</Not-Used>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>@spring.version@</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>@servlet-api.version@</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Hello {{name}}"
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.test;
|
||||
|
||||
public class SampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.io.*;
|
||||
import org.springframework.boot.maven.*;
|
||||
|
||||
Verify.verifyJar(
|
||||
new File( basedir, "target/jar-0.0.1.BUILD-SNAPSHOT.jar" ), "some.random.Main", "Hello world"
|
||||
);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.maven.it</groupId>
|
||||
<artifactId>jar</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>@project.groupId@</groupId>
|
||||
<artifactId>@project.artifactId@</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>false</executable>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>some.random.Main</mainClass>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Not-Used>Foo</Not-Used>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>@spring.version@</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>@servlet-api.version@</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.test;
|
||||
|
||||
public class SampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.io.*;
|
||||
import org.springframework.boot.maven.*;
|
||||
|
||||
Verify.verifyJar(
|
||||
new File( basedir, "target/jar-0.0.1.BUILD-SNAPSHOT.jar" ), "some.random.Main", false
|
||||
);
|
||||
|
||||
@@ -2,6 +2,6 @@ import java.io.*;
|
||||
import org.springframework.boot.maven.*;
|
||||
|
||||
Verify.verifyJar(
|
||||
new File( basedir, "target/jar-0.0.1.BUILD-SNAPSHOT.jar" ), "some.random.Main"
|
||||
new File( basedir, "target/jar-0.0.1.BUILD-SNAPSHOT.jar" ), "some.random.Main", "Spring Boot Startup Script"
|
||||
);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.maven;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.jar.JarFile;
|
||||
@@ -34,6 +35,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.DefaultLaunchScript;
|
||||
import org.springframework.boot.loader.tools.LaunchScript;
|
||||
import org.springframework.boot.loader.tools.Layout;
|
||||
import org.springframework.boot.loader.tools.Layouts;
|
||||
import org.springframework.boot.loader.tools.Libraries;
|
||||
@@ -124,6 +127,29 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
|
||||
@Parameter
|
||||
private List<Dependency> requiresUnpack;
|
||||
|
||||
/**
|
||||
* Make a fully executable jar for *nix machines by prepending a launch script to the
|
||||
* jar.
|
||||
* @since 1.3
|
||||
*/
|
||||
@Parameter(defaultValue = "true")
|
||||
private boolean executable;
|
||||
|
||||
/**
|
||||
* The embedded launch script to prepend to the front of the jar if it is fully
|
||||
* executable. If not specified the 'Spring Boot' default script will be used.
|
||||
* @since 1.3
|
||||
*/
|
||||
@Parameter
|
||||
private File embeddedLaunchScript;
|
||||
|
||||
/**
|
||||
* Properties that should be expanded in the embedded launch script.
|
||||
* @since 1.3
|
||||
*/
|
||||
@Parameter
|
||||
private Properties embeddedLaunchScriptProperties;
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||
if (this.project.getPackaging().equals("pom")) {
|
||||
@@ -167,7 +193,8 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
|
||||
Libraries libraries = new ArtifactsLibraries(artifacts, this.requiresUnpack,
|
||||
getLog());
|
||||
try {
|
||||
repackager.repackage(target, libraries);
|
||||
LaunchScript launchScript = getLaunchScript();
|
||||
repackager.repackage(target, libraries, launchScript);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new MojoExecutionException(ex.getMessage(), ex);
|
||||
@@ -190,6 +217,14 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
|
||||
+ this.project.getPackaging());
|
||||
}
|
||||
|
||||
private LaunchScript getLaunchScript() throws IOException {
|
||||
if (this.executable) {
|
||||
return new DefaultLaunchScript(this.embeddedLaunchScript,
|
||||
this.embeddedLaunchScriptProperties);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static enum LayoutType {
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,8 +26,12 @@ import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
@@ -44,8 +48,14 @@ public class Verify {
|
||||
new JarArchiveVerification(file, SAMPLE_APP).verify();
|
||||
}
|
||||
|
||||
public static void verifyJar(File file, String main) throws Exception {
|
||||
new JarArchiveVerification(file, main).verify();
|
||||
public static void verifyJar(File file, String main, String... scriptContents)
|
||||
throws Exception {
|
||||
verifyJar(file, main, true, scriptContents);
|
||||
}
|
||||
|
||||
public static void verifyJar(File file, String main, boolean executable,
|
||||
String... scriptContents) throws Exception {
|
||||
new JarArchiveVerification(file, main).verify(executable, scriptContents);
|
||||
}
|
||||
|
||||
public static void verifyWar(File file) throws Exception {
|
||||
@@ -149,9 +159,30 @@ public class Verify {
|
||||
}
|
||||
|
||||
public void verify() throws Exception {
|
||||
verify(true);
|
||||
}
|
||||
|
||||
public void verify(boolean executable, String... scriptContents) throws Exception {
|
||||
assertTrue("Archive missing", this.file.exists());
|
||||
assertTrue("Archive not a file", this.file.isFile());
|
||||
|
||||
if (scriptContents.length > 0 && executable) {
|
||||
String contents = new String(FileCopyUtils.copyToByteArray(this.file));
|
||||
contents = contents.substring(0, contents.indexOf(new String(new byte[] {
|
||||
0x50, 0x4b, 0x03, 0x04 })));
|
||||
for (String content : scriptContents) {
|
||||
assertThat(contents, containsString(content));
|
||||
}
|
||||
}
|
||||
|
||||
if (!executable) {
|
||||
String contents = new String(FileCopyUtils.copyToByteArray(this.file));
|
||||
assertTrue(
|
||||
"Is executable",
|
||||
contents.startsWith(new String(new byte[] { 0x50, 0x4b, 0x03,
|
||||
0x04 })));
|
||||
}
|
||||
|
||||
ZipFile zipFile = new ZipFile(this.file);
|
||||
try {
|
||||
ArchiveVerifier verifier = new ArchiveVerifier(zipFile);
|
||||
|
||||
Reference in New Issue
Block a user