Polish "Make dev tools' home directory configurable"

See gh-17924
pull/27409/head
Andy Wilkinson 3 years ago
parent b9dbfad473
commit 8e7a6ceb44

@ -23,8 +23,11 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.devtools.system.DevToolsEnablementDeducer;
@ -59,6 +62,10 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
private static final Set<PropertySourceLoader> PROPERTY_SOURCE_LOADERS;
private final Properties systemProperties;
private final Map<String, String> environmentVariables;
static {
Set<PropertySourceLoader> propertySourceLoaders = new HashSet<>();
propertySourceLoaders.add(new PropertiesPropertySourceLoader());
@ -68,6 +75,15 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
PROPERTY_SOURCE_LOADERS = Collections.unmodifiableSet(propertySourceLoaders);
}
public DevToolsHomePropertiesPostProcessor() {
this(System.getenv(), System.getProperties());
}
DevToolsHomePropertiesPostProcessor(Map<String, String> environmentVariables, Properties systemProperties) {
this.environmentVariables = environmentVariables;
this.systemProperties = systemProperties;
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
if (DevToolsEnablementDeducer.shouldEnable(Thread.currentThread())) {
@ -93,7 +109,7 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
private void addPropertySource(List<PropertySource<?>> propertySources, String fileName,
Function<File, String> propertySourceNamer) {
File home = getProjectRootFolder();
File home = getHomeDirectory();
File file = (home != null) ? new File(home, fileName) : null;
FileSystemResource resource = (file != null) ? new FileSystemResource(file) : null;
if (resource != null && resource.exists() && resource.isFile()) {
@ -121,21 +137,19 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
.anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension));
}
protected File getProjectRootFolder() {
String rootFolder = System.getenv("PROJECT_ROOT_FOLDER");
if (rootFolder == null) {
rootFolder = System.getProperty("PROJECT_ROOT_FOLDER");
}
if (StringUtils.hasLength(rootFolder)) {
return new File(rootFolder);
}
return getHomeDirectory();
protected File getHomeDirectory() {
return getHomeDirectory(() -> this.environmentVariables.get("SPRING_DEVTOOLS_HOME"),
() -> this.systemProperties.getProperty("spring.devtools.home"),
() -> this.systemProperties.getProperty("user.home"));
}
protected File getHomeDirectory() {
String home = System.getProperty("user.home");
if (StringUtils.hasLength(home)) {
return new File(home);
@SafeVarargs
private final File getHomeDirectory(Supplier<String>... pathSuppliers) {
for (Supplier<String> pathSupplier : pathSuppliers) {
String path = pathSupplier.get();
if (StringUtils.hasText(path)) {
return new File(path);
}
}
return null;
}

@ -21,6 +21,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import org.junit.jupiter.api.BeforeEach;
@ -47,12 +49,12 @@ class DevToolsHomePropertiesPostProcessorTests {
private File home;
private File rootDir;
private File customHome;
@BeforeEach
void setup(@TempDir File tempDir, @TempDir File rootDir) {
this.home = tempDir;
this.rootDir = rootDir;
void setup(@TempDir File tempDir) {
this.home = new File(tempDir, "default-home");
this.customHome = new File(tempDir, "custom-home");
this.configDir = this.home + "/.config/spring-boot/";
new File(this.configDir).mkdirs();
}
@ -67,17 +69,25 @@ class DevToolsHomePropertiesPostProcessorTests {
}
@Test
void loadsRootFolderProperties() throws Exception {
System.setProperty("PROJECT_ROOT_FOLDER", this.rootDir.getAbsolutePath());
void loadsPropertiesFromCustomHomeDirectorySetUsingSystemProperty() throws Exception {
Properties properties = new Properties();
properties.put("uvw", "xyz");
OutputStream out = new FileOutputStream(
new File(this.rootDir, ".config/spring-boot/spring-boot-devtools.properties"));
properties.store(out, null);
out.close();
ConfigurableEnvironment environment = new MockEnvironment();
MockDevToolHomePropertiesPostProcessor postProcessor = new MockDevToolHomePropertiesPostProcessor();
runPostProcessor(() -> postProcessor.postProcessEnvironment(environment, null));
writeFile(properties, this.customHome, ".config/spring-boot/spring-boot-devtools.properties");
Properties systemProperties = new Properties();
systemProperties.setProperty("spring.devtools.home", this.customHome.getAbsolutePath());
ConfigurableEnvironment environment = getPostProcessedEnvironment(systemProperties);
assertThat(environment.getProperty("uvw")).isEqualTo("xyz");
}
@Test
void loadsPropertiesFromCustomHomeDirectorySetUsingEnvironmentVariable() throws Exception {
Properties properties = new Properties();
properties.put("uvw", "xyz");
writeFile(properties, this.customHome, ".config/spring-boot/spring-boot-devtools.properties");
Properties systemProperties = new Properties();
systemProperties.setProperty("spring.devtools.home", this.customHome.getAbsolutePath());
ConfigurableEnvironment environment = getPostProcessedEnvironment(
Collections.singletonMap("SPRING_DEVTOOLS_HOME", this.customHome.getAbsolutePath()));
assertThat(environment.getProperty("uvw")).isEqualTo("xyz");
}
@ -169,15 +179,39 @@ class DevToolsHomePropertiesPostProcessorTests {
assertThat(environment.getProperty("abc")).isNull();
}
private void writeFile(Properties properties, String s) throws IOException {
OutputStream out = new FileOutputStream(new File(this.home, s));
private void writeFile(Properties properties, String path) throws IOException {
writeFile(properties, this.home, path);
}
private void writeFile(Properties properties, File home, String path) throws IOException {
File file = new File(home, path);
file.getParentFile().mkdirs();
try (OutputStream out = new FileOutputStream(file)) {
properties.store(out, null);
out.close();
}
}
private ConfigurableEnvironment getPostProcessedEnvironment() throws Exception {
return getPostProcessedEnvironment(null, null);
}
private ConfigurableEnvironment getPostProcessedEnvironment(Properties systemProperties) throws Exception {
return getPostProcessedEnvironment(null, systemProperties);
}
private ConfigurableEnvironment getPostProcessedEnvironment(Map<String, String> env) throws Exception {
return getPostProcessedEnvironment(env, null);
}
private ConfigurableEnvironment getPostProcessedEnvironment(Map<String, String> env, Properties systemProperties)
throws Exception {
if (systemProperties == null) {
systemProperties = new Properties();
systemProperties.setProperty("user.home", this.home.getAbsolutePath());
}
ConfigurableEnvironment environment = new MockEnvironment();
MockDevToolHomePropertiesPostProcessor postProcessor = new MockDevToolHomePropertiesPostProcessor();
DevToolsHomePropertiesPostProcessor postProcessor = new DevToolsHomePropertiesPostProcessor(
(env != null) ? env : Collections.emptyMap(), systemProperties);
runPostProcessor(() -> postProcessor.postProcessEnvironment(environment, null));
return environment;
}
@ -188,13 +222,4 @@ class DevToolsHomePropertiesPostProcessorTests {
thread.join();
}
private class MockDevToolHomePropertiesPostProcessor extends DevToolsHomePropertiesPostProcessor {
@Override
protected File getHomeDirectory() {
return DevToolsHomePropertiesPostProcessorTests.this.home;
}
}
}

@ -285,6 +285,9 @@ For example, to configure restart to always use a <<using#using.devtools.restart
trigger-file: ".reloadtrigger"
----
By default, `$HOME` is the user's home directory.
To customize this location, set the `SPRING_DEVTOOLS_HOME` environment variable or the `spring.devtools.home` system property.
NOTE: If devtools configuration files are not found in `$HOME/.config/spring-boot`, the root of the `$HOME` directory is searched for the presence of a `.spring-boot-devtools.properties` file.
This allows you to share the devtools global configuration with applications that are on an older version of Spring Boot that does not support the `$HOME/.config/spring-boot` location.

Loading…
Cancel
Save