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

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