Provide sensible defaults for launch script properties when using Gradle
Closes gh-4458
This commit is contained in:
parent
b01efb2392
commit
a097f923c1
|
@ -678,69 +678,98 @@ Spring Boot Maven or Gradle plugins.
|
||||||
|
|
||||||
The following property substitutions are supported with the default script:
|
The following property substitutions are supported with the default script:
|
||||||
|
|
||||||
[cols="1,6"]
|
[cols="1,3,3,3"]
|
||||||
|===
|
|===
|
||||||
|Name |Description
|
|Name |Description |Gradle default |Maven default
|
||||||
|
|
||||||
|`mode`
|
|`mode`
|
||||||
|The script mode. Defaults to `auto`.
|
|The script mode.
|
||||||
|
|`auto`
|
||||||
|
|`auto`
|
||||||
|
|
||||||
|`initInfoProvides`
|
|`initInfoProvides`
|
||||||
|The `Provides` section of "`INIT INFO`". Defaults to `spring-boot-application` for Gradle
|
|The `Provides` section of "`INIT INFO`"
|
||||||
and to `${project.artifactId}` for Maven.
|
|`${task.baseName}`
|
||||||
|
|`${project.artifactId}`
|
||||||
|
|
||||||
|`initInfoRequiredStart`
|
|`initInfoRequiredStart`
|
||||||
|The `Required-Start` section of "`INIT INFO`". Defaults to `$remote_fs $syslog $network`.
|
|`Required-Start` section of "`INIT INFO`".
|
||||||
|
|`$remote_fs $syslog $network`
|
||||||
|
|`$remote_fs $syslog $network`
|
||||||
|
|
||||||
|`initInfoRequiredStop`
|
|`initInfoRequiredStop`
|
||||||
|The `Required-Stop` section of "`INIT INFO`". Defaults to `$remote_fs $syslog $network`.
|
|`Required-Stop` section of "`INIT INFO`".
|
||||||
|
|`$remote_fs $syslog $network`
|
||||||
|
|`$remote_fs $syslog $network`
|
||||||
|
|
||||||
|`initInfoDefaultStart`
|
|`initInfoDefaultStart`
|
||||||
|The `Default-Start` section of "`INIT INFO`". Defaults to `2 3 4 5`.
|
|`Default-Start` section of "`INIT INFO`".
|
||||||
|
|`2 3 4 5`
|
||||||
|
|`2 3 4 5`
|
||||||
|
|
||||||
|`initInfoDefaultStop`
|
|`initInfoDefaultStop`
|
||||||
|The `Default-Stop` section of "`INIT INFO`". Defaults to `0 1 6`.
|
|`Default-Stop` section of "`INIT INFO`".
|
||||||
|
|`0 1 6`
|
||||||
|
|`0 1 6`
|
||||||
|
|
||||||
|`initInfoShortDescription`
|
|`initInfoShortDescription`
|
||||||
|The `Short-Description` section of "`INIT INFO`". Defaults to `Spring Boot Application`
|
|`Short-Description` section of "`INIT INFO`".
|
||||||
for Gradle and to `${project.name}` for Maven.
|
|Single-line version of `${project.description}` (falling back to `${task.baseName}`)
|
||||||
|
|`${project.name}`
|
||||||
|
|
||||||
|`initInfoDescription`
|
|`initInfoDescription`
|
||||||
|The `Description` section of "`INIT INFO`". Defaults to `Spring Boot Application` for
|
|`Description` section of "`INIT INFO`".
|
||||||
Gradle and to `${project.description}` (falling back to `${project.name}`) for Maven.
|
|`${project.description}` (falling back to `${task.baseName}`)
|
||||||
|
|`${project.description}` (falling back to `${project.name}`)
|
||||||
|
|
||||||
|`initInfoChkconfig`
|
|`initInfoChkconfig`
|
||||||
|The `chkconfig` section of "`INIT INFO`". Defaults to `2345 99 01`.
|
|`chkconfig` section of "`INIT INFO`"
|
||||||
|
|`2345 99 01`
|
||||||
|
|`2345 99 01`
|
||||||
|
|
||||||
|`confFolder`
|
|`confFolder`
|
||||||
|The default value for `CONF_FOLDER`. Defaults to the folder containing the jar.
|
|The default value for `CONF_FOLDER`
|
||||||
|
|Folder containing the jar
|
||||||
|
|Folder containing the jar
|
||||||
|
|
||||||
|`inlinedConfScript`
|
|`inlinedConfScript`
|
||||||
|Reference to a file script that should be inlined in the default launch script.
|
|Reference to a file script that should be inlined in the default launch script.
|
||||||
This can be used to set environmental variables such as `JAVA_OPTS` before any external
|
This can be used to set environmental variables such as `JAVA_OPTS` before any external
|
||||||
config files are loaded.
|
config files are loaded
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
|`logFolder`
|
|`logFolder`
|
||||||
|The default value for `LOG_FOLDER`. Only valid for an `init.d` service.
|
|Default value for `LOG_FOLDER`. Only valid for an `init.d` service
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
|`logFilename`
|
|`logFilename`
|
||||||
|The default value for `LOG_FILENAME`. Only valid for an `init.d` service.
|
|Default value for `LOG_FILENAME`. Only valid for an `init.d` service
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
|`pidFolder`
|
|`pidFolder`
|
||||||
|The default value for `PID_FOLDER`. Only valid for an `init.d` service.
|
|Default value for `PID_FOLDER`. Only valid for an `init.d` service
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
|`pidFilename`
|
|`pidFilename`
|
||||||
|The default value for the name of the PID file in `PID_FOLDER`. Only valid for an
|
|Default value for the name of the PID file in `PID_FOLDER`. Only valid for an
|
||||||
`init.d` service.
|
`init.d` service
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
||||||
|`useStartStopDaemon`
|
|`useStartStopDaemon`
|
||||||
|Whether the `start-stop-daemon` command, when it's available, should be used to control
|
|Whether the `start-stop-daemon` command, when it's available, should be used to control
|
||||||
the process. Defaults to `true`.
|
the process
|
||||||
|
|`true`
|
||||||
|
|`true`
|
||||||
|
|
||||||
|`stopWaitTime`
|
|`stopWaitTime`
|
||||||
|The default value for `STOP_WAIT_TIME`. Only valid for an `init.d` service.
|
|Default value for `STOP_WAIT_TIME` in seconds. Only valid for an `init.d` service
|
||||||
Defaults to 60 seconds.
|
|60
|
||||||
|
|60
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ public class BootJar extends Jar implements BootArchive {
|
||||||
private LaunchScriptConfiguration enableLaunchScriptIfNecessary() {
|
private LaunchScriptConfiguration enableLaunchScriptIfNecessary() {
|
||||||
LaunchScriptConfiguration launchScript = this.support.getLaunchScript();
|
LaunchScriptConfiguration launchScript = this.support.getLaunchScript();
|
||||||
if (launchScript == null) {
|
if (launchScript == null) {
|
||||||
launchScript = new LaunchScriptConfiguration();
|
launchScript = new LaunchScriptConfiguration(this);
|
||||||
this.support.setLaunchScript(launchScript);
|
this.support.setLaunchScript(launchScript);
|
||||||
}
|
}
|
||||||
return launchScript;
|
return launchScript;
|
||||||
|
|
|
@ -162,7 +162,7 @@ public class BootWar extends War implements BootArchive {
|
||||||
private LaunchScriptConfiguration enableLaunchScriptIfNecessary() {
|
private LaunchScriptConfiguration enableLaunchScriptIfNecessary() {
|
||||||
LaunchScriptConfiguration launchScript = this.support.getLaunchScript();
|
LaunchScriptConfiguration launchScript = this.support.getLaunchScript();
|
||||||
if (launchScript == null) {
|
if (launchScript == null) {
|
||||||
launchScript = new LaunchScriptConfiguration();
|
launchScript = new LaunchScriptConfiguration(this);
|
||||||
this.support.setLaunchScript(launchScript);
|
this.support.setLaunchScript(launchScript);
|
||||||
}
|
}
|
||||||
return launchScript;
|
return launchScript;
|
||||||
|
|
|
@ -22,6 +22,9 @@ import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
|
||||||
|
|
||||||
import org.springframework.boot.loader.tools.FileUtils;
|
import org.springframework.boot.loader.tools.FileUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +40,19 @@ public class LaunchScriptConfiguration implements Serializable {
|
||||||
|
|
||||||
private File script;
|
private File script;
|
||||||
|
|
||||||
|
public LaunchScriptConfiguration() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchScriptConfiguration(AbstractArchiveTask archiveTask) {
|
||||||
|
Project project = archiveTask.getProject();
|
||||||
|
putIfMissing(this.properties, "initInfoProvides", archiveTask.getBaseName());
|
||||||
|
putIfMissing(this.properties, "initInfoShortDescription",
|
||||||
|
removeLineBreaks(project.getDescription()), archiveTask.getBaseName());
|
||||||
|
putIfMissing(this.properties, "initInfoDescription",
|
||||||
|
augmentLineBreaks(project.getDescription()), archiveTask.getBaseName());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the properties that are applied to the launch script when it's being
|
* Returns the properties that are applied to the launch script when it's being
|
||||||
* including in the executable archive.
|
* including in the executable archive.
|
||||||
|
@ -121,4 +137,24 @@ public class LaunchScriptConfiguration implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String removeLineBreaks(String string) {
|
||||||
|
return (string != null ? string.replaceAll("\\s+", " ") : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String augmentLineBreaks(String string) {
|
||||||
|
return (string != null ? string.replaceAll("\n", "\n# ") : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putIfMissing(Map<String, String> properties, String key,
|
||||||
|
String... valueCandidates) {
|
||||||
|
if (!properties.containsKey(key)) {
|
||||||
|
for (String candidate : valueCandidates) {
|
||||||
|
if (candidate != null && !candidate.isEmpty()) {
|
||||||
|
properties.put(key, candidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ import java.nio.file.attribute.PosixFilePermission;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
@ -64,6 +66,8 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
|
||||||
|
|
||||||
private final String classesPath;
|
private final String classesPath;
|
||||||
|
|
||||||
|
private Project project;
|
||||||
|
|
||||||
private T task;
|
private T task;
|
||||||
|
|
||||||
protected AbstractBootArchiveTests(Class<T> taskClass, String launcherClass,
|
protected AbstractBootArchiveTests(Class<T> taskClass, String launcherClass,
|
||||||
|
@ -77,10 +81,12 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
|
||||||
@Before
|
@Before
|
||||||
public void createTask() {
|
public void createTask() {
|
||||||
try {
|
try {
|
||||||
Project project = ProjectBuilder.builder()
|
this.project = ProjectBuilder.builder().withProjectDir(this.temp.newFolder())
|
||||||
.withProjectDir(this.temp.newFolder()).build();
|
.build();
|
||||||
|
this.project
|
||||||
|
.setDescription("Test project for " + this.taskClass.getSimpleName());
|
||||||
this.task = configure(
|
this.task = configure(
|
||||||
project.getTasks().create("testArchive", this.taskClass));
|
this.project.getTasks().create("testArchive", this.taskClass));
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
|
@ -186,8 +192,12 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
|
||||||
this.task.setMainClassName("com.example.Main");
|
this.task.setMainClassName("com.example.Main");
|
||||||
this.task.launchScript();
|
this.task.launchScript();
|
||||||
this.task.execute();
|
this.task.execute();
|
||||||
|
Map<String, String> properties = new HashMap<>();
|
||||||
|
properties.put("initInfoProvides", this.task.getBaseName());
|
||||||
|
properties.put("initInfoShortDescription", this.project.getDescription());
|
||||||
|
properties.put("initInfoDescription", this.project.getDescription());
|
||||||
assertThat(Files.readAllBytes(this.task.getArchivePath().toPath()))
|
assertThat(Files.readAllBytes(this.task.getArchivePath().toPath()))
|
||||||
.startsWith(new DefaultLaunchScript(null, null).toByteArray());
|
.startsWith(new DefaultLaunchScript(null, properties).toByteArray());
|
||||||
try {
|
try {
|
||||||
Set<PosixFilePermission> permissions = Files
|
Set<PosixFilePermission> permissions = Files
|
||||||
.getPosixFilePermissions(this.task.getArchivePath().toPath());
|
.getPosixFilePermissions(this.task.getArchivePath().toPath());
|
||||||
|
@ -211,13 +221,20 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void launchScriptPropertiesAreReplaced() throws IOException {
|
public void launchScriptInitInfoPropertiesCanBeCustomized() throws IOException {
|
||||||
this.task.setMainClassName("com.example.Main");
|
this.task.setMainClassName("com.example.Main");
|
||||||
this.task.launchScript((configuration) -> configuration.getProperties()
|
this.task.launchScript((configuration) -> {
|
||||||
.put("initInfoProvides", "test property value"));
|
configuration.getProperties().put("initInfoProvides", "provides");
|
||||||
|
configuration.getProperties().put("initInfoShortDescription",
|
||||||
|
"short description");
|
||||||
|
configuration.getProperties().put("initInfoDescription", "description");
|
||||||
|
});
|
||||||
this.task.execute();
|
this.task.execute();
|
||||||
assertThat(Files.readAllBytes(this.task.getArchivePath().toPath()))
|
byte[] bytes = Files.readAllBytes(this.task.getArchivePath().toPath());
|
||||||
.containsSequence("test property value".getBytes());
|
assertThat(bytes).containsSequence("Provides: provides".getBytes());
|
||||||
|
assertThat(bytes)
|
||||||
|
.containsSequence("Short-Description: short description".getBytes());
|
||||||
|
assertThat(bytes).containsSequence("Description: description".getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2018 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.tasks.bundling;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link LaunchScriptConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class LaunchScriptConfigurationTests {
|
||||||
|
|
||||||
|
private final AbstractArchiveTask task = mock(AbstractArchiveTask.class);
|
||||||
|
|
||||||
|
private final Project project = mock(Project.class);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
given(this.task.getProject()).willReturn(this.project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoProvidesUsesArchiveBaseNameByDefault() {
|
||||||
|
given(this.task.getBaseName()).willReturn("base-name");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoProvides", "base-name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoShortDescriptionUsesDescriptionByDefault() {
|
||||||
|
given(this.project.getDescription()).willReturn("Project description");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoShortDescription", "Project description");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoShortDescriptionUsesArchiveBaseNameWhenDescriptionIsNull() {
|
||||||
|
given(this.task.getBaseName()).willReturn("base-name");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoShortDescription", "base-name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoShortDescriptionUsesSingleLineVersionOfMultiLineProjectDescription() {
|
||||||
|
given(this.project.getDescription()).willReturn("Project\ndescription");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoShortDescription", "Project description");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoDescriptionUsesArchiveBaseNameWhenDescriptionIsNull() {
|
||||||
|
given(this.task.getBaseName()).willReturn("base-name");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoDescription", "base-name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoDescriptionUsesProjectDescriptionByDefault() {
|
||||||
|
given(this.project.getDescription()).willReturn("Project description");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoDescription", "Project description");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initInfoDescriptionUsesCorrectlyFormattedMultiLineProjectDescription() {
|
||||||
|
given(this.project.getDescription()).willReturn("The\nproject\ndescription");
|
||||||
|
assertThat(new LaunchScriptConfiguration(this.task).getProperties())
|
||||||
|
.containsEntry("initInfoDescription", "The\n# project\n# description");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue