Support inlining a conf script into the default launch script
See gh-9590
This commit is contained in:
parent
c79b76847b
commit
5ee28a08e1
|
@ -760,6 +760,11 @@ for Gradle and to `${project.name}` for Maven.
|
||||||
|`confFolder`
|
|`confFolder`
|
||||||
|The default value for `CONF_FOLDER`. Defaults to the folder containing the jar.
|
|The default value for `CONF_FOLDER`. Defaults to the folder containing the jar.
|
||||||
|
|
||||||
|
|`inlinedConfScript`
|
||||||
|
|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 config files are loaded.
|
||||||
|
|
||||||
|`logFolder`
|
|`logFolder`
|
||||||
|The default value for `LOG_FOLDER`. Only valid for an `init.d` service.
|
|The default value for `LOG_FOLDER`. Only valid for an `init.d` service.
|
||||||
|
|
||||||
|
|
|
@ -16,34 +16,35 @@
|
||||||
|
|
||||||
package org.springframework.boot.loader.tools;
|
package org.springframework.boot.loader.tools;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of {@link LaunchScript}. Provides the default Spring Boot launch
|
* Default implementation of {@link LaunchScript}. Provides the default Spring Boot launch
|
||||||
* script or can load a specific script File. Also support mustache style template
|
* script or can load a specific script File. Also support mustache style template
|
||||||
* expansion of the form <code>{{name:default}}</code>.
|
* expansion of the form <code>{{name:default}}</code>.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Justin Rosenberg
|
||||||
* @since 1.3.0
|
* @since 1.3.0
|
||||||
*/
|
*/
|
||||||
public class DefaultLaunchScript implements LaunchScript {
|
public class DefaultLaunchScript implements LaunchScript {
|
||||||
|
|
||||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 4096;
|
|
||||||
|
|
||||||
private static final Pattern PLACEHOLDER_PATTERN = Pattern
|
private static final Pattern PLACEHOLDER_PATTERN = Pattern
|
||||||
.compile("\\{\\{(\\w+)(:.*?)?\\}\\}(?!\\})");
|
.compile("\\{\\{(\\w+)(:.*?)?\\}\\}(?!\\})");
|
||||||
|
|
||||||
|
private static final List<String> FILE_PATH_KEYS = Arrays.asList("inlinedConfScript");
|
||||||
|
|
||||||
private final String content;
|
private final String content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,45 +58,52 @@ public class DefaultLaunchScript implements LaunchScript {
|
||||||
this.content = expandPlaceholders(content, properties);
|
this.content = expandPlaceholders(content, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads file contents.
|
||||||
|
* @param file File to load. If null, will load default launch.script
|
||||||
|
* @return String representation of file contents.
|
||||||
|
* @throws IOException if file is not found our can't be loaded.
|
||||||
|
*/
|
||||||
private String loadContent(File file) throws IOException {
|
private String loadContent(File file) throws IOException {
|
||||||
|
final byte[] fileBytes;
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return loadContent(getClass().getResourceAsStream("launch.script"));
|
fileBytes = FileCopyUtils
|
||||||
|
.copyToByteArray(getClass().getResourceAsStream("launch.script"));
|
||||||
}
|
}
|
||||||
return loadContent(new FileInputStream(file));
|
else {
|
||||||
|
fileBytes = FileCopyUtils.copyToByteArray(file);
|
||||||
|
}
|
||||||
|
return new String(fileBytes, UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String loadContent(InputStream inputStream) throws IOException {
|
/**
|
||||||
try {
|
* Replaces variable placeholders in file with specified property values.
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
* @param content String with variables defined in {{variable:default}} format.
|
||||||
copy(inputStream, outputStream);
|
* @param properties Key value pairs for variables to replace
|
||||||
return new String(outputStream.toByteArray(), UTF_8);
|
* @return Updated String
|
||||||
}
|
* @throws IOException if a file property value or path is specified and the file
|
||||||
finally {
|
* cannot be loaded.
|
||||||
inputStream.close();
|
*/
|
||||||
}
|
private String expandPlaceholders(String content, Map<?, ?> properties)
|
||||||
}
|
|
||||||
|
|
||||||
private void copy(InputStream inputStream, OutputStream outputStream)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int bytesRead = -1;
|
|
||||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
||||||
outputStream.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
outputStream.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String expandPlaceholders(String content, Map<?, ?> properties) {
|
|
||||||
StringBuffer expanded = new StringBuffer();
|
StringBuffer expanded = new StringBuffer();
|
||||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(content);
|
Matcher matcher = PLACEHOLDER_PATTERN.matcher(content);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String name = matcher.group(1);
|
String name = matcher.group(1);
|
||||||
String value = matcher.group(2);
|
final String value;
|
||||||
|
String defaultValue = matcher.group(2);
|
||||||
if (properties != null && properties.containsKey(name)) {
|
if (properties != null && properties.containsKey(name)) {
|
||||||
value = (String) properties.get(name);
|
Object propertyValue = properties.get(name);
|
||||||
|
if (FILE_PATH_KEYS.contains(name)) {
|
||||||
|
value = parseFilePropertyValue(properties.get(name));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value = (value == null ? matcher.group(0) : value.substring(1));
|
value = propertyValue.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = (defaultValue == null ? matcher.group(0)
|
||||||
|
: defaultValue.substring(1));
|
||||||
}
|
}
|
||||||
matcher.appendReplacement(expanded, value.replace("$", "\\$"));
|
matcher.appendReplacement(expanded, value.replace("$", "\\$"));
|
||||||
}
|
}
|
||||||
|
@ -103,6 +111,26 @@ public class DefaultLaunchScript implements LaunchScript {
|
||||||
return expanded.toString();
|
return expanded.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads file based on File object or String path.
|
||||||
|
* @param propertyValue File Object or String path to file.
|
||||||
|
* @return File contents.
|
||||||
|
* @throws IOException if a file property value or path is specified and the file
|
||||||
|
* cannot be loaded.
|
||||||
|
*/
|
||||||
|
private String parseFilePropertyValue(Object propertyValue) throws IOException {
|
||||||
|
if (propertyValue instanceof File) {
|
||||||
|
return loadContent((File) propertyValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return loadContent(new File(propertyValue.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content of the launch script as a byte array.
|
||||||
|
* @return Byte representation of script.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public byte[] toByteArray() {
|
public byte[] toByteArray() {
|
||||||
return this.content.getBytes(UTF_8);
|
return this.content.getBytes(UTF_8);
|
||||||
|
|
3
spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script
Executable file → Normal file
3
spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script
Executable file → Normal file
|
@ -46,6 +46,9 @@ done
|
||||||
jarfolder="$( (cd "$(dirname "$jarfile")" && pwd -P) )"
|
jarfolder="$( (cd "$(dirname "$jarfile")" && pwd -P) )"
|
||||||
cd "$WORKING_DIR" || exit 1
|
cd "$WORKING_DIR" || exit 1
|
||||||
|
|
||||||
|
# Inline script specified in build properties
|
||||||
|
{{inlinedConfScript:}}
|
||||||
|
|
||||||
# Source any config file
|
# Source any config file
|
||||||
configfile="$(basename "${jarfile%.*}.conf")"
|
configfile="$(basename "${jarfile%.*}.conf")"
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.boot.loader.tools;
|
package org.springframework.boot.loader.tools;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -126,6 +127,14 @@ public class DefaultLaunchScriptTests {
|
||||||
assertThatPlaceholderCanBeReplaced("stopWaitTime");
|
assertThatPlaceholderCanBeReplaced("stopWaitTime");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void inlinedConfScriptFileLoad() throws IOException {
|
||||||
|
DefaultLaunchScript script = new DefaultLaunchScript(null,
|
||||||
|
createProperties("inlinedConfScript:src/test/resources/example.script"));
|
||||||
|
String content = new String(script.toByteArray());
|
||||||
|
assertThat(content).contains("FOO=BAR");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void defaultForUseStartStopDaemonIsTrue() throws Exception {
|
public void defaultForUseStartStopDaemonIsTrue() throws Exception {
|
||||||
DefaultLaunchScript script = new DefaultLaunchScript(null, null);
|
DefaultLaunchScript script = new DefaultLaunchScript(null, null);
|
||||||
|
@ -185,6 +194,15 @@ public class DefaultLaunchScriptTests {
|
||||||
assertThat(content).isEqualTo("hello");
|
assertThat(content).isEqualTo("hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expandVariablesCanDefaultToBlank() throws Exception {
|
||||||
|
File file = this.temporaryFolder.newFile();
|
||||||
|
FileCopyUtils.copy("s{{p:}}{{r:}}ing".getBytes(), file);
|
||||||
|
DefaultLaunchScript script = new DefaultLaunchScript(file, null);
|
||||||
|
String content = new String(script.toByteArray());
|
||||||
|
assertThat(content).isEqualTo("sing");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void expandVariablesWithDefaultsOverride() throws Exception {
|
public void expandVariablesWithDefaultsOverride() throws Exception {
|
||||||
File file = this.temporaryFolder.newFile();
|
File file = this.temporaryFolder.newFile();
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
FOO=BAR
|
Loading…
Reference in New Issue