Commit ad1248e4 authored by Phillip Webb's avatar Phillip Webb

Replace "folder" with "directory"

Consistently use the term "directory" instead of "folder"

Closes gh-21218
parent ec871d67
...@@ -96,7 +96,7 @@ public class GroovyTemplateAutoConfiguration { ...@@ -96,7 +96,7 @@ public class GroovyTemplateAutoConfiguration {
* MarkupTemplateEngine could be loaded from groovy-templates or groovy-all. * MarkupTemplateEngine could be loaded from groovy-templates or groovy-all.
* Unfortunately it's quite common for people to use groovy-all and not actually * Unfortunately it's quite common for people to use groovy-all and not actually
* need templating support. This method attempts to check the source jar so that * need templating support. This method attempts to check the source jar so that
* we can skip the {@code /template} folder check for such cases. * we can skip the {@code /template} directory check for such cases.
* @return true if the groovy-all jar is used * @return true if the groovy-all jar is used
*/ */
private boolean isUsingGroovyAllJar() { private boolean isUsingGroovyAllJar() {
......
...@@ -245,13 +245,13 @@ class ArtemisAutoConfigurationTests { ...@@ -245,13 +245,13 @@ class ArtemisAutoConfigurationTests {
@Test @Test
void embeddedWithPersistentMode(@TempDir Path temp) throws IOException { void embeddedWithPersistentMode(@TempDir Path temp) throws IOException {
File dataFolder = Files.createTempDirectory(temp, null).toFile(); File dataDirectory = Files.createTempDirectory(temp, null).toFile();
final String messageId = UUID.randomUUID().toString(); final String messageId = UUID.randomUUID().toString();
// Start the server and post a message to some queue // Start the server and post a message to some queue
this.contextRunner.withUserConfiguration(EmptyConfiguration.class) this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.embedded.queues=TestQueue", .withPropertyValues("spring.artemis.embedded.queues=TestQueue",
"spring.artemis.embedded.persistent:true", "spring.artemis.embedded.persistent:true",
"spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath()) "spring.artemis.embedded.dataDirectory:" + dataDirectory.getAbsolutePath())
.run((context) -> context.getBean(JmsTemplate.class).send("TestQueue", .run((context) -> context.getBean(JmsTemplate.class).send("TestQueue",
(session) -> session.createTextMessage(messageId))) (session) -> session.createTextMessage(messageId)))
.run((context) -> { .run((context) -> {
......
...@@ -147,13 +147,13 @@ class ServletWebServerFactoryCustomizerTests { ...@@ -147,13 +147,13 @@ class ServletWebServerFactoryCustomizerTests {
@Test @Test
void sessionStoreDir() { void sessionStoreDir() {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
map.put("server.servlet.session.store-dir", "myfolder"); map.put("server.servlet.session.store-dir", "mydirectory");
bindProperties(map); bindProperties(map);
ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class); ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);
this.customizer.customize(factory); this.customizer.customize(factory);
ArgumentCaptor<Session> sessionCaptor = ArgumentCaptor.forClass(Session.class); ArgumentCaptor<Session> sessionCaptor = ArgumentCaptor.forClass(Session.class);
verify(factory).setSession(sessionCaptor.capture()); verify(factory).setSession(sessionCaptor.capture());
assertThat(sessionCaptor.getValue().getStoreDir()).isEqualTo(new File("myfolder")); assertThat(sessionCaptor.getValue().getStoreDir()).isEqualTo(new File("mydirectory"));
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -66,23 +66,23 @@ class ResourceMatcher { ...@@ -66,23 +66,23 @@ class ResourceMatcher {
matchedResources.add(new MatchedResource(root)); matchedResources.add(new MatchedResource(root));
} }
else { else {
matchedResources.addAll(findInFolder(root)); matchedResources.addAll(findInDirectory(root));
} }
} }
return matchedResources; return matchedResources;
} }
private List<MatchedResource> findInFolder(File folder) throws IOException { private List<MatchedResource> findInDirectory(File directory) throws IOException {
List<MatchedResource> matchedResources = new ArrayList<>(); List<MatchedResource> matchedResources = new ArrayList<>();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
new FolderResourceLoader(folder)); new DirectoryResourceLoader(directory));
for (String include : this.includes) { for (String include : this.includes) {
for (Resource candidate : resolver.getResources(include)) { for (Resource candidate : resolver.getResources(include)) {
File file = candidate.getFile(); File file = candidate.getFile();
if (file.isFile()) { if (file.isFile()) {
MatchedResource matchedResource = new MatchedResource(folder, file); MatchedResource matchedResource = new MatchedResource(directory, file);
if (!isExcluded(matchedResource)) { if (!isExcluded(matchedResource)) {
matchedResources.add(matchedResource); matchedResources.add(matchedResource);
} }
...@@ -130,31 +130,31 @@ class ResourceMatcher { ...@@ -130,31 +130,31 @@ class ResourceMatcher {
} }
/** /**
* {@link ResourceLoader} to get load resource from a folder. * {@link ResourceLoader} to get load resource from a directory.
*/ */
private static class FolderResourceLoader extends DefaultResourceLoader { private static class DirectoryResourceLoader extends DefaultResourceLoader {
private final File rootFolder; private final File rootDirectory;
FolderResourceLoader(File root) throws MalformedURLException { DirectoryResourceLoader(File root) throws MalformedURLException {
super(new FolderClassLoader(root)); super(new DirectoryClassLoader(root));
this.rootFolder = root; this.rootDirectory = root;
} }
@Override @Override
protected Resource getResourceByPath(String path) { protected Resource getResourceByPath(String path) {
return new FileSystemResource(new File(this.rootFolder, path)); return new FileSystemResource(new File(this.rootDirectory, path));
} }
} }
/** /**
* {@link ClassLoader} backed by a folder. * {@link ClassLoader} backed by a directory.
*/ */
private static class FolderClassLoader extends URLClassLoader { private static class DirectoryClassLoader extends URLClassLoader {
FolderClassLoader(File rootFolder) throws MalformedURLException { DirectoryClassLoader(File rootDirectory) throws MalformedURLException {
super(new URL[] { rootFolder.toURI().toURL() }); super(new URL[] { rootDirectory.toURI().toURL() });
} }
@Override @Override
...@@ -186,9 +186,10 @@ class ResourceMatcher { ...@@ -186,9 +186,10 @@ class ResourceMatcher {
this.root = this.name.endsWith(".jar"); this.root = this.name.endsWith(".jar");
} }
private MatchedResource(File rootFolder, File file) { private MatchedResource(File rootDirectory, File file) {
this.name = StringUtils String filePath = file.getAbsolutePath();
.cleanPath(file.getAbsolutePath().substring(rootFolder.getAbsolutePath().length() + 1)); String rootDirectoryPath = rootDirectory.getAbsolutePath();
this.name = StringUtils.cleanPath(filePath.substring(rootDirectoryPath.length() + 1));
this.file = file; this.file = file;
this.root = false; this.root = false;
} }
......
...@@ -90,23 +90,24 @@ class ProjectGenerator { ...@@ -90,23 +90,24 @@ class ProjectGenerator {
} }
private void extractProject(ProjectGenerationResponse entity, String output, boolean overwrite) throws IOException { private void extractProject(ProjectGenerationResponse entity, String output, boolean overwrite) throws IOException {
File outputFolder = (output != null) ? new File(output) : new File(System.getProperty("user.dir")); File outputDirectory = (output != null) ? new File(output) : new File(System.getProperty("user.dir"));
if (!outputFolder.exists()) { if (!outputDirectory.exists()) {
outputFolder.mkdirs(); outputDirectory.mkdirs();
} }
try (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(entity.getContent()))) { try (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(entity.getContent()))) {
extractFromStream(zipStream, overwrite, outputFolder); extractFromStream(zipStream, overwrite, outputDirectory);
fixExecutableFlag(outputFolder, "mvnw"); fixExecutableFlag(outputDirectory, "mvnw");
fixExecutableFlag(outputFolder, "gradlew"); fixExecutableFlag(outputDirectory, "gradlew");
Log.info("Project extracted to '" + outputFolder.getAbsolutePath() + "'"); Log.info("Project extracted to '" + outputDirectory.getAbsolutePath() + "'");
} }
} }
private void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputFolder) throws IOException { private void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputDirectory)
throws IOException {
ZipEntry entry = zipStream.getNextEntry(); ZipEntry entry = zipStream.getNextEntry();
String canonicalOutputPath = outputFolder.getCanonicalPath() + File.separator; String canonicalOutputPath = outputDirectory.getCanonicalPath() + File.separator;
while (entry != null) { while (entry != null) {
File file = new File(outputFolder, entry.getName()); File file = new File(outputDirectory, entry.getName());
String canonicalEntryPath = file.getCanonicalPath(); String canonicalEntryPath = file.getCanonicalPath();
if (!canonicalEntryPath.startsWith(canonicalOutputPath)) { if (!canonicalEntryPath.startsWith(canonicalOutputPath)) {
throw new ReportableException("Entry '" + entry.getName() + "' would be written to '" throw new ReportableException("Entry '" + entry.getName() + "' would be written to '"
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -19,7 +19,7 @@ package org.springframework.boot.devtools.autoconfigure; ...@@ -19,7 +19,7 @@ package org.springframework.boot.devtools.autoconfigure;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.springframework.boot.devtools.classpath.ClassPathFolders; import org.springframework.boot.devtools.classpath.ClassPathDirectories;
import org.springframework.boot.devtools.filewatch.ChangedFiles; import org.springframework.boot.devtools.filewatch.ChangedFiles;
import org.springframework.boot.devtools.filewatch.FileChangeListener; import org.springframework.boot.devtools.filewatch.FileChangeListener;
import org.springframework.boot.devtools.filewatch.FileSystemWatcher; import org.springframework.boot.devtools.filewatch.FileSystemWatcher;
...@@ -44,7 +44,7 @@ class FileWatchingFailureHandler implements FailureHandler { ...@@ -44,7 +44,7 @@ class FileWatchingFailureHandler implements FailureHandler {
public Outcome handle(Throwable failure) { public Outcome handle(Throwable failure) {
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
FileSystemWatcher watcher = this.fileSystemWatcherFactory.getFileSystemWatcher(); FileSystemWatcher watcher = this.fileSystemWatcherFactory.getFileSystemWatcher();
watcher.addSourceFolders(new ClassPathFolders(Restarter.getInstance().getInitialUrls())); watcher.addSourceDirectories(new ClassPathDirectories(Restarter.getInstance().getInitialUrls()));
watcher.addListener(new Listener(latch)); watcher.addListener(new Listener(latch));
watcher.start(); watcher.start();
try { try {
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -148,7 +148,7 @@ public class LocalDevToolsAutoConfiguration { ...@@ -148,7 +148,7 @@ public class LocalDevToolsAutoConfiguration {
} }
List<File> additionalPaths = restartProperties.getAdditionalPaths(); List<File> additionalPaths = restartProperties.getAdditionalPaths();
for (File path : additionalPaths) { for (File path : additionalPaths) {
watcher.addSourceFolder(path.getAbsoluteFile()); watcher.addSourceDirectory(path.getAbsoluteFile());
} }
return watcher; return watcher;
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -40,10 +40,10 @@ import org.springframework.boot.devtools.remote.server.HandlerMapper; ...@@ -40,10 +40,10 @@ import org.springframework.boot.devtools.remote.server.HandlerMapper;
import org.springframework.boot.devtools.remote.server.HttpHeaderAccessManager; import org.springframework.boot.devtools.remote.server.HttpHeaderAccessManager;
import org.springframework.boot.devtools.remote.server.HttpStatusHandler; import org.springframework.boot.devtools.remote.server.HttpStatusHandler;
import org.springframework.boot.devtools.remote.server.UrlHandlerMapper; import org.springframework.boot.devtools.remote.server.UrlHandlerMapper;
import org.springframework.boot.devtools.restart.server.DefaultSourceFolderUrlFilter; import org.springframework.boot.devtools.restart.server.DefaultSourceDirectoryUrlFilter;
import org.springframework.boot.devtools.restart.server.HttpRestartServer; import org.springframework.boot.devtools.restart.server.HttpRestartServer;
import org.springframework.boot.devtools.restart.server.HttpRestartServerHandler; import org.springframework.boot.devtools.restart.server.HttpRestartServerHandler;
import org.springframework.boot.devtools.restart.server.SourceFolderUrlFilter; import org.springframework.boot.devtools.restart.server.SourceDirectoryUrlFilter;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -109,14 +109,14 @@ public class RemoteDevToolsAutoConfiguration { ...@@ -109,14 +109,14 @@ public class RemoteDevToolsAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
SourceFolderUrlFilter remoteRestartSourceFolderUrlFilter() { SourceDirectoryUrlFilter remoteRestartSourceDirectoryUrlFilter() {
return new DefaultSourceFolderUrlFilter(); return new DefaultSourceDirectoryUrlFilter();
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
HttpRestartServer remoteRestartHttpRestartServer(SourceFolderUrlFilter sourceFolderUrlFilter) { HttpRestartServer remoteRestartHttpRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {
return new HttpRestartServer(sourceFolderUrlFilter); return new HttpRestartServer(sourceDirectoryUrlFilter);
} }
@Bean @Bean
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -30,18 +30,18 @@ import org.springframework.core.log.LogMessage; ...@@ -30,18 +30,18 @@ import org.springframework.core.log.LogMessage;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
/** /**
* Provides access to entries on the classpath that refer to folders. * Provides access to entries on the classpath that refer to directories.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 1.3.0 * @since 2.3.0
*/ */
public class ClassPathFolders implements Iterable<File> { public class ClassPathDirectories implements Iterable<File> {
private static final Log logger = LogFactory.getLog(ClassPathFolders.class); private static final Log logger = LogFactory.getLog(ClassPathDirectories.class);
private final List<File> folders = new ArrayList<>(); private final List<File> directories = new ArrayList<>();
public ClassPathFolders(URL[] urls) { public ClassPathDirectories(URL[] urls) {
if (urls != null) { if (urls != null) {
addUrls(urls); addUrls(urls);
} }
...@@ -56,7 +56,7 @@ public class ClassPathFolders implements Iterable<File> { ...@@ -56,7 +56,7 @@ public class ClassPathFolders implements Iterable<File> {
private void addUrl(URL url) { private void addUrl(URL url) {
if (url.getProtocol().equals("file") && url.getPath().endsWith("/")) { if (url.getProtocol().equals("file") && url.getPath().endsWith("/")) {
try { try {
this.folders.add(ResourceUtils.getFile(url)); this.directories.add(ResourceUtils.getFile(url));
} }
catch (Exception ex) { catch (Exception ex) {
logger.warn(LogMessage.format("Unable to get classpath URL %s", url)); logger.warn(LogMessage.format("Unable to get classpath URL %s", url));
...@@ -67,7 +67,7 @@ public class ClassPathFolders implements Iterable<File> { ...@@ -67,7 +67,7 @@ public class ClassPathFolders implements Iterable<File> {
@Override @Override
public Iterator<File> iterator() { public Iterator<File> iterator() {
return Collections.unmodifiableList(this.folders).iterator(); return Collections.unmodifiableList(this.directories).iterator();
} }
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -28,7 +28,7 @@ import org.springframework.context.ApplicationContextAware; ...@@ -28,7 +28,7 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Encapsulates a {@link FileSystemWatcher} to watch the local classpath folders for * Encapsulates a {@link FileSystemWatcher} to watch the local classpath directories for
* changes. * changes.
* *
* @author Phillip Webb * @author Phillip Webb
...@@ -58,7 +58,7 @@ public class ClassPathFileSystemWatcher implements InitializingBean, DisposableB ...@@ -58,7 +58,7 @@ public class ClassPathFileSystemWatcher implements InitializingBean, DisposableB
Assert.notNull(urls, "Urls must not be null"); Assert.notNull(urls, "Urls must not be null");
this.fileSystemWatcher = fileSystemWatcherFactory.getFileSystemWatcher(); this.fileSystemWatcher = fileSystemWatcherFactory.getFileSystemWatcher();
this.restartStrategy = restartStrategy; this.restartStrategy = restartStrategy;
this.fileSystemWatcher.addSourceFolders(new ClassPathFolders(urls)); this.fileSystemWatcher.addSourceDirectories(new ClassPathDirectories(urls));
} }
/** /**
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -40,7 +40,7 @@ import org.springframework.util.StringUtils; ...@@ -40,7 +40,7 @@ import org.springframework.util.StringUtils;
/** /**
* {@link EnvironmentPostProcessor} to add devtools properties from the user's home * {@link EnvironmentPostProcessor} to add devtools properties from the user's home
* folder. * directory.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
...@@ -93,7 +93,7 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce ...@@ -93,7 +93,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 = getHomeFolder(); 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,7 +121,7 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce ...@@ -121,7 +121,7 @@ public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProce
.anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension)); .anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension));
} }
protected File getHomeFolder() { protected File getHomeDirectory() {
String home = System.getProperty("user.home"); String home = System.getProperty("user.home");
if (StringUtils.hasLength(home)) { if (StringUtils.hasLength(home)) {
return new File(home); return new File(home);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -30,7 +30,7 @@ import org.springframework.util.StringUtils; ...@@ -30,7 +30,7 @@ import org.springframework.util.StringUtils;
*/ */
public final class ChangedFile { public final class ChangedFile {
private final File sourceFolder; private final File sourceDirectory;
private final File file; private final File file;
...@@ -38,15 +38,15 @@ public final class ChangedFile { ...@@ -38,15 +38,15 @@ public final class ChangedFile {
/** /**
* Create a new {@link ChangedFile} instance. * Create a new {@link ChangedFile} instance.
* @param sourceFolder the source folder * @param sourceDirectory the source directory
* @param file the file * @param file the file
* @param type the type of change * @param type the type of change
*/ */
public ChangedFile(File sourceFolder, File file, Type type) { public ChangedFile(File sourceDirectory, File file, Type type) {
Assert.notNull(sourceFolder, "SourceFolder must not be null"); Assert.notNull(sourceDirectory, "SourceDirectory must not be null");
Assert.notNull(file, "File must not be null"); Assert.notNull(file, "File must not be null");
Assert.notNull(type, "Type must not be null"); Assert.notNull(type, "Type must not be null");
this.sourceFolder = sourceFolder; this.sourceDirectory = sourceDirectory;
this.file = file; this.file = file;
this.type = type; this.type = type;
} }
...@@ -68,17 +68,17 @@ public final class ChangedFile { ...@@ -68,17 +68,17 @@ public final class ChangedFile {
} }
/** /**
* Return the name of the file relative to the source folder. * Return the name of the file relative to the source directory.
* @return the relative name * @return the relative name
*/ */
public String getRelativeName() { public String getRelativeName() {
File folder = this.sourceFolder.getAbsoluteFile(); File directory = this.sourceDirectory.getAbsoluteFile();
File file = this.file.getAbsoluteFile(); File file = this.file.getAbsoluteFile();
String folderName = StringUtils.cleanPath(folder.getPath()); String directoryName = StringUtils.cleanPath(directory.getPath());
String fileName = StringUtils.cleanPath(file.getPath()); String fileName = StringUtils.cleanPath(file.getPath());
Assert.state(fileName.startsWith(folderName), Assert.state(fileName.startsWith(directoryName),
() -> "The file " + fileName + " is not contained in the source folder " + folderName); () -> "The file " + fileName + " is not contained in the source directory " + directoryName);
return fileName.substring(folderName.length() + 1); return fileName.substring(directoryName.length() + 1);
} }
@Override @Override
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -22,7 +22,7 @@ import java.util.Iterator; ...@@ -22,7 +22,7 @@ import java.util.Iterator;
import java.util.Set; import java.util.Set;
/** /**
* A collections of files from a specific source folder that have changed. * A collections of files from a specific source directory that have changed.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 1.3.0 * @since 1.3.0
...@@ -31,21 +31,21 @@ import java.util.Set; ...@@ -31,21 +31,21 @@ import java.util.Set;
*/ */
public final class ChangedFiles implements Iterable<ChangedFile> { public final class ChangedFiles implements Iterable<ChangedFile> {
private final File sourceFolder; private final File sourceDirectory;
private final Set<ChangedFile> files; private final Set<ChangedFile> files;
public ChangedFiles(File sourceFolder, Set<ChangedFile> files) { public ChangedFiles(File sourceDirectory, Set<ChangedFile> files) {
this.sourceFolder = sourceFolder; this.sourceDirectory = sourceDirectory;
this.files = Collections.unmodifiableSet(files); this.files = Collections.unmodifiableSet(files);
} }
/** /**
* The source folder being watched. * The source directory being watched.
* @return the source folder * @return the source directory
*/ */
public File getSourceFolder() { public File getSourceDirectory() {
return this.sourceFolder; return this.sourceDirectory;
} }
@Override @Override
...@@ -71,7 +71,7 @@ public final class ChangedFiles implements Iterable<ChangedFile> { ...@@ -71,7 +71,7 @@ public final class ChangedFiles implements Iterable<ChangedFile> {
} }
if (obj instanceof ChangedFiles) { if (obj instanceof ChangedFiles) {
ChangedFiles other = (ChangedFiles) obj; ChangedFiles other = (ChangedFiles) obj;
return this.sourceFolder.equals(other.sourceFolder) && this.files.equals(other.files); return this.sourceDirectory.equals(other.sourceDirectory) && this.files.equals(other.files);
} }
return super.equals(obj); return super.equals(obj);
} }
...@@ -83,7 +83,7 @@ public final class ChangedFiles implements Iterable<ChangedFile> { ...@@ -83,7 +83,7 @@ public final class ChangedFiles implements Iterable<ChangedFile> {
@Override @Override
public String toString() { public String toString() {
return this.sourceFolder + " " + this.files; return this.sourceDirectory + " " + this.files;
} }
} }
...@@ -31,31 +31,31 @@ import org.springframework.boot.devtools.filewatch.ChangedFile.Type; ...@@ -31,31 +31,31 @@ import org.springframework.boot.devtools.filewatch.ChangedFile.Type;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* A snapshot of a folder at a given point in time. * A snapshot of a directory at a given point in time.
* *
* @author Phillip Webb * @author Phillip Webb
*/ */
class FolderSnapshot { class DirectorySnapshot {
private static final Set<String> DOT_FOLDERS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(".", ".."))); private static final Set<String> DOTS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(".", "..")));
private final File folder; private final File directory;
private final Date time; private final Date time;
private Set<FileSnapshot> files; private Set<FileSnapshot> files;
/** /**
* Create a new {@link FolderSnapshot} for the given folder. * Create a new {@link DirectorySnapshot} for the given directory.
* @param folder the source folder * @param directory the source directory
*/ */
FolderSnapshot(File folder) { DirectorySnapshot(File directory) {
Assert.notNull(folder, "Folder must not be null"); Assert.notNull(directory, "Directory must not be null");
Assert.isTrue(!folder.isFile(), () -> "Folder '" + folder + "' must not be a file"); Assert.isTrue(!directory.isFile(), () -> "Directory '" + directory + "' must not be a file");
this.folder = folder; this.directory = directory;
this.time = new Date(); this.time = new Date();
Set<FileSnapshot> files = new LinkedHashSet<>(); Set<FileSnapshot> files = new LinkedHashSet<>();
collectFiles(folder, files); collectFiles(directory, files);
this.files = Collections.unmodifiableSet(files); this.files = Collections.unmodifiableSet(files);
} }
...@@ -63,7 +63,7 @@ class FolderSnapshot { ...@@ -63,7 +63,7 @@ class FolderSnapshot {
File[] children = source.listFiles(); File[] children = source.listFiles();
if (children != null) { if (children != null) {
for (File child : children) { for (File child : children) {
if (child.isDirectory() && !DOT_FOLDERS.contains(child.getName())) { if (child.isDirectory() && !DOTS.contains(child.getName())) {
collectFiles(child, result); collectFiles(child, result);
} }
else if (child.isFile()) { else if (child.isFile()) {
...@@ -73,29 +73,30 @@ class FolderSnapshot { ...@@ -73,29 +73,30 @@ class FolderSnapshot {
} }
} }
ChangedFiles getChangedFiles(FolderSnapshot snapshot, FileFilter triggerFilter) { ChangedFiles getChangedFiles(DirectorySnapshot snapshot, FileFilter triggerFilter) {
Assert.notNull(snapshot, "Snapshot must not be null"); Assert.notNull(snapshot, "Snapshot must not be null");
File folder = this.folder; File directory = this.directory;
Assert.isTrue(snapshot.folder.equals(folder), () -> "Snapshot source folder must be '" + folder + "'"); Assert.isTrue(snapshot.directory.equals(directory),
() -> "Snapshot source directory must be '" + directory + "'");
Set<ChangedFile> changes = new LinkedHashSet<>(); Set<ChangedFile> changes = new LinkedHashSet<>();
Map<File, FileSnapshot> previousFiles = getFilesMap(); Map<File, FileSnapshot> previousFiles = getFilesMap();
for (FileSnapshot currentFile : snapshot.files) { for (FileSnapshot currentFile : snapshot.files) {
if (acceptChangedFile(triggerFilter, currentFile)) { if (acceptChangedFile(triggerFilter, currentFile)) {
FileSnapshot previousFile = previousFiles.remove(currentFile.getFile()); FileSnapshot previousFile = previousFiles.remove(currentFile.getFile());
if (previousFile == null) { if (previousFile == null) {
changes.add(new ChangedFile(folder, currentFile.getFile(), Type.ADD)); changes.add(new ChangedFile(directory, currentFile.getFile(), Type.ADD));
} }
else if (!previousFile.equals(currentFile)) { else if (!previousFile.equals(currentFile)) {
changes.add(new ChangedFile(folder, currentFile.getFile(), Type.MODIFY)); changes.add(new ChangedFile(directory, currentFile.getFile(), Type.MODIFY));
} }
} }
} }
for (FileSnapshot previousFile : previousFiles.values()) { for (FileSnapshot previousFile : previousFiles.values()) {
if (acceptChangedFile(triggerFilter, previousFile)) { if (acceptChangedFile(triggerFilter, previousFile)) {
changes.add(new ChangedFile(folder, previousFile.getFile(), Type.DELETE)); changes.add(new ChangedFile(directory, previousFile.getFile(), Type.DELETE));
} }
} }
return new ChangedFiles(folder, changes); return new ChangedFiles(directory, changes);
} }
private boolean acceptChangedFile(FileFilter triggerFilter, FileSnapshot file) { private boolean acceptChangedFile(FileFilter triggerFilter, FileSnapshot file) {
...@@ -118,14 +119,14 @@ class FolderSnapshot { ...@@ -118,14 +119,14 @@ class FolderSnapshot {
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (obj instanceof FolderSnapshot) { if (obj instanceof DirectorySnapshot) {
return equals((FolderSnapshot) obj, null); return equals((DirectorySnapshot) obj, null);
} }
return super.equals(obj); return super.equals(obj);
} }
boolean equals(FolderSnapshot other, FileFilter filter) { boolean equals(DirectorySnapshot other, FileFilter filter) {
if (this.folder.equals(other.folder)) { if (this.directory.equals(other.directory)) {
Set<FileSnapshot> ourFiles = filter(this.files, filter); Set<FileSnapshot> ourFiles = filter(this.files, filter);
Set<FileSnapshot> otherFiles = filter(other.files, filter); Set<FileSnapshot> otherFiles = filter(other.files, filter);
return ourFiles.equals(otherFiles); return ourFiles.equals(otherFiles);
...@@ -148,22 +149,22 @@ class FolderSnapshot { ...@@ -148,22 +149,22 @@ class FolderSnapshot {
@Override @Override
public int hashCode() { public int hashCode() {
int hashCode = this.folder.hashCode(); int hashCode = this.directory.hashCode();
hashCode = 31 * hashCode + this.files.hashCode(); hashCode = 31 * hashCode + this.files.hashCode();
return hashCode; return hashCode;
} }
/** /**
* Return the source folder of this snapshot. * Return the source directory of this snapshot.
* @return the source folder * @return the source directory
*/ */
File getFolder() { File getDirectory() {
return this.folder; return this.directory;
} }
@Override @Override
public String toString() { public String toString() {
return this.folder + " snapshot at " + this.time; return this.directory + " snapshot at " + this.time;
} }
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -37,7 +37,7 @@ class FileSnapshot { ...@@ -37,7 +37,7 @@ class FileSnapshot {
FileSnapshot(File file) { FileSnapshot(File file) {
Assert.notNull(file, "File must not be null"); Assert.notNull(file, "File must not be null");
Assert.isTrue(file.isFile() || !file.exists(), "File must not be a folder"); Assert.isTrue(file.isFile() || !file.exists(), "File must not be a directory");
this.file = file; this.file = file;
this.exists = file.exists(); this.exists = file.exists();
this.length = file.length(); this.length = file.length();
......
...@@ -33,7 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -33,7 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Watches specific folders for file changes. * Watches specific directories for file changes.
* *
* @author Andy Clement * @author Andy Clement
* @author Phillip Webb * @author Phillip Webb
...@@ -56,7 +56,7 @@ public class FileSystemWatcher { ...@@ -56,7 +56,7 @@ public class FileSystemWatcher {
private final AtomicInteger remainingScans = new AtomicInteger(-1); private final AtomicInteger remainingScans = new AtomicInteger(-1);
private final Map<File, FolderSnapshot> folders = new HashMap<>(); private final Map<File, DirectorySnapshot> directories = new HashMap<>();
private Thread watchThread; private Thread watchThread;
...@@ -104,30 +104,28 @@ public class FileSystemWatcher { ...@@ -104,30 +104,28 @@ public class FileSystemWatcher {
} }
/** /**
* Add source folders to monitor. Cannot be called after the watcher has been * Add source directories to monitor. Cannot be called after the watcher has been
* {@link #start() started}. * {@link #start() started}.
* @param folders the folders to monitor * @param directories the directories to monitor
*/ */
public void addSourceFolders(Iterable<File> folders) { public void addSourceDirectories(Iterable<File> directories) {
Assert.notNull(folders, "Folders must not be null"); Assert.notNull(directories, "Directories must not be null");
synchronized (this.monitor) { synchronized (this.monitor) {
for (File folder : folders) { directories.forEach(this::addSourceDirectory);
addSourceFolder(folder);
}
} }
} }
/** /**
* Add a source folder to monitor. Cannot be called after the watcher has been * Add a source directory to monitor. Cannot be called after the watcher has been
* {@link #start() started}. * {@link #start() started}.
* @param folder the folder to monitor * @param directory the directory to monitor
*/ */
public void addSourceFolder(File folder) { public void addSourceDirectory(File directory) {
Assert.notNull(folder, "Folder must not be null"); Assert.notNull(directory, "Directory must not be null");
Assert.isTrue(!folder.isFile(), () -> "Folder '" + folder + "' must not be a file"); Assert.isTrue(!directory.isFile(), () -> "Directory '" + directory + "' must not be a file");
synchronized (this.monitor) { synchronized (this.monitor) {
checkNotStarted(); checkNotStarted();
this.folders.put(folder, null); this.directories.put(directory, null);
} }
} }
...@@ -148,15 +146,15 @@ public class FileSystemWatcher { ...@@ -148,15 +146,15 @@ public class FileSystemWatcher {
} }
/** /**
* Start monitoring the source folder for changes. * Start monitoring the source directory for changes.
*/ */
public void start() { public void start() {
synchronized (this.monitor) { synchronized (this.monitor) {
saveInitialSnapshots(); saveInitialSnapshots();
if (this.watchThread == null) { if (this.watchThread == null) {
Map<File, FolderSnapshot> localFolders = new HashMap<>(this.folders); Map<File, DirectorySnapshot> localDirectories = new HashMap<>(this.directories);
this.watchThread = new Thread(new Watcher(this.remainingScans, new ArrayList<>(this.listeners), this.watchThread = new Thread(new Watcher(this.remainingScans, new ArrayList<>(this.listeners),
this.triggerFilter, this.pollInterval, this.quietPeriod, localFolders)); this.triggerFilter, this.pollInterval, this.quietPeriod, localDirectories));
this.watchThread.setName("File Watcher"); this.watchThread.setName("File Watcher");
this.watchThread.setDaemon(this.daemon); this.watchThread.setDaemon(this.daemon);
this.watchThread.start(); this.watchThread.start();
...@@ -165,18 +163,18 @@ public class FileSystemWatcher { ...@@ -165,18 +163,18 @@ public class FileSystemWatcher {
} }
private void saveInitialSnapshots() { private void saveInitialSnapshots() {
this.folders.replaceAll((f, v) -> new FolderSnapshot(f)); this.directories.replaceAll((f, v) -> new DirectorySnapshot(f));
} }
/** /**
* Stop monitoring the source folders. * Stop monitoring the source directories.
*/ */
public void stop() { public void stop() {
stopAfter(0); stopAfter(0);
} }
/** /**
* Stop monitoring the source folders. * Stop monitoring the source directories.
* @param remainingScans the number of remaining scans * @param remainingScans the number of remaining scans
*/ */
void stopAfter(int remainingScans) { void stopAfter(int remainingScans) {
...@@ -213,16 +211,16 @@ public class FileSystemWatcher { ...@@ -213,16 +211,16 @@ public class FileSystemWatcher {
private final long quietPeriod; private final long quietPeriod;
private Map<File, FolderSnapshot> folders; private Map<File, DirectorySnapshot> directories;
private Watcher(AtomicInteger remainingScans, List<FileChangeListener> listeners, FileFilter triggerFilter, private Watcher(AtomicInteger remainingScans, List<FileChangeListener> listeners, FileFilter triggerFilter,
long pollInterval, long quietPeriod, Map<File, FolderSnapshot> folders) { long pollInterval, long quietPeriod, Map<File, DirectorySnapshot> directories) {
this.remainingScans = remainingScans; this.remainingScans = remainingScans;
this.listeners = listeners; this.listeners = listeners;
this.triggerFilter = triggerFilter; this.triggerFilter = triggerFilter;
this.pollInterval = pollInterval; this.pollInterval = pollInterval;
this.quietPeriod = quietPeriod; this.quietPeriod = quietPeriod;
this.folders = folders; this.directories = directories;
} }
@Override @Override
...@@ -244,47 +242,47 @@ public class FileSystemWatcher { ...@@ -244,47 +242,47 @@ public class FileSystemWatcher {
private void scan() throws InterruptedException { private void scan() throws InterruptedException {
Thread.sleep(this.pollInterval - this.quietPeriod); Thread.sleep(this.pollInterval - this.quietPeriod);
Map<File, FolderSnapshot> previous; Map<File, DirectorySnapshot> previous;
Map<File, FolderSnapshot> current = this.folders; Map<File, DirectorySnapshot> current = this.directories;
do { do {
previous = current; previous = current;
current = getCurrentSnapshots(); current = getCurrentSnapshots();
Thread.sleep(this.quietPeriod); Thread.sleep(this.quietPeriod);
} }
while (isDifferent(previous, current)); while (isDifferent(previous, current));
if (isDifferent(this.folders, current)) { if (isDifferent(this.directories, current)) {
updateSnapshots(current.values()); updateSnapshots(current.values());
} }
} }
private boolean isDifferent(Map<File, FolderSnapshot> previous, Map<File, FolderSnapshot> current) { private boolean isDifferent(Map<File, DirectorySnapshot> previous, Map<File, DirectorySnapshot> current) {
if (!previous.keySet().equals(current.keySet())) { if (!previous.keySet().equals(current.keySet())) {
return true; return true;
} }
for (Map.Entry<File, FolderSnapshot> entry : previous.entrySet()) { for (Map.Entry<File, DirectorySnapshot> entry : previous.entrySet()) {
FolderSnapshot previousFolder = entry.getValue(); DirectorySnapshot previousDirectory = entry.getValue();
FolderSnapshot currentFolder = current.get(entry.getKey()); DirectorySnapshot currentDirectory = current.get(entry.getKey());
if (!previousFolder.equals(currentFolder, this.triggerFilter)) { if (!previousDirectory.equals(currentDirectory, this.triggerFilter)) {
return true; return true;
} }
} }
return false; return false;
} }
private Map<File, FolderSnapshot> getCurrentSnapshots() { private Map<File, DirectorySnapshot> getCurrentSnapshots() {
Map<File, FolderSnapshot> snapshots = new LinkedHashMap<>(); Map<File, DirectorySnapshot> snapshots = new LinkedHashMap<>();
for (File folder : this.folders.keySet()) { for (File directory : this.directories.keySet()) {
snapshots.put(folder, new FolderSnapshot(folder)); snapshots.put(directory, new DirectorySnapshot(directory));
} }
return snapshots; return snapshots;
} }
private void updateSnapshots(Collection<FolderSnapshot> snapshots) { private void updateSnapshots(Collection<DirectorySnapshot> snapshots) {
Map<File, FolderSnapshot> updated = new LinkedHashMap<>(); Map<File, DirectorySnapshot> updated = new LinkedHashMap<>();
Set<ChangedFiles> changeSet = new LinkedHashSet<>(); Set<ChangedFiles> changeSet = new LinkedHashSet<>();
for (FolderSnapshot snapshot : snapshots) { for (DirectorySnapshot snapshot : snapshots) {
FolderSnapshot previous = this.folders.get(snapshot.getFolder()); DirectorySnapshot previous = this.directories.get(snapshot.getDirectory());
updated.put(snapshot.getFolder(), snapshot); updated.put(snapshot.getDirectory(), snapshot);
ChangedFiles changedFiles = previous.getChangedFiles(snapshot, this.triggerFilter); ChangedFiles changedFiles = previous.getChangedFiles(snapshot, this.triggerFilter);
if (!changedFiles.getFiles().isEmpty()) { if (!changedFiles.getFiles().isEmpty()) {
changeSet.add(changedFiles); changeSet.add(changedFiles);
...@@ -293,7 +291,7 @@ public class FileSystemWatcher { ...@@ -293,7 +291,7 @@ public class FileSystemWatcher {
if (!changeSet.isEmpty()) { if (!changeSet.isEmpty()) {
fireListeners(Collections.unmodifiableSet(changeSet)); fireListeners(Collections.unmodifiableSet(changeSet));
} }
this.folders = updated; this.directories = updated;
} }
private void fireListeners(Set<ChangedFiles> changeSet) { private void fireListeners(Set<ChangedFiles> changeSet) {
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -144,9 +144,9 @@ public class ClassPathChangeUploader implements ApplicationListener<ClassPathCha ...@@ -144,9 +144,9 @@ public class ClassPathChangeUploader implements ApplicationListener<ClassPathCha
private ClassLoaderFiles getClassLoaderFiles(ClassPathChangedEvent event) throws IOException { private ClassLoaderFiles getClassLoaderFiles(ClassPathChangedEvent event) throws IOException {
ClassLoaderFiles files = new ClassLoaderFiles(); ClassLoaderFiles files = new ClassLoaderFiles();
for (ChangedFiles changedFiles : event.getChangeSet()) { for (ChangedFiles changedFiles : event.getChangeSet()) {
String sourceFolder = changedFiles.getSourceFolder().getAbsolutePath(); String sourceDirectory = changedFiles.getSourceDirectory().getAbsolutePath();
for (ChangedFile changedFile : changedFiles) { for (ChangedFile changedFile : changedFiles) {
files.addFile(sourceFolder, changedFile.getRelativeName(), asClassLoaderFile(changedFile)); files.addFile(sourceDirectory, changedFile.getRelativeName(), asClassLoaderFile(changedFile));
} }
} }
return files; return files;
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -56,7 +56,7 @@ final class ChangeableUrls implements Iterable<URL> { ...@@ -56,7 +56,7 @@ final class ChangeableUrls implements Iterable<URL> {
DevToolsSettings settings = DevToolsSettings.get(); DevToolsSettings settings = DevToolsSettings.get();
List<URL> reloadableUrls = new ArrayList<>(urls.length); List<URL> reloadableUrls = new ArrayList<>(urls.length);
for (URL url : urls) { for (URL url : urls) {
if ((settings.isRestartInclude(url) || isFolderUrl(url.toString())) && !settings.isRestartExclude(url)) { if ((settings.isRestartInclude(url) || isDirectoryUrl(url.toString())) && !settings.isRestartExclude(url)) {
reloadableUrls.add(url); reloadableUrls.add(url);
} }
} }
...@@ -66,7 +66,7 @@ final class ChangeableUrls implements Iterable<URL> { ...@@ -66,7 +66,7 @@ final class ChangeableUrls implements Iterable<URL> {
this.urls = Collections.unmodifiableList(reloadableUrls); this.urls = Collections.unmodifiableList(reloadableUrls);
} }
private boolean isFolderUrl(String urlString) { private boolean isDirectoryUrl(String urlString) {
return urlString.startsWith("file:") && urlString.endsWith("/"); return urlString.startsWith("file:") && urlString.endsWith("/");
} }
......
...@@ -31,7 +31,7 @@ import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile; ...@@ -31,7 +31,7 @@ import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFileURLStreamHandler; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFileURLStreamHandler;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.AbstractResource; import org.springframework.core.io.AbstractResource;
...@@ -123,8 +123,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe ...@@ -123,8 +123,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
private List<Resource> getAdditionalResources(String locationPattern) throws MalformedURLException { private List<Resource> getAdditionalResources(String locationPattern) throws MalformedURLException {
List<Resource> additionalResources = new ArrayList<>(); List<Resource> additionalResources = new ArrayList<>();
String trimmedLocationPattern = trimLocationPattern(locationPattern); String trimmedLocationPattern = trimLocationPattern(locationPattern);
for (SourceFolder sourceFolder : this.classLoaderFiles.getSourceFolders()) { for (SourceDirectory sourceDirectory : this.classLoaderFiles.getSourceDirectories()) {
for (Entry<String, ClassLoaderFile> entry : sourceFolder.getFilesEntrySet()) { for (Entry<String, ClassLoaderFile> entry : sourceDirectory.getFilesEntrySet()) {
String name = entry.getKey(); String name = entry.getKey();
ClassLoaderFile file = entry.getValue(); ClassLoaderFile file = entry.getValue();
if (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) { if (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) {
...@@ -147,8 +147,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe ...@@ -147,8 +147,8 @@ final class ClassLoaderFilesResourcePatternResolver implements ResourcePatternRe
} }
private boolean isDeleted(Resource resource) { private boolean isDeleted(Resource resource) {
for (SourceFolder sourceFolder : this.classLoaderFiles.getSourceFolders()) { for (SourceDirectory sourceDirectory : this.classLoaderFiles.getSourceDirectories()) {
for (Entry<String, ClassLoaderFile> entry : sourceFolder.getFilesEntrySet()) { for (Entry<String, ClassLoaderFile> entry : sourceDirectory.getFilesEntrySet()) {
try { try {
String name = entry.getKey(); String name = entry.getKey();
ClassLoaderFile file = entry.getValue(); ClassLoaderFile file = entry.getValue();
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -30,7 +30,7 @@ import org.springframework.util.Assert; ...@@ -30,7 +30,7 @@ import org.springframework.util.Assert;
/** /**
* {@link ClassLoaderFileRepository} that maintains a collection of * {@link ClassLoaderFileRepository} that maintains a collection of
* {@link ClassLoaderFile} items grouped by source folders. * {@link ClassLoaderFile} items grouped by source directories.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 1.3.0 * @since 1.3.0
...@@ -41,13 +41,13 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -41,13 +41,13 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
private final Map<String, SourceFolder> sourceFolders; private final Map<String, SourceDirectory> sourceDirectories;
/** /**
* Create a new {@link ClassLoaderFiles} instance. * Create a new {@link ClassLoaderFiles} instance.
*/ */
public ClassLoaderFiles() { public ClassLoaderFiles() {
this.sourceFolders = new LinkedHashMap<>(); this.sourceDirectories = new LinkedHashMap<>();
} }
/** /**
...@@ -56,7 +56,7 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -56,7 +56,7 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
*/ */
public ClassLoaderFiles(ClassLoaderFiles classLoaderFiles) { public ClassLoaderFiles(ClassLoaderFiles classLoaderFiles) {
Assert.notNull(classLoaderFiles, "ClassLoaderFiles must not be null"); Assert.notNull(classLoaderFiles, "ClassLoaderFiles must not be null");
this.sourceFolders = new LinkedHashMap<>(classLoaderFiles.sourceFolders); this.sourceDirectories = new LinkedHashMap<>(classLoaderFiles.sourceDirectories);
} }
/** /**
...@@ -66,9 +66,9 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -66,9 +66,9 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
*/ */
public void addAll(ClassLoaderFiles files) { public void addAll(ClassLoaderFiles files) {
Assert.notNull(files, "Files must not be null"); Assert.notNull(files, "Files must not be null");
for (SourceFolder folder : files.getSourceFolders()) { for (SourceDirectory directory : files.getSourceDirectories()) {
for (Map.Entry<String, ClassLoaderFile> entry : folder.getFilesEntrySet()) { for (Map.Entry<String, ClassLoaderFile> entry : directory.getFilesEntrySet()) {
addFile(folder.getName(), entry.getKey(), entry.getValue()); addFile(directory.getName(), entry.getKey(), entry.getValue());
} }
} }
} }
...@@ -84,45 +84,45 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -84,45 +84,45 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
/** /**
* Add a single {@link ClassLoaderFile} to the collection. * Add a single {@link ClassLoaderFile} to the collection.
* @param sourceFolder the source folder of the file * @param sourceDirectory the source directory of the file
* @param name the name of the file * @param name the name of the file
* @param file the file to add * @param file the file to add
*/ */
public void addFile(String sourceFolder, String name, ClassLoaderFile file) { public void addFile(String sourceDirectory, String name, ClassLoaderFile file) {
Assert.notNull(sourceFolder, "SourceFolder must not be null"); Assert.notNull(sourceDirectory, "SourceDirectory must not be null");
Assert.notNull(name, "Name must not be null"); Assert.notNull(name, "Name must not be null");
Assert.notNull(file, "File must not be null"); Assert.notNull(file, "File must not be null");
removeAll(name); removeAll(name);
getOrCreateSourceFolder(sourceFolder).add(name, file); getOrCreateSourceDirectory(sourceDirectory).add(name, file);
} }
private void removeAll(String name) { private void removeAll(String name) {
for (SourceFolder sourceFolder : this.sourceFolders.values()) { for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
sourceFolder.remove(name); sourceDirectory.remove(name);
} }
} }
/** /**
* Get or create a {@link SourceFolder} with the given name. * Get or create a {@link SourceDirectory} with the given name.
* @param name the name of the folder * @param name the name of the directory
* @return an existing or newly added {@link SourceFolder} * @return an existing or newly added {@link SourceDirectory}
*/ */
protected final SourceFolder getOrCreateSourceFolder(String name) { protected final SourceDirectory getOrCreateSourceDirectory(String name) {
SourceFolder sourceFolder = this.sourceFolders.get(name); SourceDirectory sourceDirectory = this.sourceDirectories.get(name);
if (sourceFolder == null) { if (sourceDirectory == null) {
sourceFolder = new SourceFolder(name); sourceDirectory = new SourceDirectory(name);
this.sourceFolders.put(name, sourceFolder); this.sourceDirectories.put(name, sourceDirectory);
} }
return sourceFolder; return sourceDirectory;
} }
/** /**
* Return all {@link SourceFolder SourceFolders} that have been added to the * Return all {@link SourceDirectory SourceDirectories} that have been added to the
* collection. * collection.
* @return a collection of {@link SourceFolder} items * @return a collection of {@link SourceDirectory} items
*/ */
public Collection<SourceFolder> getSourceFolders() { public Collection<SourceDirectory> getSourceDirectories() {
return Collections.unmodifiableCollection(this.sourceFolders.values()); return Collections.unmodifiableCollection(this.sourceDirectories.values());
} }
/** /**
...@@ -131,16 +131,16 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -131,16 +131,16 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
*/ */
public int size() { public int size() {
int size = 0; int size = 0;
for (SourceFolder sourceFolder : this.sourceFolders.values()) { for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
size += sourceFolder.getFiles().size(); size += sourceDirectory.getFiles().size();
} }
return size; return size;
} }
@Override @Override
public ClassLoaderFile getFile(String name) { public ClassLoaderFile getFile(String name) {
for (SourceFolder sourceFolder : this.sourceFolders.values()) { for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
ClassLoaderFile file = sourceFolder.get(name); ClassLoaderFile file = sourceDirectory.get(name);
if (file != null) { if (file != null) {
return file; return file;
} }
...@@ -149,9 +149,9 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -149,9 +149,9 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
} }
/** /**
* An individual source folder that is being managed by the collection. * An individual source directory that is being managed by the collection.
*/ */
public static class SourceFolder implements Serializable { public static class SourceDirectory implements Serializable {
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
...@@ -159,7 +159,7 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -159,7 +159,7 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
private final Map<String, ClassLoaderFile> files = new LinkedHashMap<>(); private final Map<String, ClassLoaderFile> files = new LinkedHashMap<>();
SourceFolder(String name) { SourceDirectory(String name) {
this.name = name; this.name = name;
} }
...@@ -180,8 +180,8 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -180,8 +180,8 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
} }
/** /**
* Return the name of the source folder. * Return the name of the source directory.
* @return the name of the source folder * @return the name of the source directory
*/ */
public String getName() { public String getName() {
return this.name; return this.name;
...@@ -189,8 +189,8 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable ...@@ -189,8 +189,8 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable
/** /**
* Return all {@link ClassLoaderFile ClassLoaderFiles} in the collection that are * Return all {@link ClassLoaderFile ClassLoaderFiles} in the collection that are
* contained in this source folder. * contained in this source directory.
* @return the files contained in the source folder * @return the files contained in the source directory
*/ */
public Collection<ClassLoaderFile> getFiles() { public Collection<ClassLoaderFile> getFiles() {
return Collections.unmodifiableCollection(this.files.values()); return Collections.unmodifiableCollection(this.files.values());
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -26,13 +26,13 @@ import java.util.regex.Pattern; ...@@ -26,13 +26,13 @@ import java.util.regex.Pattern;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Default implementation of {@link SourceFolderUrlFilter} that attempts to match URLs * Default implementation of {@link SourceDirectoryUrlFilter} that attempts to match URLs
* using common naming conventions. * using common naming conventions.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 1.3.0 * @since 2.3.0
*/ */
public class DefaultSourceFolderUrlFilter implements SourceFolderUrlFilter { public class DefaultSourceDirectoryUrlFilter implements SourceDirectoryUrlFilter {
private static final String[] COMMON_ENDINGS = { "/target/classes", "/bin" }; private static final String[] COMMON_ENDINGS = { "/target/classes", "/bin" };
...@@ -44,12 +44,12 @@ public class DefaultSourceFolderUrlFilter implements SourceFolderUrlFilter { ...@@ -44,12 +44,12 @@ public class DefaultSourceFolderUrlFilter implements SourceFolderUrlFilter {
"spring-boot-devtools", "spring-boot-autoconfigure", "spring-boot-actuator", "spring-boot-starter")); "spring-boot-devtools", "spring-boot-autoconfigure", "spring-boot-actuator", "spring-boot-starter"));
@Override @Override
public boolean isMatch(String sourceFolder, URL url) { public boolean isMatch(String sourceDirectory, URL url) {
String jarName = getJarName(url); String jarName = getJarName(url);
if (!StringUtils.hasLength(jarName)) { if (!StringUtils.hasLength(jarName)) {
return false; return false;
} }
return isMatch(sourceFolder, jarName); return isMatch(sourceDirectory, jarName);
} }
private String getJarName(URL url) { private String getJarName(URL url) {
...@@ -60,23 +60,23 @@ public class DefaultSourceFolderUrlFilter implements SourceFolderUrlFilter { ...@@ -60,23 +60,23 @@ public class DefaultSourceFolderUrlFilter implements SourceFolderUrlFilter {
return null; return null;
} }
private boolean isMatch(String sourceFolder, String jarName) { private boolean isMatch(String sourceDirectory, String jarName) {
sourceFolder = stripTrailingSlash(sourceFolder); sourceDirectory = stripTrailingSlash(sourceDirectory);
sourceFolder = stripCommonEnds(sourceFolder); sourceDirectory = stripCommonEnds(sourceDirectory);
String[] folders = StringUtils.delimitedListToStringArray(sourceFolder, "/"); String[] directories = StringUtils.delimitedListToStringArray(sourceDirectory, "/");
for (int i = folders.length - 1; i >= 0; i--) { for (int i = directories.length - 1; i >= 0; i--) {
if (isFolderMatch(folders[i], jarName)) { if (isDirectoryMatch(directories[i], jarName)) {
return true; return true;
} }
} }
return false; return false;
} }
private boolean isFolderMatch(String folder, String jarName) { private boolean isDirectoryMatch(String directory, String jarName) {
if (!jarName.startsWith(folder) || SKIPPED_PROJECTS.contains(folder)) { if (!jarName.startsWith(directory) || SKIPPED_PROJECTS.contains(directory)) {
return false; return false;
} }
String version = jarName.substring(folder.length()); String version = jarName.substring(directory.length());
return version.isEmpty() || VERSION_PATTERN.matcher(version).matches(); return version.isEmpty() || VERSION_PATTERN.matcher(version).matches();
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -44,12 +44,12 @@ public class HttpRestartServer { ...@@ -44,12 +44,12 @@ public class HttpRestartServer {
/** /**
* Create a new {@link HttpRestartServer} instance. * Create a new {@link HttpRestartServer} instance.
* @param sourceFolderUrlFilter the source filter used to link remote folder to the * @param sourceDirectoryUrlFilter the source filter used to link remote directory to
* local classpath * the local classpath
*/ */
public HttpRestartServer(SourceFolderUrlFilter sourceFolderUrlFilter) { public HttpRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {
Assert.notNull(sourceFolderUrlFilter, "SourceFolderUrlFilter must not be null"); Assert.notNull(sourceDirectoryUrlFilter, "SourceDirectoryUrlFilter must not be null");
this.server = new RestartServer(sourceFolderUrlFilter); this.server = new RestartServer(sourceDirectoryUrlFilter);
} }
/** /**
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -32,7 +32,7 @@ import org.springframework.boot.devtools.restart.Restarter; ...@@ -32,7 +32,7 @@ import org.springframework.boot.devtools.restart.Restarter;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
...@@ -48,29 +48,29 @@ public class RestartServer { ...@@ -48,29 +48,29 @@ public class RestartServer {
private static final Log logger = LogFactory.getLog(RestartServer.class); private static final Log logger = LogFactory.getLog(RestartServer.class);
private final SourceFolderUrlFilter sourceFolderUrlFilter; private final SourceDirectoryUrlFilter sourceDirectoryUrlFilter;
private final ClassLoader classLoader; private final ClassLoader classLoader;
/** /**
* Create a new {@link RestartServer} instance. * Create a new {@link RestartServer} instance.
* @param sourceFolderUrlFilter the source filter used to link remote folder to the * @param sourceDirectoryUrlFilter the source filter used to link remote directory to
* local classpath * the local classpath
*/ */
public RestartServer(SourceFolderUrlFilter sourceFolderUrlFilter) { public RestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {
this(sourceFolderUrlFilter, Thread.currentThread().getContextClassLoader()); this(sourceDirectoryUrlFilter, Thread.currentThread().getContextClassLoader());
} }
/** /**
* Create a new {@link RestartServer} instance. * Create a new {@link RestartServer} instance.
* @param sourceFolderUrlFilter the source filter used to link remote folder to the * @param sourceDirectoryUrlFilter the source filter used to link remote directory to
* local classpath * the local classpath
* @param classLoader the application classloader * @param classLoader the application classloader
*/ */
public RestartServer(SourceFolderUrlFilter sourceFolderUrlFilter, ClassLoader classLoader) { public RestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter, ClassLoader classLoader) {
Assert.notNull(sourceFolderUrlFilter, "SourceFolderUrlFilter must not be null"); Assert.notNull(sourceDirectoryUrlFilter, "SourceDirectoryUrlFilter must not be null");
Assert.notNull(classLoader, "ClassLoader must not be null"); Assert.notNull(classLoader, "ClassLoader must not be null");
this.sourceFolderUrlFilter = sourceFolderUrlFilter; this.sourceDirectoryUrlFilter = sourceDirectoryUrlFilter;
this.classLoader = classLoader; this.classLoader = classLoader;
} }
...@@ -82,27 +82,27 @@ public class RestartServer { ...@@ -82,27 +82,27 @@ public class RestartServer {
public void updateAndRestart(ClassLoaderFiles files) { public void updateAndRestart(ClassLoaderFiles files) {
Set<URL> urls = new LinkedHashSet<>(); Set<URL> urls = new LinkedHashSet<>();
Set<URL> classLoaderUrls = getClassLoaderUrls(); Set<URL> classLoaderUrls = getClassLoaderUrls();
for (SourceFolder folder : files.getSourceFolders()) { for (SourceDirectory directory : files.getSourceDirectories()) {
for (Entry<String, ClassLoaderFile> entry : folder.getFilesEntrySet()) { for (Entry<String, ClassLoaderFile> entry : directory.getFilesEntrySet()) {
for (URL url : classLoaderUrls) { for (URL url : classLoaderUrls) {
if (updateFileSystem(url, entry.getKey(), entry.getValue())) { if (updateFileSystem(url, entry.getKey(), entry.getValue())) {
urls.add(url); urls.add(url);
} }
} }
} }
urls.addAll(getMatchingUrls(classLoaderUrls, folder.getName())); urls.addAll(getMatchingUrls(classLoaderUrls, directory.getName()));
} }
updateTimeStamp(urls); updateTimeStamp(urls);
restart(urls, files); restart(urls, files);
} }
private boolean updateFileSystem(URL url, String name, ClassLoaderFile classLoaderFile) { private boolean updateFileSystem(URL url, String name, ClassLoaderFile classLoaderFile) {
if (!isFolderUrl(url.toString())) { if (!isDirectoryUrl(url.toString())) {
return false; return false;
} }
try { try {
File folder = ResourceUtils.getFile(url); File directory = ResourceUtils.getFile(url);
File file = new File(folder, name); File file = new File(directory, name);
if (file.exists() && file.canWrite()) { if (file.exists() && file.canWrite()) {
if (classLoaderFile.getKind() == Kind.DELETED) { if (classLoaderFile.getKind() == Kind.DELETED) {
return file.delete(); return file.delete();
...@@ -117,16 +117,16 @@ public class RestartServer { ...@@ -117,16 +117,16 @@ public class RestartServer {
return false; return false;
} }
private boolean isFolderUrl(String urlString) { private boolean isDirectoryUrl(String urlString) {
return urlString.startsWith("file:") && urlString.endsWith("/"); return urlString.startsWith("file:") && urlString.endsWith("/");
} }
private Set<URL> getMatchingUrls(Set<URL> urls, String sourceFolder) { private Set<URL> getMatchingUrls(Set<URL> urls, String sourceDirectory) {
Set<URL> matchingUrls = new LinkedHashSet<>(); Set<URL> matchingUrls = new LinkedHashSet<>();
for (URL url : urls) { for (URL url : urls) {
if (this.sourceFolderUrlFilter.isMatch(sourceFolder, url)) { if (this.sourceDirectoryUrlFilter.isMatch(sourceDirectory, url)) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("URL " + url + " matched against source folder " + sourceFolder); logger.debug("URL " + url + " matched against source directory " + sourceDirectory);
} }
matchingUrls.add(url); matchingUrls.add(url);
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -19,22 +19,22 @@ package org.springframework.boot.devtools.restart.server; ...@@ -19,22 +19,22 @@ package org.springframework.boot.devtools.restart.server;
import java.net.URL; import java.net.URL;
/** /**
* Filter URLs based on a source folder name. Used to match URLs from the running * Filter URLs based on a source directory name. Used to match URLs from the running
* classpath against source folders on a remote system. * classpath against source directory on a remote system.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 1.3.0 * @since 2.3.0
* @see DefaultSourceFolderUrlFilter * @see DefaultSourceDirectoryUrlFilter
*/ */
@FunctionalInterface @FunctionalInterface
public interface SourceFolderUrlFilter { public interface SourceDirectoryUrlFilter {
/** /**
* Determine if the specified URL matches a source folder. * Determine if the specified URL matches a source directory.
* @param sourceFolder the source folder * @param sourceDirectory the source directory
* @param url the URL to check * @param url the URL to check
* @return {@code true} if the URL matches * @return {@code true} if the URL matches
*/ */
boolean isMatch(String sourceFolder, URL url); boolean isMatch(String sourceDirectory, URL url);
} }
...@@ -213,8 +213,8 @@ class LocalDevToolsAutoConfigurationTests { ...@@ -213,8 +213,8 @@ class LocalDevToolsAutoConfigurationTests {
ClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class); ClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class);
Object watcher = ReflectionTestUtils.getField(classPathWatcher, "fileSystemWatcher"); Object watcher = ReflectionTestUtils.getField(classPathWatcher, "fileSystemWatcher");
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<File, Object> folders = (Map<File, Object>) ReflectionTestUtils.getField(watcher, "folders"); Map<File, Object> directories = (Map<File, Object>) ReflectionTestUtils.getField(watcher, "directories");
assertThat(folders).hasSize(2).containsKey(new File("src/main/java").getAbsoluteFile()) assertThat(directories).hasSize(2).containsKey(new File("src/main/java").getAbsoluteFile())
.containsKey(new File("src/test/java").getAbsoluteFile()); .containsKey(new File("src/test/java").getAbsoluteFile());
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -32,7 +32,7 @@ import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfi ...@@ -32,7 +32,7 @@ import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfi
import org.springframework.boot.devtools.remote.server.DispatcherFilter; import org.springframework.boot.devtools.remote.server.DispatcherFilter;
import org.springframework.boot.devtools.restart.MockRestarter; import org.springframework.boot.devtools.restart.MockRestarter;
import org.springframework.boot.devtools.restart.server.HttpRestartServer; import org.springframework.boot.devtools.restart.server.HttpRestartServer;
import org.springframework.boot.devtools.restart.server.SourceFolderUrlFilter; import org.springframework.boot.devtools.restart.server.SourceDirectoryUrlFilter;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -244,8 +244,8 @@ class RemoteDevToolsAutoConfigurationTests { ...@@ -244,8 +244,8 @@ class RemoteDevToolsAutoConfigurationTests {
@Bean @Bean
HttpRestartServer remoteRestartHttpRestartServer() { HttpRestartServer remoteRestartHttpRestartServer() {
SourceFolderUrlFilter sourceFolderUrlFilter = mock(SourceFolderUrlFilter.class); SourceDirectoryUrlFilter sourceDirectoryUrlFilter = mock(SourceDirectoryUrlFilter.class);
return new MockHttpRestartServer(sourceFolderUrlFilter); return new MockHttpRestartServer(sourceDirectoryUrlFilter);
} }
} }
...@@ -257,8 +257,8 @@ class RemoteDevToolsAutoConfigurationTests { ...@@ -257,8 +257,8 @@ class RemoteDevToolsAutoConfigurationTests {
private boolean invoked; private boolean invoked;
MockHttpRestartServer(SourceFolderUrlFilter sourceFolderUrlFilter) { MockHttpRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {
super(sourceFolderUrlFilter); super(sourceDirectoryUrlFilter);
} }
@Override @Override
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -93,10 +93,10 @@ class ClassPathFileChangeListenerTests { ...@@ -93,10 +93,10 @@ class ClassPathFileChangeListenerTests {
private void testSendsEvent(boolean restart) { private void testSendsEvent(boolean restart) {
ClassPathFileChangeListener listener = new ClassPathFileChangeListener(this.eventPublisher, ClassPathFileChangeListener listener = new ClassPathFileChangeListener(this.eventPublisher,
this.restartStrategy, this.fileSystemWatcher); this.restartStrategy, this.fileSystemWatcher);
File folder = new File("s1"); File directory = new File("s1");
File file = new File("f1"); File file = new File("f1");
ChangedFile file1 = new ChangedFile(folder, file, ChangedFile.Type.ADD); ChangedFile file1 = new ChangedFile(directory, file, ChangedFile.Type.ADD);
ChangedFile file2 = new ChangedFile(folder, file, ChangedFile.Type.ADD); ChangedFile file2 = new ChangedFile(directory, file, ChangedFile.Type.ADD);
Set<ChangedFile> files = new LinkedHashSet<>(); Set<ChangedFile> files = new LinkedHashSet<>();
files.add(file1); files.add(file1);
files.add(file2); files.add(file2);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -57,19 +57,19 @@ class ClassPathFileSystemWatcherTests { ...@@ -57,19 +57,19 @@ class ClassPathFileSystemWatcherTests {
} }
@Test @Test
void configuredWithRestartStrategy(@TempDir File folder) throws Exception { void configuredWithRestartStrategy(@TempDir File directory) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
Map<String, Object> properties = new HashMap<>(); Map<String, Object> properties = new HashMap<>();
List<URL> urls = new ArrayList<>(); List<URL> urls = new ArrayList<>();
urls.add(new URL("https://spring.io")); urls.add(new URL("https://spring.io"));
urls.add(folder.toURI().toURL()); urls.add(directory.toURI().toURL());
properties.put("urls", urls); properties.put("urls", urls);
MapPropertySource propertySource = new MapPropertySource("test", properties); MapPropertySource propertySource = new MapPropertySource("test", properties);
context.getEnvironment().getPropertySources().addLast(propertySource); context.getEnvironment().getPropertySources().addLast(propertySource);
context.register(Config.class); context.register(Config.class);
context.refresh(); context.refresh();
Thread.sleep(200); Thread.sleep(200);
File classFile = new File(folder, "Example.class"); File classFile = new File(directory, "Example.class");
FileCopyUtils.copy("file".getBytes(), classFile); FileCopyUtils.copy("file".getBytes(), classFile);
Thread.sleep(1000); Thread.sleep(1000);
List<ClassPathChangedEvent> events = context.getBean(Listener.class).getEvents(); List<ClassPathChangedEvent> events = context.getBean(Listener.class).getEvents();
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -49,29 +49,29 @@ class PatternClassPathRestartStrategyTests { ...@@ -49,29 +49,29 @@ class PatternClassPathRestartStrategyTests {
void singlePattern() { void singlePattern() {
ClassPathRestartStrategy strategy = createStrategy("static/**"); ClassPathRestartStrategy strategy = createStrategy("static/**");
assertRestartRequired(strategy, "static/file.txt", false); assertRestartRequired(strategy, "static/file.txt", false);
assertRestartRequired(strategy, "static/folder/file.txt", false); assertRestartRequired(strategy, "static/directory/file.txt", false);
assertRestartRequired(strategy, "public/file.txt", true); assertRestartRequired(strategy, "public/file.txt", true);
assertRestartRequired(strategy, "public/folder/file.txt", true); assertRestartRequired(strategy, "public/directory/file.txt", true);
} }
@Test @Test
void multiplePatterns() { void multiplePatterns() {
ClassPathRestartStrategy strategy = createStrategy("static/**,public/**"); ClassPathRestartStrategy strategy = createStrategy("static/**,public/**");
assertRestartRequired(strategy, "static/file.txt", false); assertRestartRequired(strategy, "static/file.txt", false);
assertRestartRequired(strategy, "static/folder/file.txt", false); assertRestartRequired(strategy, "static/directory/file.txt", false);
assertRestartRequired(strategy, "public/file.txt", false); assertRestartRequired(strategy, "public/file.txt", false);
assertRestartRequired(strategy, "public/folder/file.txt", false); assertRestartRequired(strategy, "public/directory/file.txt", false);
assertRestartRequired(strategy, "src/file.txt", true); assertRestartRequired(strategy, "src/file.txt", true);
assertRestartRequired(strategy, "src/folder/file.txt", true); assertRestartRequired(strategy, "src/directory/file.txt", true);
} }
@Test @Test
void pomChange() { void pomChange() {
ClassPathRestartStrategy strategy = createStrategy("META-INF/maven/**"); ClassPathRestartStrategy strategy = createStrategy("META-INF/maven/**");
assertRestartRequired(strategy, "pom.xml", true); assertRestartRequired(strategy, "pom.xml", true);
String mavenFolder = "META-INF/maven/org.springframework.boot/spring-boot-devtools"; String mavenDirectory = "META-INF/maven/org.springframework.boot/spring-boot-devtools";
assertRestartRequired(strategy, mavenFolder + "/pom.xml", false); assertRestartRequired(strategy, mavenDirectory + "/pom.xml", false);
assertRestartRequired(strategy, mavenFolder + "/pom.properties", false); assertRestartRequired(strategy, mavenDirectory + "/pom.properties", false);
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -55,7 +55,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -55,7 +55,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadsPropertiesFromHomeFolderUsingProperties() throws Exception { void loadsPropertiesFromHomeDirectoryUsingProperties() throws Exception {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("abc", "def"); properties.put("abc", "def");
writeFile(properties, ".spring-boot-devtools.properties"); writeFile(properties, ".spring-boot-devtools.properties");
...@@ -64,7 +64,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -64,7 +64,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadsPropertiesFromConfigFolderUsingProperties() throws Exception { void loadsPropertiesFromConfigDirectoryUsingProperties() throws Exception {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("abc", "def"); properties.put("abc", "def");
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.properties")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.properties"));
...@@ -75,7 +75,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -75,7 +75,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadsPropertiesFromConfigFolderUsingYml() throws Exception { void loadsPropertiesFromConfigDirectoryUsingYml() throws Exception {
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yml")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yml"));
File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile(); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath()); byte[] content = Files.readAllBytes(file.toPath());
...@@ -86,7 +86,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -86,7 +86,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadsPropertiesFromConfigFolderUsingYaml() throws Exception { void loadsPropertiesFromConfigDirectoryUsingYaml() throws Exception {
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml"));
File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile(); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath()); byte[] content = Files.readAllBytes(file.toPath());
...@@ -97,7 +97,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -97,7 +97,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadFromConfigFolderWithPropertiesTakingPrecedence() throws Exception { void loadFromConfigDirectoryWithPropertiesTakingPrecedence() throws Exception {
OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml")); OutputStream out = new FileOutputStream(new File(this.configDir, "spring-boot-devtools.yaml"));
File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile(); File file = new ClassPathResource("spring-devtools.yaml", getClass()).getFile();
byte[] content = Files.readAllBytes(file.toPath()); byte[] content = Files.readAllBytes(file.toPath());
...@@ -114,7 +114,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -114,7 +114,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadFromConfigFolderTakesPrecedenceOverHomeFolder() throws Exception { void loadFromConfigDirectoryTakesPrecedenceOverHomeDirectory() throws Exception {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("abc", "def"); properties.put("abc", "def");
properties.put("bar", "baz"); properties.put("bar", "baz");
...@@ -130,7 +130,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -130,7 +130,7 @@ class DevToolsHomePropertiesPostProcessorTests {
} }
@Test @Test
void loadFromConfigFolderWithYamlTakesPrecedenceOverHomeFolder() throws Exception { void loadFromConfigDirectoryWithYamlTakesPrecedenceOverHomeDirectory() throws Exception {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("abc.xyz", "jkl"); properties.put("abc.xyz", "jkl");
properties.put("bar", "baz"); properties.put("bar", "baz");
...@@ -173,7 +173,7 @@ class DevToolsHomePropertiesPostProcessorTests { ...@@ -173,7 +173,7 @@ class DevToolsHomePropertiesPostProcessorTests {
private class MockDevToolHomePropertiesPostProcessor extends DevToolsHomePropertiesPostProcessor { private class MockDevToolHomePropertiesPostProcessor extends DevToolsHomePropertiesPostProcessor {
@Override @Override
protected File getHomeFolder() { protected File getHomeDirectory() {
return DevToolsHomePropertiesPostProcessorTests.this.home; return DevToolsHomePropertiesPostProcessorTests.this.home;
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -37,45 +37,44 @@ class ChangedFileTests { ...@@ -37,45 +37,44 @@ class ChangedFileTests {
File tempDir; File tempDir;
@Test @Test
void sourceFolderMustNotBeNull() throws Exception { void sourceDirectoryMustNotBeNull() throws Exception {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> new ChangedFile(null, new File(this.tempDir, "file"), Type.ADD)) .isThrownBy(() -> new ChangedFile(null, new File(this.tempDir, "file"), Type.ADD))
.withMessageContaining("SourceFolder must not be null"); .withMessageContaining("SourceDirectory must not be null");
} }
@Test @Test
void fileMustNotBeNull() throws Exception { void fileMustNotBeNull() throws Exception {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> new ChangedFile(new File(this.tempDir, "folder"), null, Type.ADD)) .isThrownBy(() -> new ChangedFile(new File(this.tempDir, "directory"), null, Type.ADD))
.withMessageContaining("File must not be null"); .withMessageContaining("File must not be null");
} }
@Test @Test
void typeMustNotBeNull() throws Exception { void typeMustNotBeNull() throws Exception {
assertThatIllegalArgumentException() assertThatIllegalArgumentException().isThrownBy(
.isThrownBy( () -> new ChangedFile(new File(this.tempDir, "file"), new File(this.tempDir, "directory"), null))
() -> new ChangedFile(new File(this.tempDir, "file"), new File(this.tempDir, "folder"), null))
.withMessageContaining("Type must not be null"); .withMessageContaining("Type must not be null");
} }
@Test @Test
void getFile() throws Exception { void getFile() throws Exception {
File file = new File(this.tempDir, "file"); File file = new File(this.tempDir, "file");
ChangedFile changedFile = new ChangedFile(new File(this.tempDir, "folder"), file, Type.ADD); ChangedFile changedFile = new ChangedFile(new File(this.tempDir, "directory"), file, Type.ADD);
assertThat(changedFile.getFile()).isEqualTo(file); assertThat(changedFile.getFile()).isEqualTo(file);
} }
@Test @Test
void getType() throws Exception { void getType() throws Exception {
ChangedFile changedFile = new ChangedFile(new File(this.tempDir, "folder"), new File(this.tempDir, "file"), ChangedFile changedFile = new ChangedFile(new File(this.tempDir, "directory"), new File(this.tempDir, "file"),
Type.DELETE); Type.DELETE);
assertThat(changedFile.getType()).isEqualTo(Type.DELETE); assertThat(changedFile.getType()).isEqualTo(Type.DELETE);
} }
@Test @Test
void getRelativeName() throws Exception { void getRelativeName() throws Exception {
File subFolder = new File(this.tempDir, "A"); File subDirectory = new File(this.tempDir, "A");
File file = new File(subFolder, "B.txt"); File file = new File(subDirectory, "B.txt");
ChangedFile changedFile = new ChangedFile(this.tempDir, file, Type.ADD); ChangedFile changedFile = new ChangedFile(this.tempDir, file, Type.ADD);
assertThat(changedFile.getRelativeName()).isEqualTo("A/B.txt"); assertThat(changedFile.getRelativeName()).isEqualTo("A/B.txt");
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -31,72 +31,72 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -31,72 +31,72 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/** /**
* Tests for {@link FolderSnapshot}. * Tests for {@link DirectorySnapshot}.
* *
* @author Phillip Webb * @author Phillip Webb
*/ */
class FolderSnapshotTests { class DirectorySnapshotTests {
@TempDir @TempDir
File tempDir; File tempDir;
private File folder; private File directory;
private FolderSnapshot initialSnapshot; private DirectorySnapshot initialSnapshot;
@BeforeEach @BeforeEach
void setup() throws Exception { void setup() throws Exception {
this.folder = createTestFolderStructure(); this.directory = createTestDirectoryStructure();
this.initialSnapshot = new FolderSnapshot(this.folder); this.initialSnapshot = new DirectorySnapshot(this.directory);
} }
@Test @Test
void folderMustNotBeNull() { void directoryMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new FolderSnapshot(null)) assertThatIllegalArgumentException().isThrownBy(() -> new DirectorySnapshot(null))
.withMessageContaining("Folder must not be null"); .withMessageContaining("Directory must not be null");
} }
@Test @Test
void folderMustNotBeFile() throws Exception { void directoryMustNotBeFile() throws Exception {
File file = new File(this.tempDir, "file"); File file = new File(this.tempDir, "file");
file.createNewFile(); file.createNewFile();
assertThatIllegalArgumentException().isThrownBy(() -> new FolderSnapshot(file)) assertThatIllegalArgumentException().isThrownBy(() -> new DirectorySnapshot(file))
.withMessageContaining("Folder '" + file + "' must not be a file"); .withMessageContaining("Directory '" + file + "' must not be a file");
} }
@Test @Test
void folderDoesNotHaveToExist() throws Exception { void directoryDoesNotHaveToExist() throws Exception {
File file = new File(this.tempDir, "does/not/exist"); File file = new File(this.tempDir, "does/not/exist");
FolderSnapshot snapshot = new FolderSnapshot(file); DirectorySnapshot snapshot = new DirectorySnapshot(file);
assertThat(snapshot).isEqualTo(new FolderSnapshot(file)); assertThat(snapshot).isEqualTo(new DirectorySnapshot(file));
} }
@Test @Test
void equalsWhenNothingHasChanged() { void equalsWhenNothingHasChanged() {
FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); DirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);
assertThat(this.initialSnapshot).isEqualTo(updatedSnapshot); assertThat(this.initialSnapshot).isEqualTo(updatedSnapshot);
assertThat(this.initialSnapshot.hashCode()).isEqualTo(updatedSnapshot.hashCode()); assertThat(this.initialSnapshot.hashCode()).isEqualTo(updatedSnapshot.hashCode());
} }
@Test @Test
void notEqualsWhenAFileIsAdded() throws Exception { void notEqualsWhenAFileIsAdded() throws Exception {
new File(new File(this.folder, "folder1"), "newfile").createNewFile(); new File(new File(this.directory, "directory1"), "newfile").createNewFile();
FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); DirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);
assertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot); assertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot);
} }
@Test @Test
void notEqualsWhenAFileIsDeleted() { void notEqualsWhenAFileIsDeleted() {
new File(new File(this.folder, "folder1"), "file1").delete(); new File(new File(this.directory, "directory1"), "file1").delete();
FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); DirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);
assertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot); assertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot);
} }
@Test @Test
void notEqualsWhenAFileIsModified() throws Exception { void notEqualsWhenAFileIsModified() throws Exception {
File file1 = new File(new File(this.folder, "folder1"), "file1"); File file1 = new File(new File(this.directory, "directory1"), "file1");
FileCopyUtils.copy("updatedcontent".getBytes(), file1); FileCopyUtils.copy("updatedcontent".getBytes(), file1);
FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); DirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);
assertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot); assertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot);
} }
...@@ -107,30 +107,30 @@ class FolderSnapshotTests { ...@@ -107,30 +107,30 @@ class FolderSnapshotTests {
} }
@Test @Test
void getChangedFilesSnapshotMustBeTheSameSourceFolder() throws Exception { void getChangedFilesSnapshotMustBeTheSameSourceDirectory() throws Exception {
assertThatIllegalArgumentException().isThrownBy( assertThatIllegalArgumentException().isThrownBy(
() -> this.initialSnapshot.getChangedFiles(new FolderSnapshot(createTestFolderStructure()), null)) () -> this.initialSnapshot.getChangedFiles(new DirectorySnapshot(createTestDirectoryStructure()), null))
.withMessageContaining("Snapshot source folder must be '" + this.folder + "'"); .withMessageContaining("Snapshot source directory must be '" + this.directory + "'");
} }
@Test @Test
void getChangedFilesWhenNothingHasChanged() { void getChangedFilesWhenNothingHasChanged() {
FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); DirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);
this.initialSnapshot.getChangedFiles(updatedSnapshot, null); this.initialSnapshot.getChangedFiles(updatedSnapshot, null);
} }
@Test @Test
void getChangedFilesWhenAFileIsAddedAndDeletedAndChanged() throws Exception { void getChangedFilesWhenAFileIsAddedAndDeletedAndChanged() throws Exception {
File folder1 = new File(this.folder, "folder1"); File directory1 = new File(this.directory, "directory1");
File file1 = new File(folder1, "file1"); File file1 = new File(directory1, "file1");
File file2 = new File(folder1, "file2"); File file2 = new File(directory1, "file2");
File newFile = new File(folder1, "newfile"); File newFile = new File(directory1, "newfile");
FileCopyUtils.copy("updatedcontent".getBytes(), file1); FileCopyUtils.copy("updatedcontent".getBytes(), file1);
file2.delete(); file2.delete();
newFile.createNewFile(); newFile.createNewFile();
FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); DirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);
ChangedFiles changedFiles = this.initialSnapshot.getChangedFiles(updatedSnapshot, null); ChangedFiles changedFiles = this.initialSnapshot.getChangedFiles(updatedSnapshot, null);
assertThat(changedFiles.getSourceFolder()).isEqualTo(this.folder); assertThat(changedFiles.getSourceDirectory()).isEqualTo(this.directory);
assertThat(getChangedFile(changedFiles, file1).getType()).isEqualTo(Type.MODIFY); assertThat(getChangedFile(changedFiles, file1).getType()).isEqualTo(Type.MODIFY);
assertThat(getChangedFile(changedFiles, file2).getType()).isEqualTo(Type.DELETE); assertThat(getChangedFile(changedFiles, file2).getType()).isEqualTo(Type.DELETE);
assertThat(getChangedFile(changedFiles, newFile).getType()).isEqualTo(Type.ADD); assertThat(getChangedFile(changedFiles, newFile).getType()).isEqualTo(Type.ADD);
...@@ -145,12 +145,12 @@ class FolderSnapshotTests { ...@@ -145,12 +145,12 @@ class FolderSnapshotTests {
return null; return null;
} }
private File createTestFolderStructure() throws IOException { private File createTestDirectoryStructure() throws IOException {
File root = new File(this.tempDir, UUID.randomUUID().toString()); File root = new File(this.tempDir, UUID.randomUUID().toString());
File folder1 = new File(root, "folder1"); File directory1 = new File(root, "directory1");
folder1.mkdirs(); directory1.mkdirs();
FileCopyUtils.copy("abc".getBytes(), new File(folder1, "file1")); FileCopyUtils.copy("abc".getBytes(), new File(directory1, "file1"));
FileCopyUtils.copy("abc".getBytes(), new File(folder1, "file2")); FileCopyUtils.copy("abc".getBytes(), new File(directory1, "file2"));
return root; return root;
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -51,11 +51,11 @@ class FileSnapshotTests { ...@@ -51,11 +51,11 @@ class FileSnapshotTests {
} }
@Test @Test
void fileMustNotBeAFolder() throws Exception { void fileMustNotBeADirectory() throws Exception {
File file = new File(this.tempDir, "file"); File file = new File(this.tempDir, "file");
file.mkdir(); file.mkdir();
assertThatIllegalArgumentException().isThrownBy(() -> new FileSnapshot(file)) assertThatIllegalArgumentException().isThrownBy(() -> new FileSnapshot(file))
.withMessageContaining("File must not be a folder"); .withMessageContaining("File must not be a directory");
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -37,7 +37,7 @@ import org.springframework.boot.devtools.filewatch.ChangedFiles; ...@@ -37,7 +37,7 @@ import org.springframework.boot.devtools.filewatch.ChangedFiles;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;
import org.springframework.boot.devtools.test.MockClientHttpRequestFactory; import org.springframework.boot.devtools.test.MockClientHttpRequestFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.mock.http.client.MockClientHttpRequest; import org.springframework.mock.http.client.MockClientHttpRequest;
...@@ -91,33 +91,33 @@ class ClassPathChangeUploaderTests { ...@@ -91,33 +91,33 @@ class ClassPathChangeUploaderTests {
} }
@Test @Test
void sendsClassLoaderFiles(@TempDir File sourceFolder) throws Exception { void sendsClassLoaderFiles(@TempDir File sourceDirectory) throws Exception {
ClassPathChangedEvent event = createClassPathChangedEvent(sourceFolder); ClassPathChangedEvent event = createClassPathChangedEvent(sourceDirectory);
this.requestFactory.willRespond(HttpStatus.OK); this.requestFactory.willRespond(HttpStatus.OK);
this.uploader.onApplicationEvent(event); this.uploader.onApplicationEvent(event);
assertThat(this.requestFactory.getExecutedRequests()).hasSize(1); assertThat(this.requestFactory.getExecutedRequests()).hasSize(1);
MockClientHttpRequest request = this.requestFactory.getExecutedRequests().get(0); MockClientHttpRequest request = this.requestFactory.getExecutedRequests().get(0);
verifyUploadRequest(sourceFolder, request); verifyUploadRequest(sourceDirectory, request);
} }
@Test @Test
void retriesOnSocketException(@TempDir File sourceFolder) throws Exception { void retriesOnSocketException(@TempDir File sourceDirectory) throws Exception {
ClassPathChangedEvent event = createClassPathChangedEvent(sourceFolder); ClassPathChangedEvent event = createClassPathChangedEvent(sourceDirectory);
this.requestFactory.willRespond(new SocketException()); this.requestFactory.willRespond(new SocketException());
this.requestFactory.willRespond(HttpStatus.OK); this.requestFactory.willRespond(HttpStatus.OK);
this.uploader.onApplicationEvent(event); this.uploader.onApplicationEvent(event);
assertThat(this.requestFactory.getExecutedRequests()).hasSize(2); assertThat(this.requestFactory.getExecutedRequests()).hasSize(2);
verifyUploadRequest(sourceFolder, this.requestFactory.getExecutedRequests().get(1)); verifyUploadRequest(sourceDirectory, this.requestFactory.getExecutedRequests().get(1));
} }
private void verifyUploadRequest(File sourceFolder, MockClientHttpRequest request) private void verifyUploadRequest(File sourceDirectory, MockClientHttpRequest request)
throws IOException, ClassNotFoundException { throws IOException, ClassNotFoundException {
ClassLoaderFiles classLoaderFiles = deserialize(request.getBodyAsBytes()); ClassLoaderFiles classLoaderFiles = deserialize(request.getBodyAsBytes());
Collection<SourceFolder> sourceFolders = classLoaderFiles.getSourceFolders(); Collection<SourceDirectory> sourceDirectories = classLoaderFiles.getSourceDirectories();
assertThat(sourceFolders.size()).isEqualTo(1); assertThat(sourceDirectories.size()).isEqualTo(1);
SourceFolder classSourceFolder = sourceFolders.iterator().next(); SourceDirectory classSourceDirectory = sourceDirectories.iterator().next();
assertThat(classSourceFolder.getName()).isEqualTo(sourceFolder.getAbsolutePath()); assertThat(classSourceDirectory.getName()).isEqualTo(sourceDirectory.getAbsolutePath());
Iterator<ClassLoaderFile> classFiles = classSourceFolder.getFiles().iterator(); Iterator<ClassLoaderFile> classFiles = classSourceDirectory.getFiles().iterator();
assertClassFile(classFiles.next(), "File1", ClassLoaderFile.Kind.ADDED); assertClassFile(classFiles.next(), "File1", ClassLoaderFile.Kind.ADDED);
assertClassFile(classFiles.next(), "File2", ClassLoaderFile.Kind.MODIFIED); assertClassFile(classFiles.next(), "File2", ClassLoaderFile.Kind.MODIFIED);
assertClassFile(classFiles.next(), null, ClassLoaderFile.Kind.DELETED); assertClassFile(classFiles.next(), null, ClassLoaderFile.Kind.DELETED);
...@@ -129,21 +129,21 @@ class ClassPathChangeUploaderTests { ...@@ -129,21 +129,21 @@ class ClassPathChangeUploaderTests {
assertThat(file.getKind()).isEqualTo(kind); assertThat(file.getKind()).isEqualTo(kind);
} }
private ClassPathChangedEvent createClassPathChangedEvent(File sourceFolder) throws IOException { private ClassPathChangedEvent createClassPathChangedEvent(File sourceDirectory) throws IOException {
Set<ChangedFile> files = new LinkedHashSet<>(); Set<ChangedFile> files = new LinkedHashSet<>();
File file1 = createFile(sourceFolder, "File1"); File file1 = createFile(sourceDirectory, "File1");
File file2 = createFile(sourceFolder, "File2"); File file2 = createFile(sourceDirectory, "File2");
File file3 = createFile(sourceFolder, "File3"); File file3 = createFile(sourceDirectory, "File3");
files.add(new ChangedFile(sourceFolder, file1, Type.ADD)); files.add(new ChangedFile(sourceDirectory, file1, Type.ADD));
files.add(new ChangedFile(sourceFolder, file2, Type.MODIFY)); files.add(new ChangedFile(sourceDirectory, file2, Type.MODIFY));
files.add(new ChangedFile(sourceFolder, file3, Type.DELETE)); files.add(new ChangedFile(sourceDirectory, file3, Type.DELETE));
Set<ChangedFiles> changeSet = new LinkedHashSet<>(); Set<ChangedFiles> changeSet = new LinkedHashSet<>();
changeSet.add(new ChangedFiles(sourceFolder, files)); changeSet.add(new ChangedFiles(sourceDirectory, files));
return new ClassPathChangedEvent(this, changeSet, false); return new ClassPathChangedEvent(this, changeSet, false);
} }
private File createFile(File sourceFolder, String name) throws IOException { private File createFile(File sourceDirectory, String name) throws IOException {
File file = new File(sourceFolder, name); File file = new File(sourceDirectory, name);
FileCopyUtils.copy(name.getBytes(), file); FileCopyUtils.copy(name.getBytes(), file);
return file; return file;
} }
......
...@@ -46,7 +46,7 @@ class ChangeableUrlsTests { ...@@ -46,7 +46,7 @@ class ChangeableUrlsTests {
File tempDir; File tempDir;
@Test @Test
void folderUrl() throws Exception { void directoryUrl() throws Exception {
URL url = makeUrl("myproject"); URL url = makeUrl("myproject");
assertThat(ChangeableUrls.fromUrls(url).size()).isEqualTo(1); assertThat(ChangeableUrls.fromUrls(url).size()).isEqualTo(1);
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -83,25 +83,25 @@ class ClassLoaderFilesResourcePatternResolverTests { ...@@ -83,25 +83,25 @@ class ClassLoaderFilesResourcePatternResolverTests {
} }
@Test @Test
void getResourceWhenDeletedShouldReturnDeletedResource(@TempDir File folder) throws Exception { void getResourceWhenDeletedShouldReturnDeletedResource(@TempDir File directory) throws Exception {
File file = createFile(folder, "name.class"); File file = createFile(directory, "name.class");
this.files.addFile(folder.getName(), "name.class", new ClassLoaderFile(Kind.DELETED, null)); this.files.addFile(directory.getName(), "name.class", new ClassLoaderFile(Kind.DELETED, null));
Resource resource = this.resolver.getResource("file:" + file.getAbsolutePath()); Resource resource = this.resolver.getResource("file:" + file.getAbsolutePath());
assertThat(resource).isNotNull().isInstanceOf(DeletedClassLoaderFileResource.class); assertThat(resource).isNotNull().isInstanceOf(DeletedClassLoaderFileResource.class);
} }
@Test @Test
void getResourcesShouldReturnResources(@TempDir File folder) throws Exception { void getResourcesShouldReturnResources(@TempDir File directory) throws Exception {
createFile(folder, "name.class"); createFile(directory, "name.class");
Resource[] resources = this.resolver.getResources("file:" + folder.getAbsolutePath() + "/**"); Resource[] resources = this.resolver.getResources("file:" + directory.getAbsolutePath() + "/**");
assertThat(resources).isNotEmpty(); assertThat(resources).isNotEmpty();
} }
@Test @Test
void getResourcesWhenDeletedShouldFilterDeleted(@TempDir File folder) throws Exception { void getResourcesWhenDeletedShouldFilterDeleted(@TempDir File directory) throws Exception {
createFile(folder, "name.class"); createFile(directory, "name.class");
this.files.addFile(folder.getName(), "name.class", new ClassLoaderFile(Kind.DELETED, null)); this.files.addFile(directory.getName(), "name.class", new ClassLoaderFile(Kind.DELETED, null));
Resource[] resources = this.resolver.getResources("file:" + folder.getAbsolutePath() + "/**"); Resource[] resources = this.resolver.getResources("file:" + directory.getAbsolutePath() + "/**");
assertThat(resources).isEmpty(); assertThat(resources).isEmpty();
} }
...@@ -179,8 +179,8 @@ class ClassLoaderFilesResourcePatternResolverTests { ...@@ -179,8 +179,8 @@ class ClassLoaderFilesResourcePatternResolverTests {
return resolver; return resolver;
} }
private File createFile(File folder, String name) throws IOException { private File createFile(File directory, String name) throws IOException {
File file = new File(folder, name); File file = new File(directory, name);
FileCopyUtils.copy("test".getBytes(), file); FileCopyUtils.copy("test".getBytes(), file);
return file; return file;
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -25,7 +25,7 @@ import java.util.Iterator; ...@@ -25,7 +25,7 @@ import java.util.Iterator;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;
import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceFolder; import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
...@@ -79,18 +79,18 @@ class ClassLoaderFilesTests { ...@@ -79,18 +79,18 @@ class ClassLoaderFilesTests {
} }
@Test @Test
void addTwiceInDifferentSourceFolders() { void addTwiceInDifferentSourceDirectories() {
ClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]); ClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]);
ClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]); ClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);
this.files.addFile("a", "myfile", file1); this.files.addFile("a", "myfile", file1);
this.files.addFile("b", "myfile", file2); this.files.addFile("b", "myfile", file2);
assertThat(this.files.getFile("myfile")).isEqualTo(file2); assertThat(this.files.getFile("myfile")).isEqualTo(file2);
assertThat(this.files.getOrCreateSourceFolder("a").getFiles().size()).isEqualTo(0); assertThat(this.files.getOrCreateSourceDirectory("a").getFiles().size()).isEqualTo(0);
assertThat(this.files.getOrCreateSourceFolder("b").getFiles().size()).isEqualTo(1); assertThat(this.files.getOrCreateSourceDirectory("b").getFiles().size()).isEqualTo(1);
} }
@Test @Test
void getSourceFolders() { void getSourceDirectories() {
ClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]); ClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]);
ClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]); ClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);
ClassLoaderFile file3 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]); ClassLoaderFile file3 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);
...@@ -99,14 +99,14 @@ class ClassLoaderFilesTests { ...@@ -99,14 +99,14 @@ class ClassLoaderFilesTests {
this.files.addFile("a", "myfile2", file2); this.files.addFile("a", "myfile2", file2);
this.files.addFile("b", "myfile3", file3); this.files.addFile("b", "myfile3", file3);
this.files.addFile("b", "myfile4", file4); this.files.addFile("b", "myfile4", file4);
Iterator<SourceFolder> sourceFolders = this.files.getSourceFolders().iterator(); Iterator<SourceDirectory> sourceDirectories = this.files.getSourceDirectories().iterator();
SourceFolder sourceFolder1 = sourceFolders.next(); SourceDirectory sourceDirectory1 = sourceDirectories.next();
SourceFolder sourceFolder2 = sourceFolders.next(); SourceDirectory sourceDirectory2 = sourceDirectories.next();
assertThat(sourceFolders.hasNext()).isFalse(); assertThat(sourceDirectories.hasNext()).isFalse();
assertThat(sourceFolder1.getName()).isEqualTo("a"); assertThat(sourceDirectory1.getName()).isEqualTo("a");
assertThat(sourceFolder2.getName()).isEqualTo("b"); assertThat(sourceDirectory2.getName()).isEqualTo("b");
assertThat(sourceFolder1.getFiles()).containsOnly(file1, file2); assertThat(sourceDirectory1.getFiles()).containsOnly(file1, file2);
assertThat(sourceFolder2.getFiles()).containsOnly(file3, file4); assertThat(sourceDirectory2.getFiles()).containsOnly(file3, file4);
} }
@Test @Test
...@@ -132,13 +132,13 @@ class ClassLoaderFilesTests { ...@@ -132,13 +132,13 @@ class ClassLoaderFilesTests {
toAdd.addFile("a", "myfile2", file2); toAdd.addFile("a", "myfile2", file2);
toAdd.addFile("b", "myfile3", file3); toAdd.addFile("b", "myfile3", file3);
this.files.addAll(toAdd); this.files.addAll(toAdd);
Iterator<SourceFolder> sourceFolders = this.files.getSourceFolders().iterator(); Iterator<SourceDirectory> sourceDirectoryies = this.files.getSourceDirectories().iterator();
SourceFolder sourceFolder1 = sourceFolders.next(); SourceDirectory sourceDirectory1 = sourceDirectoryies.next();
SourceFolder sourceFolder2 = sourceFolders.next(); SourceDirectory sourceDirectory2 = sourceDirectoryies.next();
assertThat(sourceFolders.hasNext()).isFalse(); assertThat(sourceDirectoryies.hasNext()).isFalse();
assertThat(sourceFolder1.getName()).isEqualTo("a"); assertThat(sourceDirectory1.getName()).isEqualTo("a");
assertThat(sourceFolder2.getName()).isEqualTo("b"); assertThat(sourceDirectory2.getName()).isEqualTo("b");
assertThat(sourceFolder1.getFiles()).containsOnly(file1, file2); assertThat(sourceDirectory1.getFiles()).containsOnly(file1, file2);
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -27,11 +27,11 @@ import org.junit.jupiter.api.Test; ...@@ -27,11 +27,11 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Tests for {@link DefaultSourceFolderUrlFilter}. * Tests for {@link DefaultSourceDirectoryUrlFilter}.
* *
* @author Phillip Webb * @author Phillip Webb
*/ */
class DefaultSourceFolderUrlFilterTests { class DefaultSourceDirectoryUrlFilterTests {
private static final String SOURCE_ROOT = "/Users/me/code/some-root/"; private static final String SOURCE_ROOT = "/Users/me/code/some-root/";
...@@ -52,33 +52,33 @@ class DefaultSourceFolderUrlFilterTests { ...@@ -52,33 +52,33 @@ class DefaultSourceFolderUrlFilterTests {
COMMON_POSTFIXES = Collections.unmodifiableList(postfixes); COMMON_POSTFIXES = Collections.unmodifiableList(postfixes);
} }
private DefaultSourceFolderUrlFilter filter = new DefaultSourceFolderUrlFilter(); private DefaultSourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();
@Test @Test
void mavenSourceFolder() throws Exception { void mavenSourceDirectory() throws Exception {
doTest("my-module/target/classes/"); doTest("my-module/target/classes/");
} }
@Test @Test
void gradleEclipseSourceFolder() throws Exception { void gradleEclipseSourceDirectory() throws Exception {
doTest("my-module/bin/"); doTest("my-module/bin/");
} }
@Test @Test
void unusualSourceFolder() throws Exception { void unusualSourceDirectory() throws Exception {
doTest("my-module/something/quite/quite/mad/"); doTest("my-module/something/quite/quite/mad/");
} }
@Test @Test
void skippedProjects() throws Exception { void skippedProjects() throws Exception {
String sourceFolder = "/Users/me/code/spring-boot-samples/spring-boot-sample-devtools"; String sourceDirectory = "/Users/me/code/spring-boot-samples/spring-boot-sample-devtools";
URL jarUrl = new URL("jar:file:/Users/me/tmp/spring-boot-sample-devtools-1.3.0.BUILD-SNAPSHOT.jar!/"); URL jarUrl = new URL("jar:file:/Users/me/tmp/spring-boot-sample-devtools-1.3.0.BUILD-SNAPSHOT.jar!/");
assertThat(this.filter.isMatch(sourceFolder, jarUrl)).isTrue(); assertThat(this.filter.isMatch(sourceDirectory, jarUrl)).isTrue();
URL nestedJarUrl = new URL("jar:file:/Users/me/tmp/spring-boot-sample-devtools-1.3.0.BUILD-SNAPSHOT.jar!/" URL nestedJarUrl = new URL("jar:file:/Users/me/tmp/spring-boot-sample-devtools-1.3.0.BUILD-SNAPSHOT.jar!/"
+ "lib/spring-boot-1.3.0.BUILD-SNAPSHOT.jar!/"); + "lib/spring-boot-1.3.0.BUILD-SNAPSHOT.jar!/");
assertThat(this.filter.isMatch(sourceFolder, nestedJarUrl)).isFalse(); assertThat(this.filter.isMatch(sourceDirectory, nestedJarUrl)).isFalse();
URL fileUrl = new URL("file:/Users/me/tmp/spring-boot-sample-devtools-1.3.0.BUILD-SNAPSHOT.jar"); URL fileUrl = new URL("file:/Users/me/tmp/spring-boot-sample-devtools-1.3.0.BUILD-SNAPSHOT.jar");
assertThat(this.filter.isMatch(sourceFolder, fileUrl)).isTrue(); assertThat(this.filter.isMatch(sourceDirectory, fileUrl)).isTrue();
} }
private void doTest(String sourcePostfix) throws MalformedURLException { private void doTest(String sourcePostfix) throws MalformedURLException {
...@@ -89,11 +89,11 @@ class DefaultSourceFolderUrlFilterTests { ...@@ -89,11 +89,11 @@ class DefaultSourceFolderUrlFilterTests {
} }
private void doTest(String sourcePostfix, String moduleRoot, boolean expected) throws MalformedURLException { private void doTest(String sourcePostfix, String moduleRoot, boolean expected) throws MalformedURLException {
String sourceFolder = SOURCE_ROOT + sourcePostfix; String sourceDirectory = SOURCE_ROOT + sourcePostfix;
for (String postfix : COMMON_POSTFIXES) { for (String postfix : COMMON_POSTFIXES) {
for (URL url : getUrls(moduleRoot + postfix)) { for (URL url : getUrls(moduleRoot + postfix)) {
boolean match = this.filter.isMatch(sourceFolder, url); boolean match = this.filter.isMatch(sourceDirectory, url);
assertThat(match).as(url + " against " + sourceFolder).isEqualTo(expected); assertThat(match).as(url + " against " + sourceDirectory).isEqualTo(expected);
} }
} }
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -62,9 +62,9 @@ class HttpRestartServerTests { ...@@ -62,9 +62,9 @@ class HttpRestartServerTests {
} }
@Test @Test
void sourceFolderUrlFilterMustNotBeNull() { void sourceDirectoryUrlFilterMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((SourceFolderUrlFilter) null)) assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((SourceDirectoryUrlFilter) null))
.withMessageContaining("SourceFolderUrlFilter must not be null"); .withMessageContaining("SourceDirectoryUrlFilter must not be null");
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -43,9 +43,9 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException ...@@ -43,9 +43,9 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
class RestartServerTests { class RestartServerTests {
@Test @Test
void sourceFolderUrlFilterMustNotBeNull() { void sourceDirectoryUrlFilterMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new RestartServer((SourceFolderUrlFilter) null)) assertThatIllegalArgumentException().isThrownBy(() -> new RestartServer((SourceDirectoryUrlFilter) null))
.withMessageContaining("SourceFolderUrlFilter must not be null"); .withMessageContaining("SourceDirectoryUrlFilter must not be null");
} }
@Test @Test
...@@ -56,7 +56,7 @@ class RestartServerTests { ...@@ -56,7 +56,7 @@ class RestartServerTests {
URL url4 = new URL("file:/proj/module-d.jar!/"); URL url4 = new URL("file:/proj/module-d.jar!/");
URLClassLoader classLoaderA = new URLClassLoader(new URL[] { url1, url2 }); URLClassLoader classLoaderA = new URLClassLoader(new URL[] { url1, url2 });
URLClassLoader classLoaderB = new URLClassLoader(new URL[] { url3, url4 }, classLoaderA); URLClassLoader classLoaderB = new URLClassLoader(new URL[] { url3, url4 }, classLoaderA);
SourceFolderUrlFilter filter = new DefaultSourceFolderUrlFilter(); SourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();
MockRestartServer server = new MockRestartServer(filter, classLoaderB); MockRestartServer server = new MockRestartServer(filter, classLoaderB);
ClassLoaderFiles files = new ClassLoaderFiles(); ClassLoaderFiles files = new ClassLoaderFiles();
ClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, new byte[0]); ClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, new byte[0]);
...@@ -70,14 +70,14 @@ class RestartServerTests { ...@@ -70,14 +70,14 @@ class RestartServerTests {
} }
@Test @Test
void updateSetsJarLastModified(@TempDir File folder) throws Exception { void updateSetsJarLastModified(@TempDir File directory) throws Exception {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
File jarFile = new File(folder, "module-a.jar"); File jarFile = new File(directory, "module-a.jar");
new FileOutputStream(jarFile).close(); new FileOutputStream(jarFile).close();
jarFile.setLastModified(0); jarFile.setLastModified(0);
URL url = jarFile.toURI().toURL(); URL url = jarFile.toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[] { url }); URLClassLoader classLoader = new URLClassLoader(new URL[] { url });
SourceFolderUrlFilter filter = new DefaultSourceFolderUrlFilter(); SourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();
MockRestartServer server = new MockRestartServer(filter, classLoader); MockRestartServer server = new MockRestartServer(filter, classLoader);
ClassLoaderFiles files = new ClassLoaderFiles(); ClassLoaderFiles files = new ClassLoaderFiles();
ClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, new byte[0]); ClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, new byte[0]);
...@@ -87,15 +87,15 @@ class RestartServerTests { ...@@ -87,15 +87,15 @@ class RestartServerTests {
} }
@Test @Test
void updateReplacesLocalFilesWhenPossible(@TempDir File folder) throws Exception { void updateReplacesLocalFilesWhenPossible(@TempDir File directory) throws Exception {
// This is critical for Cloud Foundry support where the application is // This is critical for Cloud Foundry support where the application is
// run exploded and resources can be found from the servlet root (outside of the // run exploded and resources can be found from the servlet root (outside of the
// classloader) // classloader)
File classFile = new File(folder, "ClassA.class"); File classFile = new File(directory, "ClassA.class");
FileCopyUtils.copy("abc".getBytes(), classFile); FileCopyUtils.copy("abc".getBytes(), classFile);
URL url = folder.toURI().toURL(); URL url = directory.toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[] { url }); URLClassLoader classLoader = new URLClassLoader(new URL[] { url });
SourceFolderUrlFilter filter = new DefaultSourceFolderUrlFilter(); SourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();
MockRestartServer server = new MockRestartServer(filter, classLoader); MockRestartServer server = new MockRestartServer(filter, classLoader);
ClassLoaderFiles files = new ClassLoaderFiles(); ClassLoaderFiles files = new ClassLoaderFiles();
ClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, "def".getBytes()); ClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, "def".getBytes());
...@@ -106,8 +106,8 @@ class RestartServerTests { ...@@ -106,8 +106,8 @@ class RestartServerTests {
static class MockRestartServer extends RestartServer { static class MockRestartServer extends RestartServer {
MockRestartServer(SourceFolderUrlFilter sourceFolderUrlFilter, ClassLoader classLoader) { MockRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter, ClassLoader classLoader) {
super(sourceFolderUrlFilter, classLoader); super(sourceDirectoryUrlFilter, classLoader);
} }
private Set<URL> restartUrls; private Set<URL> restartUrls;
......
...@@ -89,7 +89,7 @@ Any dependencies that are required when running embedded but are not required wh ...@@ -89,7 +89,7 @@ Any dependencies that are required when running embedded but are not required wh
[[executable-jar-war-index-files]] [[executable-jar-war-index-files]]
=== Index Files === Index Files
Spring Boot Loader-compatible jar and war archives can include additional index files under the `BOOT-INF/` folder. Spring Boot Loader-compatible jar and war archives can include additional index files under the `BOOT-INF/` directory.
A `classpath.idx` file can be provided for both jars and wars, it provides the ordering that jars should be added to the classpath. A `classpath.idx` file can be provided for both jars and wars, it provides the ordering that jars should be added to the classpath.
The `layers.idx` file can be used only for jars, it allows a jar to be split into logical layers for Docker/OCI image creation. The `layers.idx` file can be used only for jars, it allows a jar to be split into logical layers for Docker/OCI image creation.
...@@ -101,7 +101,7 @@ These files, however, are _not_ parsed internally as YAML and they must be writt ...@@ -101,7 +101,7 @@ These files, however, are _not_ parsed internally as YAML and they must be writt
[[executable-jar-war-index-files-classpath]] [[executable-jar-war-index-files-classpath]]
=== Classpath Index === Classpath Index
The classpath index file can be provided in `BOOT-INF/classpath.idx`. The classpath index file can be provided in `BOOT-INF/classpath.idx`.
It provides a list of jar names (not including the folder) in the order that they should be added to the classpath. It provides a list of jar names (not including the directory) in the order that they should be added to the classpath.
Each line must start with dash space (`"-&#183;"`) and names must be in double quotes. Each line must start with dash space (`"-&#183;"`) and names must be in double quotes.
For example, given the following jar: For example, given the following jar:
...@@ -136,9 +136,9 @@ The classpath index file can be provided in `BOOT-INF/layers.idx`. ...@@ -136,9 +136,9 @@ The classpath index file can be provided in `BOOT-INF/layers.idx`.
It provides a list of layers and the parts of the jar that should be contained within them. It provides a list of layers and the parts of the jar that should be contained within them.
Layers are written in the order that they should be added to the Docker/OCI image. Layers are written in the order that they should be added to the Docker/OCI image.
Layers names are written as quoted strings prefixed with dash space (`"-&#183;"`) and with a colon (`":"`) suffix. Layers names are written as quoted strings prefixed with dash space (`"-&#183;"`) and with a colon (`":"`) suffix.
Layer content is either a file or folder name written as a quoted string prefixed by space space dash space (`"&#183;&#183;-&#183;"`). Layer content is either a file or directory name written as a quoted string prefixed by space space dash space (`"&#183;&#183;-&#183;"`).
A folder name ends with `/`, a file name does not. A directory name ends with `/`, a file name does not.
When a folder name is used it means that all files inside that folder are in the same layer. When a directory name is used it means that all files inside that directory are in the same layer.
A typical example of a layers index would be: A typical example of a layers index would be:
......
...@@ -51,7 +51,7 @@ You need to remember to start Ant using the `-lib` option, as shown in the follo ...@@ -51,7 +51,7 @@ You need to remember to start Ant using the `-lib` option, as shown in the follo
[indent=0,subs="verbatim,quotes,attributes"] [indent=0,subs="verbatim,quotes,attributes"]
---- ----
$ ant -lib <folder containing spring-boot-antlib-{spring-boot-version}.jar> $ ant -lib <directory containing spring-boot-antlib-{spring-boot-version}.jar>
---- ----
TIP: The "`Using Spring Boot`" section includes a more complete example of <<using-spring-boot.adoc#using-boot-ant, using Apache Ant with `spring-boot-antlib`>>. TIP: The "`Using Spring Boot`" section includes a more complete example of <<using-spring-boot.adoc#using-boot-ant, using Apache Ant with `spring-boot-antlib`>>.
......
...@@ -365,8 +365,8 @@ Before we begin, open a terminal and run the following commands to ensure that y ...@@ -365,8 +365,8 @@ Before we begin, open a terminal and run the following commands to ensure that y
Java version: 1.8.0_102, vendor: Oracle Corporation Java version: 1.8.0_102, vendor: Oracle Corporation
---- ----
NOTE: This sample needs to be created in its own folder. NOTE: This sample needs to be created in its own directory.
Subsequent instructions assume that you have created a suitable folder and that it is your current directory. Subsequent instructions assume that you have created a suitable directory and that it is your current directory.
...@@ -481,7 +481,7 @@ If you run `mvn dependency:tree` again, you see that there are now a number of a ...@@ -481,7 +481,7 @@ If you run `mvn dependency:tree` again, you see that there are now a number of a
[[getting-started-first-application-code]] [[getting-started-first-application-code]]
=== Writing the Code === Writing the Code
To finish our application, we need to create a single Java file. To finish our application, we need to create a single Java file.
By default, Maven compiles sources from `src/main/java`, so you need to create that folder structure and then add a file named `src/main/java/Example.java` to contain the following code: By default, Maven compiles sources from `src/main/java`, so you need to create that directory structure and then add a file named `src/main/java/Example.java` to contain the following code:
[source,java,indent=0] [source,java,indent=0]
---- ----
......
...@@ -605,7 +605,7 @@ To enable that support, your application needs to have two additional dependenci ...@@ -605,7 +605,7 @@ To enable that support, your application needs to have two additional dependenci
Spring Boot ships by default with Tomcat 9.0.x which supports HTTP/2 out of the box when using JDK 9 or later. Spring Boot ships by default with Tomcat 9.0.x which supports HTTP/2 out of the box when using JDK 9 or later.
Alternatively, HTTP/2 can be used on JDK 8 if the `libtcnative` library and its dependencies are installed on the host operating system. Alternatively, HTTP/2 can be used on JDK 8 if the `libtcnative` library and its dependencies are installed on the host operating system.
The library folder must be made available, if not already, to the JVM library path. The library directory must be made available, if not already, to the JVM library path.
You can do so with a JVM argument such as `-Djava.library.path=/usr/local/opt/tomcat-native/lib`. You can do so with a JVM argument such as `-Djava.library.path=/usr/local/opt/tomcat-native/lib`.
More on this in the https://tomcat.apache.org/tomcat-9.0-doc/apr.html[official Tomcat documentation]. More on this in the https://tomcat.apache.org/tomcat-9.0-doc/apr.html[official Tomcat documentation].
...@@ -2019,7 +2019,7 @@ Spring Boot supports two higher-level migration tools: https://flywaydb.org/[Fly ...@@ -2019,7 +2019,7 @@ Spring Boot supports two higher-level migration tools: https://flywaydb.org/[Fly
To automatically run Flyway database migrations on startup, add the `org.flywaydb:flyway-core` to your classpath. To automatically run Flyway database migrations on startup, add the `org.flywaydb:flyway-core` to your classpath.
Typically, migrations are scripts in the form `V<VERSION>__<NAME>.sql` (with `<VERSION>` an underscore-separated version, such as '`1`' or '`2_1`'). Typically, migrations are scripts in the form `V<VERSION>__<NAME>.sql` (with `<VERSION>` an underscore-separated version, such as '`1`' or '`2_1`').
By default, they are in a folder called `classpath:db/migration`, but you can modify that location by setting `spring.flyway.locations`. By default, they are in a directory called `classpath:db/migration`, but you can modify that location by setting `spring.flyway.locations`.
This is a comma-separated list of one or more `classpath:` or `filesystem:` locations. This is a comma-separated list of one or more `classpath:` or `filesystem:` locations.
For example, the following configuration would search for scripts in both the default classpath location and the `/opt/migration` directory: For example, the following configuration would search for scripts in both the default classpath location and the `/opt/migration` directory:
...@@ -2036,7 +2036,7 @@ Assume the following: ...@@ -2036,7 +2036,7 @@ Assume the following:
spring.flyway.locations=classpath:db/migration/{vendor} spring.flyway.locations=classpath:db/migration/{vendor}
---- ----
Rather than using `db/migration`, the preceding configuration sets the folder to use according to the type of the database (such as `db/migration/mysql` for MySQL). Rather than using `db/migration`, the preceding configuration sets the directory to use according to the type of the database (such as `db/migration/mysql` for MySQL).
The list of supported databases is available in {spring-boot-module-code}/jdbc/DatabaseDriver.java[`DatabaseDriver`]. The list of supported databases is available in {spring-boot-module-code}/jdbc/DatabaseDriver.java[`DatabaseDriver`].
Migrations can also be written in Java. Migrations can also be written in Java.
...@@ -2049,7 +2049,7 @@ Spring Boot calls `Flyway.migrate()` to perform the database migration. ...@@ -2049,7 +2049,7 @@ Spring Boot calls `Flyway.migrate()` to perform the database migration.
If you would like more control, provide a `@Bean` that implements {spring-boot-autoconfigure-module-code}/flyway/FlywayMigrationStrategy.java[`FlywayMigrationStrategy`]. If you would like more control, provide a `@Bean` that implements {spring-boot-autoconfigure-module-code}/flyway/FlywayMigrationStrategy.java[`FlywayMigrationStrategy`].
Flyway supports SQL and Java https://flywaydb.org/documentation/callbacks.html[callbacks]. Flyway supports SQL and Java https://flywaydb.org/documentation/callbacks.html[callbacks].
To use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` folder. To use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` directory.
To use Java-based callbacks, create one or more beans that implement `Callback`. To use Java-based callbacks, create one or more beans that implement `Callback`.
Any such beans are automatically registered with `Flyway`. Any such beans are automatically registered with `Flyway`.
They can be ordered by using `@Order` or by implementing `Ordered`. They can be ordered by using `@Order` or by implementing `Ordered`.
......
...@@ -447,7 +447,7 @@ Property values can be injected directly into your beans by using the `@Value` a ...@@ -447,7 +447,7 @@ Property values can be injected directly into your beans by using the `@Value` a
Spring Boot uses a very particular `PropertySource` order that is designed to allow sensible overriding of values. Spring Boot uses a very particular `PropertySource` order that is designed to allow sensible overriding of values.
Properties are considered in the following order: Properties are considered in the following order:
. <<using-spring-boot.adoc#using-boot-devtools-globalsettings,Devtools global settings properties>> in the `$HOME/.config/spring-boot` folder when devtools is active. . <<using-spring-boot.adoc#using-boot-devtools-globalsettings,Devtools global settings properties>> in the `$HOME/.config/spring-boot` directory when devtools is active.
. {spring-framework-api}/test/context/TestPropertySource.html[`@TestPropertySource`] annotations on your tests. . {spring-framework-api}/test/context/TestPropertySource.html[`@TestPropertySource`] annotations on your tests.
. `properties` attribute on your tests. . `properties` attribute on your tests.
Available on {spring-boot-test-module-api}/context/SpringBootTest.html[`@SpringBootTest`] and the <<boot-features-testing-spring-boot-applications-testing-autoconfigured-tests,test annotations for testing a particular slice of your application>>. Available on {spring-boot-test-module-api}/context/SpringBootTest.html[`@SpringBootTest`] and the <<boot-features-testing-spring-boot-applications-testing-autoconfigured-tests,test annotations for testing a particular slice of your application>>.
...@@ -2482,11 +2482,11 @@ In the preceding example, if `YourException` is thrown by a controller defined i ...@@ -2482,11 +2482,11 @@ In the preceding example, if `YourException` is thrown by a controller defined i
[[boot-features-error-handling-custom-error-pages]] [[boot-features-error-handling-custom-error-pages]]
===== Custom Error Pages ===== Custom Error Pages
If you want to display a custom HTML error page for a given status code, you can add a file to an `/error` folder. If you want to display a custom HTML error page for a given status code, you can add a file to an `/error` directory.
Error pages can either be static HTML (that is, added under any of the static resource folders) or be built by using templates. Error pages can either be static HTML (that is, added under any of the static resource directories) or be built by using templates.
The name of the file should be the exact status code or a series mask. The name of the file should be the exact status code or a series mask.
For example, to map `404` to a static HTML file, your folder structure would be as follows: For example, to map `404` to a static HTML file, your directory structure would be as follows:
[source,indent=0,subs="verbatim,quotes,attributes"] [source,indent=0,subs="verbatim,quotes,attributes"]
---- ----
...@@ -2501,7 +2501,7 @@ For example, to map `404` to a static HTML file, your folder structure would be ...@@ -2501,7 +2501,7 @@ For example, to map `404` to a static HTML file, your folder structure would be
+- <other public assets> +- <other public assets>
---- ----
To map all `5xx` errors by using a FreeMarker template, your folder structure would be as follows: To map all `5xx` errors by using a FreeMarker template, your directory structure would be as follows:
[source,indent=0,subs="verbatim,quotes,attributes"] [source,indent=0,subs="verbatim,quotes,attributes"]
---- ----
...@@ -2828,11 +2828,11 @@ For a more complete picture, you can also subclass `DefaultErrorWebExceptionHand ...@@ -2828,11 +2828,11 @@ For a more complete picture, you can also subclass `DefaultErrorWebExceptionHand
[[boot-features-webflux-error-handling-custom-error-pages]] [[boot-features-webflux-error-handling-custom-error-pages]]
===== Custom Error Pages ===== Custom Error Pages
If you want to display a custom HTML error page for a given status code, you can add a file to an `/error` folder. If you want to display a custom HTML error page for a given status code, you can add a file to an `/error` directory.
Error pages can either be static HTML (that is, added under any of the static resource folders) or built with templates. Error pages can either be static HTML (that is, added under any of the static resource directories) or built with templates.
The name of the file should be the exact status code or a series mask. The name of the file should be the exact status code or a series mask.
For example, to map `404` to a static HTML file, your folder structure would be as follows: For example, to map `404` to a static HTML file, your directory structure would be as follows:
[source,indent=0,subs="verbatim,quotes,attributes"] [source,indent=0,subs="verbatim,quotes,attributes"]
---- ----
...@@ -2847,7 +2847,7 @@ For example, to map `404` to a static HTML file, your folder structure would be ...@@ -2847,7 +2847,7 @@ For example, to map `404` to a static HTML file, your folder structure would be
+- <other public assets> +- <other public assets>
---- ----
To map all `5xx` errors by using a Mustache template, your folder structure would be as follows: To map all `5xx` errors by using a Mustache template, your directory structure would be as follows:
[source,indent=0,subs="verbatim,quotes,attributes"] [source,indent=0,subs="verbatim,quotes,attributes"]
---- ----
...@@ -8157,7 +8157,7 @@ Assuming the above `Dockerfile` is in the current directory, your docker image c ...@@ -8157,7 +8157,7 @@ Assuming the above `Dockerfile` is in the current directory, your docker image c
---- ----
This is a multi-stage dockerfile. This is a multi-stage dockerfile.
The builder stage extracts the folders that are needed later. The builder stage extracts the directories that are needed later.
Each of the `COPY` commands relates to the layers extracted by the jarmode. Each of the `COPY` commands relates to the layers extracted by the jarmode.
Of course, a Dockerfile can be written without using the jarmode. Of course, a Dockerfile can be written without using the jarmode.
......
...@@ -578,7 +578,7 @@ TIP: For a complete list of the properties that are applied by the devtools, see ...@@ -578,7 +578,7 @@ TIP: For a complete list of the properties that are applied by the devtools, see
=== Automatic Restart === Automatic Restart
Applications that use `spring-boot-devtools` automatically restart whenever files on the classpath change. Applications that use `spring-boot-devtools` automatically restart whenever files on the classpath change.
This can be a useful feature when working in an IDE, as it gives a very fast feedback loop for code changes. This can be a useful feature when working in an IDE, as it gives a very fast feedback loop for code changes.
By default, any entry on the classpath that points to a folder is monitored for changes. By default, any entry on the classpath that points to a directory is monitored for changes.
Note that certain resources, such as static assets and view templates, <<using-boot-devtools-restart-exclude, do not need to restart the application>>. Note that certain resources, such as static assets and view templates, <<using-boot-devtools-restart-exclude, do not need to restart the application>>.
.Triggering a restart .Triggering a restart
...@@ -767,7 +767,7 @@ If you start multiple applications from your IDE, only the first has LiveReload ...@@ -767,7 +767,7 @@ If you start multiple applications from your IDE, only the first has LiveReload
[[using-boot-devtools-globalsettings]] [[using-boot-devtools-globalsettings]]
=== Global Settings === Global Settings
You can configure global devtools settings by adding any of the following files to the `$HOME/.config/spring-boot` folder: You can configure global devtools settings by adding any of the following files to the `$HOME/.config/spring-boot` directory:
. `spring-boot-devtools.properties` . `spring-boot-devtools.properties`
. `spring-boot-devtools.yaml` . `spring-boot-devtools.yaml`
...@@ -782,7 +782,7 @@ For example, to configure restart to always use a <<using-boot-devtools-restart- ...@@ -782,7 +782,7 @@ For example, to configure restart to always use a <<using-boot-devtools-restart-
spring.devtools.restart.trigger-file=.reloadtrigger spring.devtools.restart.trigger-file=.reloadtrigger
---- ----
NOTE: If devtools configuration files are not found in `$HOME/.config/spring-boot`, the root of the `$HOME` folder 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.
[NOTE] [NOTE]
...@@ -807,7 +807,7 @@ If you observe such problems constantly, try increasing the `spring.devtools.res ...@@ -807,7 +807,7 @@ If you observe such problems constantly, try increasing the `spring.devtools.res
spring.devtools.restart.quiet-period=1s spring.devtools.restart.quiet-period=1s
---- ----
The monitored classpath folders are now polled every 2 seconds for changes, and a 1 second quiet period is maintained to make sure there are no additional class changes. The monitored classpath directories are now polled every 2 seconds for changes, and a 1 second quiet period is maintained to make sure there are no additional class changes.
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -41,7 +41,7 @@ public class SpringBootMockServletContext extends MockServletContext { ...@@ -41,7 +41,7 @@ public class SpringBootMockServletContext extends MockServletContext {
private final ResourceLoader resourceLoader; private final ResourceLoader resourceLoader;
private File emptyRootFolder; private File emptyRootDirectory;
public SpringBootMockServletContext(String resourceBasePath) { public SpringBootMockServletContext(String resourceBasePath) {
this(resourceBasePath, new FileSystemResourceLoader()); this(resourceBasePath, new FileSystemResourceLoader());
...@@ -91,16 +91,16 @@ public class SpringBootMockServletContext extends MockServletContext { ...@@ -91,16 +91,16 @@ public class SpringBootMockServletContext extends MockServletContext {
// Liquibase assumes that "/" always exists, if we don't have a directory // Liquibase assumes that "/" always exists, if we don't have a directory
// use a temporary location. // use a temporary location.
try { try {
if (this.emptyRootFolder == null) { if (this.emptyRootDirectory == null) {
synchronized (this) { synchronized (this) {
File tempFolder = File.createTempFile("spr", "servlet"); File tempDirectory = File.createTempFile("spr", "servlet");
tempFolder.delete(); tempDirectory.delete();
tempFolder.mkdirs(); tempDirectory.mkdirs();
tempFolder.deleteOnExit(); tempDirectory.deleteOnExit();
this.emptyRootFolder = tempFolder; this.emptyRootDirectory = tempDirectory;
} }
} }
return this.emptyRootFolder.toURI().toURL(); return this.emptyRootDirectory.toURI().toURL();
} }
catch (IOException ex) { catch (IOException ex) {
// Ignore // Ignore
......
...@@ -124,8 +124,8 @@ class Lifecycle implements Closeable { ...@@ -124,8 +124,8 @@ class Lifecycle implements Closeable {
private Phase detectPhase() { private Phase detectPhase() {
Phase phase = createPhase("detector"); Phase phase = createPhase("detector");
phase.withArgs("-app", Folder.APPLICATION); phase.withArgs("-app", Directory.APPLICATION);
phase.withArgs("-platform", Folder.PLATFORM); phase.withArgs("-platform", Directory.PLATFORM);
phase.withLogLevelArg(); phase.withLogLevelArg();
return phase; return phase;
} }
...@@ -133,10 +133,10 @@ class Lifecycle implements Closeable { ...@@ -133,10 +133,10 @@ class Lifecycle implements Closeable {
private Phase restorePhase() { private Phase restorePhase() {
Phase phase = createPhase("restorer"); Phase phase = createPhase("restorer");
phase.withDaemonAccess(); phase.withDaemonAccess();
phase.withArgs("-cache-dir", Folder.CACHE); phase.withArgs("-cache-dir", Directory.CACHE);
phase.withArgs("-layers", Folder.LAYERS); phase.withArgs("-layers", Directory.LAYERS);
phase.withLogLevelArg(); phase.withLogLevelArg();
phase.withBinds(this.buildCacheVolume, Folder.CACHE); phase.withBinds(this.buildCacheVolume, Directory.CACHE);
return phase; return phase;
} }
...@@ -148,18 +148,18 @@ class Lifecycle implements Closeable { ...@@ -148,18 +148,18 @@ class Lifecycle implements Closeable {
phase.withArgs("-skip-layers"); phase.withArgs("-skip-layers");
} }
phase.withArgs("-daemon"); phase.withArgs("-daemon");
phase.withArgs("-layers", Folder.LAYERS); phase.withArgs("-layers", Directory.LAYERS);
phase.withArgs("-cache-dir", Folder.CACHE); phase.withArgs("-cache-dir", Directory.CACHE);
phase.withArgs(this.request.getName()); phase.withArgs(this.request.getName());
phase.withBinds(this.buildCacheVolume, Folder.CACHE); phase.withBinds(this.buildCacheVolume, Directory.CACHE);
return phase; return phase;
} }
private Phase buildPhase() { private Phase buildPhase() {
Phase phase = createPhase("builder"); Phase phase = createPhase("builder");
phase.withArgs("-layers", Folder.LAYERS); phase.withArgs("-layers", Directory.LAYERS);
phase.withArgs("-app", Folder.APPLICATION); phase.withArgs("-app", Directory.APPLICATION);
phase.withArgs("-platform", Folder.PLATFORM); phase.withArgs("-platform", Directory.PLATFORM);
return phase; return phase;
} }
...@@ -168,14 +168,14 @@ class Lifecycle implements Closeable { ...@@ -168,14 +168,14 @@ class Lifecycle implements Closeable {
phase.withDaemonAccess(); phase.withDaemonAccess();
phase.withLogLevelArg(); phase.withLogLevelArg();
phase.withArgs("-image", this.runImageReference); phase.withArgs("-image", this.runImageReference);
phase.withArgs("-layers", Folder.LAYERS); phase.withArgs("-layers", Directory.LAYERS);
phase.withArgs("-app", Folder.APPLICATION); phase.withArgs("-app", Directory.APPLICATION);
phase.withArgs("-daemon"); phase.withArgs("-daemon");
phase.withArgs("-launch-cache", Folder.LAUNCH_CACHE); phase.withArgs("-launch-cache", Directory.LAUNCH_CACHE);
phase.withArgs("-cache-dir", Folder.CACHE); phase.withArgs("-cache-dir", Directory.CACHE);
phase.withArgs(this.request.getName()); phase.withArgs(this.request.getName());
phase.withBinds(this.launchCacheVolume, Folder.LAUNCH_CACHE); phase.withBinds(this.launchCacheVolume, Directory.LAUNCH_CACHE);
phase.withBinds(this.buildCacheVolume, Folder.CACHE); phase.withBinds(this.buildCacheVolume, Directory.CACHE);
return phase; return phase;
} }
...@@ -183,8 +183,8 @@ class Lifecycle implements Closeable { ...@@ -183,8 +183,8 @@ class Lifecycle implements Closeable {
boolean verboseLogging = this.request.isVerboseLogging() boolean verboseLogging = this.request.isVerboseLogging()
&& this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION); && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION);
Phase phase = new Phase(name, verboseLogging); Phase phase = new Phase(name, verboseLogging);
phase.withBinds(this.layersVolume, Folder.LAYERS); phase.withBinds(this.layersVolume, Directory.LAYERS);
phase.withBinds(this.applicationVolume, Folder.APPLICATION); phase.withBinds(this.applicationVolume, Directory.APPLICATION);
return phase; return phase;
} }
...@@ -211,7 +211,8 @@ class Lifecycle implements Closeable { ...@@ -211,7 +211,8 @@ class Lifecycle implements Closeable {
} }
try { try {
TarArchive applicationContent = this.request.getApplicationContent(this.builder.getBuildOwner()); TarArchive applicationContent = this.request.getApplicationContent(this.builder.getBuildOwner());
return this.docker.container().create(config, ContainerContent.of(applicationContent, Folder.APPLICATION)); return this.docker.container().create(config,
ContainerContent.of(applicationContent, Directory.APPLICATION));
} }
finally { finally {
this.applicationVolumePopulated = true; this.applicationVolumePopulated = true;
...@@ -229,13 +230,13 @@ class Lifecycle implements Closeable { ...@@ -229,13 +230,13 @@ class Lifecycle implements Closeable {
} }
/** /**
* Common folders used by the various phases. * Common directories used by the various phases.
*/ */
private static class Folder { private static class Directory {
/** /**
* The folder used by buildpacks to write their layer contributions. A new layer * The directory used by buildpacks to write their layer contributions. A new
* folder is created for each lifecycle execution. * layer directory is created for each lifecycle execution.
* <p> * <p>
* Maps to the {@code <layers...>} concept in the * Maps to the {@code <layers...>} concept in the
* <a href="https://github.com/buildpacks/spec/blob/master/buildpack.md">buildpack * <a href="https://github.com/buildpacks/spec/blob/master/buildpack.md">buildpack
...@@ -245,8 +246,8 @@ class Lifecycle implements Closeable { ...@@ -245,8 +246,8 @@ class Lifecycle implements Closeable {
static final String LAYERS = "/layers"; static final String LAYERS = "/layers";
/** /**
* The folder containing the original contributed application. A new application * The directory containing the original contributed application. A new
* folder is created for each lifecycle execution. * application directory is created for each lifecycle execution.
* <p> * <p>
* Maps to the {@code <app...>} concept in the * Maps to the {@code <app...>} concept in the
* <a href="https://github.com/buildpacks/spec/blob/master/buildpack.md">buildpack * <a href="https://github.com/buildpacks/spec/blob/master/buildpack.md">buildpack
...@@ -255,15 +256,15 @@ class Lifecycle implements Closeable { ...@@ -255,15 +256,15 @@ class Lifecycle implements Closeable {
* convention of using {@code '/workspace'}. * convention of using {@code '/workspace'}.
* <p> * <p>
* Note that application content is uploaded to the container with the first phase * Note that application content is uploaded to the container with the first phase
* that runs and saved in a volume that is passed to subsequent phases. The folder * that runs and saved in a volume that is passed to subsequent phases. The
* is mutable and buildpacks may modify the content. * directory is mutable and buildpacks may modify the content.
*/ */
static final String APPLICATION = "/workspace"; static final String APPLICATION = "/workspace";
/** /**
* The folder used by buildpacks to obtain environment variables and platform * The directory used by buildpacks to obtain environment variables and platform
* specific concerns. The platform folder is read-only and is created/populated by * specific concerns. The platform directory is read-only and is created/populated
* the {@link EphemeralBuilder}. * by the {@link EphemeralBuilder}.
* <p> * <p>
* Maps to the {@code <platform>/env} and {@code <platform>/#} concepts in the * Maps to the {@code <platform>/env} and {@code <platform>/#} concepts in the
* <a href="https://github.com/buildpacks/spec/blob/master/buildpack.md">buildpack * <a href="https://github.com/buildpacks/spec/blob/master/buildpack.md">buildpack
...@@ -273,7 +274,7 @@ class Lifecycle implements Closeable { ...@@ -273,7 +274,7 @@ class Lifecycle implements Closeable {
static final String PLATFORM = "/platform"; static final String PLATFORM = "/platform";
/** /**
* The folder used by buildpacks for caching. The volume name is based on the * The directory used by buildpacks for caching. The volume name is based on the
* image {@link BuildRequest#getName() name} being built, and is persistent across * image {@link BuildRequest#getName() name} being built, and is persistent across
* invocations even if the application content has changed. * invocations even if the application content has changed.
* <p> * <p>
...@@ -283,7 +284,7 @@ class Lifecycle implements Closeable { ...@@ -283,7 +284,7 @@ class Lifecycle implements Closeable {
static final String CACHE = "/cache"; static final String CACHE = "/cache";
/** /**
* The folder used by buildpacks for launch related caching. The volume name is * The directory used by buildpacks for launch related caching. The volume name is
* based on the image {@link BuildRequest#getName() name} being built, and is * based on the image {@link BuildRequest#getName() name} being built, and is
* persistent across invocations even if the application content has changed. * persistent across invocations even if the application content has changed.
* <p> * <p>
......
...@@ -19,7 +19,7 @@ package org.springframework.boot.buildpack.platform.io; ...@@ -19,7 +19,7 @@ package org.springframework.boot.buildpack.platform.io;
import java.io.IOException; import java.io.IOException;
/** /**
* Interface that can be used to write a file/folder layout. * Interface that can be used to write a file/directory layout.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 2.3.0 * @since 2.3.0
...@@ -27,17 +27,17 @@ import java.io.IOException; ...@@ -27,17 +27,17 @@ import java.io.IOException;
public interface Layout { public interface Layout {
/** /**
* Add a folder to the content. * Add a directory to the content.
* @param name the full name of the folder to add. * @param name the full name of the directory to add.
* @param owner the owner of the folder * @param owner the owner of the directory
* @throws IOException on IO error * @throws IOException on IO error
*/ */
void folder(String name, Owner owner) throws IOException; void directory(String name, Owner owner) throws IOException;
/** /**
* Write a file to the content. * Write a file to the content.
* @param name the full name of the file to add. * @param name the full name of the file to add.
* @param owner the owner of the folder * @param owner the owner of the file
* @param content the content to add * @param content the content to add
* @throws IOException on IO error * @throws IOException on IO error
*/ */
......
...@@ -43,8 +43,8 @@ class TarLayoutWriter implements Layout, Closeable { ...@@ -43,8 +43,8 @@ class TarLayoutWriter implements Layout, Closeable {
} }
@Override @Override
public void folder(String name, Owner owner) throws IOException { public void directory(String name, Owner owner) throws IOException {
this.outputStream.putArchiveEntry(createFolderEntry(name, owner)); this.outputStream.putArchiveEntry(createDirectoryEntry(name, owner));
this.outputStream.closeArchiveEntry(); this.outputStream.closeArchiveEntry();
} }
...@@ -55,7 +55,7 @@ class TarLayoutWriter implements Layout, Closeable { ...@@ -55,7 +55,7 @@ class TarLayoutWriter implements Layout, Closeable {
this.outputStream.closeArchiveEntry(); this.outputStream.closeArchiveEntry();
} }
private TarArchiveEntry createFolderEntry(String name, Owner owner) { private TarArchiveEntry createDirectoryEntry(String name, Owner owner) {
return createEntry(name, owner, TarConstants.LF_DIR, 0755, 0); return createEntry(name, owner, TarConstants.LF_DIR, 0755, 0);
} }
......
...@@ -86,7 +86,7 @@ public class BuildRequestTests { ...@@ -86,7 +86,7 @@ public class BuildRequestTests {
} }
@Test @Test
void forJarFileWhenJarFileIsFolderThrowsException() { void forJarFileWhenJarFileIsDirectoryThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> BuildRequest.forJarFile(this.tempDir)) assertThatIllegalArgumentException().isThrownBy(() -> BuildRequest.forJarFile(this.tempDir))
.withMessage("JarFile must be a file"); .withMessage("JarFile must be a file");
} }
......
...@@ -111,8 +111,8 @@ class EphemeralBuilderTests extends AbstractJsonTests { ...@@ -111,8 +111,8 @@ class EphemeralBuilderTests extends AbstractJsonTests {
@Test @Test
void getArchiveContainsEnvLayer() throws Exception { void getArchiveContainsEnvLayer() throws Exception {
EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env); EphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.metadata, this.creator, this.env);
File folder = unpack(getLayer(builder.getArchive(), 0), "env"); File directory = unpack(getLayer(builder.getArchive(), 0), "env");
assertThat(new File(folder, "platform/env/spring")).usingCharset(StandardCharsets.UTF_8).hasContent("boot"); assertThat(new File(directory, "platform/env/spring")).usingCharset(StandardCharsets.UTF_8).hasContent("boot");
} }
private TarArchiveInputStream getLayer(ImageArchive archive, int index) throws Exception { private TarArchiveInputStream getLayer(ImageArchive archive, int index) throws Exception {
...@@ -126,11 +126,11 @@ class EphemeralBuilderTests extends AbstractJsonTests { ...@@ -126,11 +126,11 @@ class EphemeralBuilderTests extends AbstractJsonTests {
} }
private File unpack(TarArchiveInputStream archive, String name) throws Exception { private File unpack(TarArchiveInputStream archive, String name) throws Exception {
File folder = new File(this.temp, name); File directory = new File(this.temp, name);
folder.mkdirs(); directory.mkdirs();
ArchiveEntry entry = archive.getNextEntry(); ArchiveEntry entry = archive.getNextEntry();
while (entry != null) { while (entry != null) {
File file = new File(folder, entry.getName()); File file = new File(directory, entry.getName());
if (entry.isDirectory()) { if (entry.isDirectory()) {
file.mkdirs(); file.mkdirs();
} }
...@@ -142,7 +142,7 @@ class EphemeralBuilderTests extends AbstractJsonTests { ...@@ -142,7 +142,7 @@ class EphemeralBuilderTests extends AbstractJsonTests {
} }
entry = archive.getNextEntry(); entry = archive.getNextEntry();
} }
return folder; return directory;
} }
} }
...@@ -262,7 +262,7 @@ class DockerApiTests { ...@@ -262,7 +262,7 @@ class DockerApiTests {
ImageReference imageReference = ImageReference.of("ubuntu:bionic"); ImageReference imageReference = ImageReference.of("ubuntu:bionic");
ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash")); ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash"));
TarArchive archive = TarArchive.of((layout) -> { TarArchive archive = TarArchive.of((layout) -> {
layout.folder("/test", Owner.ROOT); layout.directory("/test", Owner.ROOT);
layout.file("/test/file", Owner.ROOT, Content.of("test")); layout.file("/test/file", Owner.ROOT, Content.of("test"));
}); });
ContainerContent content = ContainerContent.of(archive); ContainerContent content = ContainerContent.of(archive);
......
...@@ -44,7 +44,7 @@ class ImageArchiveTests extends AbstractJsonTests { ...@@ -44,7 +44,7 @@ class ImageArchiveTests extends AbstractJsonTests {
void fromImageWritesToValidArchiveTar() throws Exception { void fromImageWritesToValidArchiveTar() throws Exception {
Image image = Image.of(getContent("image.json")); Image image = Image.of(getContent("image.json"));
ImageArchive archive = ImageArchive.from(image, (update) -> { ImageArchive archive = ImageArchive.from(image, (update) -> {
update.withNewLayer(Layer.of((layout) -> layout.folder("/spring", Owner.ROOT))); update.withNewLayer(Layer.of((layout) -> layout.directory("/spring", Owner.ROOT)));
update.withTag(ImageReference.of("pack.local/builder/6b7874626575656b6162")); update.withTag(ImageReference.of("pack.local/builder/6b7874626575656b6162"));
}); });
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
......
...@@ -52,17 +52,17 @@ class LayerTests { ...@@ -52,17 +52,17 @@ class LayerTests {
@Test @Test
void ofCreatesLayer() throws Exception { void ofCreatesLayer() throws Exception {
Layer layer = Layer.of((layout) -> { Layer layer = Layer.of((layout) -> {
layout.folder("/folder", Owner.ROOT); layout.directory("/directory", Owner.ROOT);
layout.file("/folder/file", Owner.ROOT, Content.of("test")); layout.file("/directory/file", Owner.ROOT, Content.of("test"));
}); });
assertThat(layer.getId().toString()) assertThat(layer.getId().toString())
.isEqualTo("sha256:8b8a3cea2ba716da6bbb0a3bf7472f235fa08c71a27cec5fbf2de1cf1baa513f"); .isEqualTo("sha256:d03a34f73804698c875eb56ff694fc2fceccc69b645e4adceb004ed13588613b");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
layer.writeTo(outputStream); layer.writeTo(outputStream);
try (TarArchiveInputStream tarStream = new TarArchiveInputStream( try (TarArchiveInputStream tarStream = new TarArchiveInputStream(
new ByteArrayInputStream(outputStream.toByteArray()))) { new ByteArrayInputStream(outputStream.toByteArray()))) {
assertThat(tarStream.getNextTarEntry().getName()).isEqualTo("/folder/"); assertThat(tarStream.getNextTarEntry().getName()).isEqualTo("/directory/");
assertThat(tarStream.getNextTarEntry().getName()).isEqualTo("/folder/file"); assertThat(tarStream.getNextTarEntry().getName()).isEqualTo("/directory/file");
assertThat(tarStream.getNextTarEntry()).isNull(); assertThat(tarStream.getNextTarEntry()).isNull();
} }
} }
......
...@@ -46,12 +46,12 @@ class TarArchiveTests { ...@@ -46,12 +46,12 @@ class TarArchiveTests {
void ofWritesTarContent() throws Exception { void ofWritesTarContent() throws Exception {
Owner owner = Owner.of(123, 456); Owner owner = Owner.of(123, 456);
TarArchive tarArchive = TarArchive.of((content) -> { TarArchive tarArchive = TarArchive.of((content) -> {
content.folder("/workspace", owner); content.directory("/workspace", owner);
content.folder("/layers", owner); content.directory("/layers", owner);
content.folder("/cnb", Owner.ROOT); content.directory("/cnb", Owner.ROOT);
content.folder("/cnb/buildpacks", Owner.ROOT); content.directory("/cnb/buildpacks", Owner.ROOT);
content.folder("/platform", Owner.ROOT); content.directory("/platform", Owner.ROOT);
content.folder("/platform/env", Owner.ROOT); content.directory("/platform/env", Owner.ROOT);
}); });
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
tarArchive.writeTo(outputStream); tarArchive.writeTo(outputStream);
......
...@@ -38,21 +38,21 @@ class TarLayoutWriterTests { ...@@ -38,21 +38,21 @@ class TarLayoutWriterTests {
void writesTarArchive() throws Exception { void writesTarArchive() throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (TarLayoutWriter writer = new TarLayoutWriter(outputStream)) { try (TarLayoutWriter writer = new TarLayoutWriter(outputStream)) {
writer.folder("/foo", Owner.ROOT); writer.directory("/foo", Owner.ROOT);
writer.file("/foo/bar.txt", Owner.of(1, 1), Content.of("test")); writer.file("/foo/bar.txt", Owner.of(1, 1), Content.of("test"));
} }
try (TarArchiveInputStream tarInputStream = new TarArchiveInputStream( try (TarArchiveInputStream tarInputStream = new TarArchiveInputStream(
new ByteArrayInputStream(outputStream.toByteArray()))) { new ByteArrayInputStream(outputStream.toByteArray()))) {
TarArchiveEntry folderEntry = tarInputStream.getNextTarEntry(); TarArchiveEntry directoryEntry = tarInputStream.getNextTarEntry();
TarArchiveEntry fileEntry = tarInputStream.getNextTarEntry(); TarArchiveEntry fileEntry = tarInputStream.getNextTarEntry();
byte[] fileContent = new byte[(int) fileEntry.getSize()]; byte[] fileContent = new byte[(int) fileEntry.getSize()];
tarInputStream.read(fileContent); tarInputStream.read(fileContent);
assertThat(tarInputStream.getNextEntry()).isNull(); assertThat(tarInputStream.getNextEntry()).isNull();
assertThat(folderEntry.getName()).isEqualTo("/foo/"); assertThat(directoryEntry.getName()).isEqualTo("/foo/");
assertThat(folderEntry.getMode()).isEqualTo(0755); assertThat(directoryEntry.getMode()).isEqualTo(0755);
assertThat(folderEntry.getLongUserId()).isEqualTo(0); assertThat(directoryEntry.getLongUserId()).isEqualTo(0);
assertThat(folderEntry.getLongGroupId()).isEqualTo(0); assertThat(directoryEntry.getLongGroupId()).isEqualTo(0);
assertThat(folderEntry.getModTime()).isEqualTo(new Date(TarLayoutWriter.NORMALIZED_MOD_TIME)); assertThat(directoryEntry.getModTime()).isEqualTo(new Date(TarLayoutWriter.NORMALIZED_MOD_TIME));
assertThat(fileEntry.getName()).isEqualTo("/foo/bar.txt"); assertThat(fileEntry.getName()).isEqualTo("/foo/bar.txt");
assertThat(fileEntry.getMode()).isEqualTo(0644); assertThat(fileEntry.getMode()).isEqualTo(0644);
assertThat(fileEntry.getLongUserId()).isEqualTo(1); assertThat(fileEntry.getLongUserId()).isEqualTo(1);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -44,9 +44,9 @@ public class MetadataStore { ...@@ -44,9 +44,9 @@ public class MetadataStore {
private static final String ADDITIONAL_METADATA_PATH = "META-INF/additional-spring-configuration-metadata.json"; private static final String ADDITIONAL_METADATA_PATH = "META-INF/additional-spring-configuration-metadata.json";
private static final String RESOURCES_FOLDER = "resources"; private static final String RESOURCES_DIRECTORY = "resources";
private static final String CLASSES_FOLDER = "classes"; private static final String CLASSES_DIRECTORY = "classes";
private final ProcessingEnvironment environment; private final ProcessingEnvironment environment;
...@@ -122,18 +122,18 @@ public class MetadataStore { ...@@ -122,18 +122,18 @@ public class MetadataStore {
} }
} }
} }
return new File(locateGradleResourcesFolder(standardLocation), ADDITIONAL_METADATA_PATH); return new File(locateGradleResourcesDirectory(standardLocation), ADDITIONAL_METADATA_PATH);
} }
private File locateGradleResourcesFolder(File standardAdditionalMetadataLocation) throws FileNotFoundException { private File locateGradleResourcesDirectory(File standardAdditionalMetadataLocation) throws FileNotFoundException {
String path = standardAdditionalMetadataLocation.getPath(); String path = standardAdditionalMetadataLocation.getPath();
int index = path.lastIndexOf(CLASSES_FOLDER); int index = path.lastIndexOf(CLASSES_DIRECTORY);
if (index < 0) { if (index < 0) {
throw new FileNotFoundException(); throw new FileNotFoundException();
} }
String buildFolderPath = path.substring(0, index); String buildDirectoryPath = path.substring(0, index);
File classOutputLocation = standardAdditionalMetadataLocation.getParentFile().getParentFile(); File classOutputLocation = standardAdditionalMetadataLocation.getParentFile().getParentFile();
return new File(buildFolderPath, RESOURCES_FOLDER + '/' + classOutputLocation.getName()); return new File(buildDirectoryPath, RESOURCES_DIRECTORY + '/' + classOutputLocation.getName());
} }
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -203,9 +203,9 @@ class MergeMetadataGenerationTests extends AbstractMetadataGenerationTests { ...@@ -203,9 +203,9 @@ class MergeMetadataGenerationTests extends AbstractMetadataGenerationTests {
@Test @Test
void mergingOfAdditionalMetadata() throws Exception { void mergingOfAdditionalMetadata() throws Exception {
File metaInfFolder = new File(getCompiler().getOutputLocation(), "META-INF"); File metaInfDirectory = new File(getCompiler().getOutputLocation(), "META-INF");
metaInfFolder.mkdirs(); metaInfDirectory.mkdirs();
File additionalMetadataFile = new File(metaInfFolder, "additional-spring-configuration-metadata.json"); File additionalMetadataFile = new File(metaInfDirectory, "additional-spring-configuration-metadata.json");
additionalMetadataFile.createNewFile(); additionalMetadataFile.createNewFile();
JSONObject property = new JSONObject(); JSONObject property = new JSONObject();
property.put("name", "foo"); property.put("name", "foo");
...@@ -273,9 +273,9 @@ class MergeMetadataGenerationTests extends AbstractMetadataGenerationTests { ...@@ -273,9 +273,9 @@ class MergeMetadataGenerationTests extends AbstractMetadataGenerationTests {
} }
private File createAdditionalMetadataFile() throws IOException { private File createAdditionalMetadataFile() throws IOException {
File metaInfFolder = new File(getCompiler().getOutputLocation(), "META-INF"); File metaInfDirectory = new File(getCompiler().getOutputLocation(), "META-INF");
metaInfFolder.mkdirs(); metaInfDirectory.mkdirs();
File additionalMetadataFile = new File(metaInfFolder, "additional-spring-configuration-metadata.json"); File additionalMetadataFile = new File(metaInfDirectory, "additional-spring-configuration-metadata.json");
additionalMetadataFile.createNewFile(); additionalMetadataFile.createNewFile();
return additionalMetadataFile; return additionalMetadataFile;
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -56,19 +56,21 @@ public class TestProject { ...@@ -56,19 +56,21 @@ public class TestProject {
* Contains copies of the original source so we can modify it safely to test * Contains copies of the original source so we can modify it safely to test
* incremental builds. * incremental builds.
*/ */
private File sourceFolder; private File sourceDirectory;
private TestCompiler compiler; private TestCompiler compiler;
private Set<File> sourceFiles = new LinkedHashSet<>(); private Set<File> sourceFiles = new LinkedHashSet<>();
public TestProject(File tempFolder, Class<?>... classes) throws IOException { public TestProject(File tempDirectory, Class<?>... classes) throws IOException {
this.sourceFolder = new File(tempFolder, "src"); this.sourceDirectory = new File(tempDirectory, "src");
this.compiler = new TestCompiler(new File(tempFolder, "build")) { this.compiler = new TestCompiler(new File(tempDirectory, "build")) {
@Override @Override
protected File getSourceFolder() { protected File getSourceDirectory() {
return TestProject.this.sourceFolder; return TestProject.this.sourceDirectory;
} }
}; };
Set<Class<?>> contents = new HashSet<>(Arrays.asList(classes)); Set<Class<?>> contents = new HashSet<>(Arrays.asList(classes));
contents.addAll(Arrays.asList(ALWAYS_INCLUDE)); contents.addAll(Arrays.asList(ALWAYS_INCLUDE));
...@@ -90,14 +92,14 @@ public class TestProject { ...@@ -90,14 +92,14 @@ public class TestProject {
} }
public File getSourceFile(Class<?> type) { public File getSourceFile(Class<?> type) {
return new File(this.sourceFolder, TestCompiler.sourcePathFor(type)); return new File(this.sourceDirectory, TestCompiler.sourcePathFor(type));
} }
public ConfigurationMetadata fullBuild() { public ConfigurationMetadata fullBuild() {
TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor( TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor(
this.compiler.getOutputLocation()); this.compiler.getOutputLocation());
TestCompilationTask task = this.compiler.getTask(this.sourceFiles); TestCompilationTask task = this.compiler.getTask(this.sourceFiles);
deleteFolderContents(this.compiler.getOutputLocation()); deleteDirectoryContents(this.compiler.getOutputLocation());
task.call(processor); task.call(processor);
return processor.getMetadata(); return processor.getMetadata();
} }
...@@ -110,13 +112,13 @@ public class TestProject { ...@@ -110,13 +112,13 @@ public class TestProject {
return processor.getMetadata(); return processor.getMetadata();
} }
private void deleteFolderContents(File outputFolder) { private void deleteDirectoryContents(File outputDirectory) {
FileSystemUtils.deleteRecursively(outputFolder); FileSystemUtils.deleteRecursively(outputDirectory);
outputFolder.mkdirs(); outputDirectory.mkdirs();
} }
/** /**
* Retrieve File relative to project's output folder. * Retrieve File relative to project's output directory.
* @param relativePath the relative path * @param relativePath the relative path
* @return the output file * @return the output file
*/ */
...@@ -183,7 +185,7 @@ public class TestProject { ...@@ -183,7 +185,7 @@ public class TestProject {
* code. * code.
*/ */
private File getOriginalSourceFile(Class<?> type) { private File getOriginalSourceFile(Class<?> type) {
return new File(TestCompiler.SOURCE_FOLDER, TestCompiler.sourcePathFor(type)); return new File(TestCompiler.SOURCE_DIRECTORY, TestCompiler.sourcePathFor(type));
} }
private static void putContents(File targetFile, String contents) throws IOException { private static void putContents(File targetFile, String contents) throws IOException {
......
...@@ -174,7 +174,7 @@ include::../gradle/packaging/boot-war-include-devtools.gradle.kts[tags=include-d ...@@ -174,7 +174,7 @@ include::../gradle/packaging/boot-war-include-devtools.gradle.kts[tags=include-d
Most libraries can be used directly when nested in an executable archive, however certain libraries can have problems. Most libraries can be used directly when nested in an executable archive, however certain libraries can have problems.
For example, JRuby includes its own nested jar support which assumes that `jruby-complete.jar` is always directly available on the file system. For example, JRuby includes its own nested jar support which assumes that `jruby-complete.jar` is always directly available on the file system.
To deal with any problematic libraries, an executable archive can be configured to unpack specific nested jars to a temporary folder when the executable archive is run. To deal with any problematic libraries, an executable archive can be configured to unpack specific nested jars to a temporary directory when the executable archive is run.
Libraries can be identified as requiring unpacking using Ant-style patterns that match against the absolute path of the source jar file: Libraries can be identified as requiring unpacking using Ant-style patterns that match against the absolute path of the source jar file:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] [source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
...@@ -268,7 +268,7 @@ include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=proper ...@@ -268,7 +268,7 @@ include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=proper
[[packaging-layered-jars]] [[packaging-layered-jars]]
==== Packaging Layered Jars ==== Packaging Layered Jars
By default, the `bootJar` task builds an archive that contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively. By default, the `bootJar` task builds an archive that contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.
For cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these folders further so that they can be written into distinct layers. For cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these directories further so that they can be written into distinct layers.
Layered jars use the same layout as regular boot packaged jars, but include an additional meta-data file that describes each layer. Layered jars use the same layout as regular boot packaged jars, but include an additional meta-data file that describes each layer.
To use this feature, the layering feature must be enabled: To use this feature, the layering feature must be enabled:
......
...@@ -46,9 +46,9 @@ public class BootJar extends Jar implements BootArchive { ...@@ -46,9 +46,9 @@ public class BootJar extends Jar implements BootArchive {
private static final String LAUNCHER = "org.springframework.boot.loader.JarLauncher"; private static final String LAUNCHER = "org.springframework.boot.loader.JarLauncher";
private static final String CLASSES_FOLDER = "BOOT-INF/classes/"; private static final String CLASSES_DIRECTORY = "BOOT-INF/classes/";
private static final String LIB_FOLDER = "BOOT-INF/lib/"; private static final String LIB_DIRECTORY = "BOOT-INF/lib/";
private static final String LAYERS_INDEX = "BOOT-INF/layers.idx"; private static final String LAYERS_INDEX = "BOOT-INF/layers.idx";
...@@ -95,8 +95,8 @@ public class BootJar extends Jar implements BootArchive { ...@@ -95,8 +95,8 @@ public class BootJar extends Jar implements BootArchive {
@Override @Override
public void copy() { public void copy() {
this.support.configureManifest(getManifest(), getMainClassName(), CLASSES_FOLDER, LIB_FOLDER, CLASSPATH_INDEX, this.support.configureManifest(getManifest(), getMainClassName(), CLASSES_DIRECTORY, LIB_DIRECTORY,
(this.layered != null) ? LAYERS_INDEX : null); CLASSPATH_INDEX, (this.layered != null) ? LAYERS_INDEX : null);
super.copy(); super.copy();
} }
...@@ -104,7 +104,7 @@ public class BootJar extends Jar implements BootArchive { ...@@ -104,7 +104,7 @@ public class BootJar extends Jar implements BootArchive {
protected CopyAction createCopyAction() { protected CopyAction createCopyAction() {
if (this.layered != null) { if (this.layered != null) {
LayerResolver layerResolver = new LayerResolver(getConfigurations(), this.layered, this::isLibrary); LayerResolver layerResolver = new LayerResolver(getConfigurations(), this.layered, this::isLibrary);
String layerToolsLocation = this.layered.isIncludeLayerTools() ? LIB_FOLDER : null; String layerToolsLocation = this.layered.isIncludeLayerTools() ? LIB_DIRECTORY : null;
return this.support.createCopyAction(this, layerResolver, layerToolsLocation); return this.support.createCopyAction(this, layerResolver, layerToolsLocation);
} }
return this.support.createCopyAction(this); return this.support.createCopyAction(this);
...@@ -265,7 +265,7 @@ public class BootJar extends Jar implements BootArchive { ...@@ -265,7 +265,7 @@ public class BootJar extends Jar implements BootArchive {
*/ */
protected boolean isLibrary(FileCopyDetails details) { protected boolean isLibrary(FileCopyDetails details) {
String path = details.getRelativePath().getPathString(); String path = details.getRelativePath().getPathString();
return path.startsWith(LIB_FOLDER); return path.startsWith(LIB_DIRECTORY);
} }
private LaunchScriptConfiguration enableLaunchScriptIfNecessary() { private LaunchScriptConfiguration enableLaunchScriptIfNecessary() {
......
...@@ -42,11 +42,11 @@ public class BootWar extends War implements BootArchive { ...@@ -42,11 +42,11 @@ public class BootWar extends War implements BootArchive {
private static final String LAUNCHER = "org.springframework.boot.loader.WarLauncher"; private static final String LAUNCHER = "org.springframework.boot.loader.WarLauncher";
private static final String CLASSES_FOLDER = "WEB-INF/classes/"; private static final String CLASSES_DIRECTORY = "WEB-INF/classes/";
private static final String LIB_PROVIDED_FOLDER = "WEB-INF/lib-provided/"; private static final String LIB_PROVIDED_DIRECTORY = "WEB-INF/lib-provided/";
private static final String LIB_FOLDER = "WEB-INF/lib/"; private static final String LIB_DIRECTORY = "WEB-INF/lib/";
private final BootArchiveSupport support; private final BootArchiveSupport support;
...@@ -70,7 +70,7 @@ public class BootWar extends War implements BootArchive { ...@@ -70,7 +70,7 @@ public class BootWar extends War implements BootArchive {
@Override @Override
public void copy() { public void copy() {
this.support.configureManifest(getManifest(), getMainClassName(), CLASSES_FOLDER, LIB_FOLDER, null, null); this.support.configureManifest(getManifest(), getMainClassName(), CLASSES_DIRECTORY, LIB_DIRECTORY, null, null);
super.copy(); super.copy();
} }
...@@ -194,7 +194,7 @@ public class BootWar extends War implements BootArchive { ...@@ -194,7 +194,7 @@ public class BootWar extends War implements BootArchive {
*/ */
protected boolean isLibrary(FileCopyDetails details) { protected boolean isLibrary(FileCopyDetails details) {
String path = details.getRelativePath().getPathString(); String path = details.getRelativePath().getPathString();
return path.startsWith(LIB_FOLDER) || path.startsWith(LIB_PROVIDED_FOLDER); return path.startsWith(LIB_DIRECTORY) || path.startsWith(LIB_PROVIDED_DIRECTORY);
} }
private LaunchScriptConfiguration enableLaunchScriptIfNecessary() { private LaunchScriptConfiguration enableLaunchScriptIfNecessary() {
......
...@@ -282,7 +282,7 @@ class BootZipCopyAction implements CopyAction { ...@@ -282,7 +282,7 @@ class BootZipCopyAction implements CopyAction {
return; return;
} }
if (isInMetaInf(details)) { if (isInMetaInf(details)) {
// Don't write loader entries until after META-INF folder (see gh-16698) // Always write loader entries after META-INF directory (see gh-16698)
return; return;
} }
LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime()); LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime());
......
...@@ -125,13 +125,13 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> { ...@@ -125,13 +125,13 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
} }
@Test @Test
void classpathFoldersArePackagedBeneathClassesPath() throws IOException { void classpathDirectoriesArePackagedBeneathClassesPath() throws IOException {
this.task.setMainClassName("com.example.Main"); this.task.setMainClassName("com.example.Main");
File classpathFolder = new File(this.temp, "classes"); File classpathDirectory = new File(this.temp, "classes");
File applicationClass = new File(classpathFolder, "com/example/Application.class"); File applicationClass = new File(classpathDirectory, "com/example/Application.class");
applicationClass.getParentFile().mkdirs(); applicationClass.getParentFile().mkdirs();
applicationClass.createNewFile(); applicationClass.createNewFile();
this.task.classpath(classpathFolder); this.task.classpath(classpathDirectory);
executeTask(); executeTask();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getEntry(this.classesPath + "com/example/Application.class")).isNotNull(); assertThat(jarFile.getEntry(this.classesPath + "com/example/Application.class")).isNotNull();
...@@ -141,14 +141,14 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> { ...@@ -141,14 +141,14 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test @Test
void moduleInfoClassIsPackagedInTheRootOfTheArchive() throws IOException { void moduleInfoClassIsPackagedInTheRootOfTheArchive() throws IOException {
this.task.setMainClassName("com.example.Main"); this.task.setMainClassName("com.example.Main");
File classpathFolder = new File(this.temp, "classes"); File classpathDirectory = new File(this.temp, "classes");
File moduleInfoClass = new File(classpathFolder, "module-info.class"); File moduleInfoClass = new File(classpathDirectory, "module-info.class");
moduleInfoClass.getParentFile().mkdirs(); moduleInfoClass.getParentFile().mkdirs();
moduleInfoClass.createNewFile(); moduleInfoClass.createNewFile();
File applicationClass = new File(classpathFolder, "com/example/Application.class"); File applicationClass = new File(classpathDirectory, "com/example/Application.class");
applicationClass.getParentFile().mkdirs(); applicationClass.getParentFile().mkdirs();
applicationClass.createNewFile(); applicationClass.createNewFile();
this.task.classpath(classpathFolder); this.task.classpath(classpathDirectory);
executeTask(); executeTask();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getEntry(this.classesPath + "com/example/Application.class")).isNotNull(); assertThat(jarFile.getEntry(this.classesPath + "com/example/Application.class")).isNotNull();
...@@ -386,11 +386,11 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> { ...@@ -386,11 +386,11 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
void allEntriesUseUnixPlatformAndUtf8NameEncoding() throws IOException { void allEntriesUseUnixPlatformAndUtf8NameEncoding() throws IOException {
this.task.setMainClassName("com.example.Main"); this.task.setMainClassName("com.example.Main");
this.task.setMetadataCharset("UTF-8"); this.task.setMetadataCharset("UTF-8");
File classpathFolder = new File(this.temp, "classes"); File classpathDirectory = new File(this.temp, "classes");
File resource = new File(classpathFolder, "some-resource.xml"); File resource = new File(classpathDirectory, "some-resource.xml");
resource.getParentFile().mkdirs(); resource.getParentFile().mkdirs();
resource.createNewFile(); resource.createNewFile();
this.task.classpath(classpathFolder); this.task.classpath(classpathDirectory);
executeTask(); executeTask();
File archivePath = this.task.getArchiveFile().get().getAsFile(); File archivePath = this.task.getArchiveFile().get().getAsFile();
try (ZipFile zip = new ZipFile(archivePath)) { try (ZipFile zip = new ZipFile(archivePath)) {
...@@ -406,11 +406,11 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> { ...@@ -406,11 +406,11 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test @Test
void loaderIsWrittenFirstThenApplicationClassesThenLibraries() throws IOException { void loaderIsWrittenFirstThenApplicationClassesThenLibraries() throws IOException {
this.task.setMainClassName("com.example.Main"); this.task.setMainClassName("com.example.Main");
File classpathFolder = new File(this.temp, "classes"); File classpathDirectory = new File(this.temp, "classes");
File applicationClass = new File(classpathFolder, "com/example/Application.class"); File applicationClass = new File(classpathDirectory, "com/example/Application.class");
applicationClass.getParentFile().mkdirs(); applicationClass.getParentFile().mkdirs();
applicationClass.createNewFile(); applicationClass.createNewFile();
this.task.classpath(classpathFolder, jarFile("first-library.jar"), jarFile("second-library.jar"), this.task.classpath(classpathDirectory, jarFile("first-library.jar"), jarFile("second-library.jar"),
jarFile("third-library.jar")); jarFile("third-library.jar"));
this.task.requiresUnpack("second-library.jar"); this.task.requiresUnpack("second-library.jar");
executeTask(); executeTask();
......
...@@ -93,12 +93,12 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> { ...@@ -93,12 +93,12 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> {
@Test @Test
void webappResourcesInDirectoriesThatOverlapWithLoaderCanBePackaged() throws IOException { void webappResourcesInDirectoriesThatOverlapWithLoaderCanBePackaged() throws IOException {
File webappFolder = new File(this.temp, "src/main/webapp"); File webappDirectory = new File(this.temp, "src/main/webapp");
webappFolder.mkdirs(); webappDirectory.mkdirs();
File orgFolder = new File(webappFolder, "org"); File orgDirectory = new File(webappDirectory, "org");
orgFolder.mkdir(); orgDirectory.mkdir();
new File(orgFolder, "foo.txt").createNewFile(); new File(orgDirectory, "foo.txt").createNewFile();
getTask().from(webappFolder); getTask().from(webappDirectory);
getTask().setMainClassName("com.example.Main"); getTask().setMainClassName("com.example.Main");
executeTask(); executeTask();
try (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) { try (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {
......
...@@ -95,8 +95,8 @@ class Context { ...@@ -95,8 +95,8 @@ class Context {
return new File(name); return new File(name);
} }
private String deduceRelativeDir(File sourceFolder, File workingDir) { private String deduceRelativeDir(File sourceDirectory, File workingDir) {
String sourcePath = sourceFolder.getAbsolutePath(); String sourcePath = sourceDirectory.getAbsolutePath();
String workingPath = workingDir.getAbsolutePath(); String workingPath = workingDir.getAbsolutePath();
if (sourcePath.equals(workingPath) || !sourcePath.startsWith(workingPath)) { if (sourcePath.equals(workingPath) || !sourcePath.startsWith(workingPath)) {
return null; return null;
......
...@@ -100,7 +100,7 @@ class ExtractCommand extends Command { ...@@ -100,7 +100,7 @@ class ExtractCommand extends Command {
private void mkDirs(File file) throws IOException { private void mkDirs(File file) throws IOException {
if (!file.exists() && !file.mkdirs()) { if (!file.exists() && !file.mkdirs()) {
throw new IOException("Unable to create folder " + file); throw new IOException("Unable to create directory " + file);
} }
} }
......
...@@ -43,10 +43,10 @@ class ContextTests { ...@@ -43,10 +43,10 @@ class ContextTests {
} }
@Test @Test
void createWhenSourceIsFolderThrowsException() { void createWhenSourceIsDirectoryThrowsException() {
File folder = new File(this.temp, "test"); File directory = new File(this.temp, "test");
folder.mkdir(); directory.mkdir();
assertThatIllegalStateException().isThrownBy(() -> new Context(folder, this.temp)) assertThatIllegalStateException().isThrownBy(() -> new Context(directory, this.temp))
.withMessage("Unable to find source JAR"); .withMessage("Unable to find source JAR");
} }
...@@ -95,13 +95,13 @@ class ContextTests { ...@@ -95,13 +95,13 @@ class ContextTests {
@Test @Test
void getRelativePathWhenCannotBeDeducedReturnsNull() throws Exception { void getRelativePathWhenCannotBeDeducedReturnsNull() throws Exception {
File folder1 = new File(this.temp, "folder1"); File directory1 = new File(this.temp, "directory1");
folder1.mkdir(); directory1.mkdir();
File folder2 = new File(this.temp, "folder1"); File directory2 = new File(this.temp, "directory2");
folder2.mkdir(); directory2.mkdir();
File jar = new File(folder1, "test.jar"); File jar = new File(directory1, "test.jar");
Files.createFile(jar.toPath()); Files.createFile(jar.toPath());
Context context = new Context(jar, folder2); Context context = new Context(jar, directory2);
assertThat(context.getRelativeJarDir()).isNull(); assertThat(context.getRelativeJarDir()).isNull();
} }
......
...@@ -70,10 +70,10 @@ class IndexedLayersTests { ...@@ -70,10 +70,10 @@ class IndexedLayersTests {
} }
@Test @Test
void getLayerWhenMatchesFolderReturnsLayer() throws Exception { void getLayerWhenMatchesDirectoryReturnsLayer() throws Exception {
IndexedLayers layers = new IndexedLayers(getIndex()); IndexedLayers layers = new IndexedLayers(getIndex());
assertThat(layers.getLayer(mockEntry("META-INF/MANIFEST.MF"))).isEqualTo("application"); assertThat(layers.getLayer(mockEntry("META-INF/MANIFEST.MF"))).isEqualTo("application");
assertThat(layers.getLayer(mockEntry("META-INF/a/sub/folder/and/a/file"))).isEqualTo("application"); assertThat(layers.getLayer(mockEntry("META-INF/a/sub/directory/and/a/file"))).isEqualTo("application");
} }
@Test @Test
......
...@@ -239,7 +239,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter { ...@@ -239,7 +239,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter, UnpackHandler unpackHandler) private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter, UnpackHandler unpackHandler)
throws IOException { throws IOException {
String name = entry.getName(); String name = entry.getName();
writeParentFolderEntries(name); writeParentDirectoryEntries(name);
if (this.writtenEntries.add(name)) { if (this.writtenEntries.add(name)) {
entry.setUnixMode(name.endsWith("/") ? UNIX_DIR_MODE : UNIX_FILE_MODE); entry.setUnixMode(name.endsWith("/") ? UNIX_DIR_MODE : UNIX_FILE_MODE);
entry.getGeneralPurposeBit().useUTF8ForNames(true); entry.getGeneralPurposeBit().useUTF8ForNames(true);
...@@ -254,7 +254,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter { ...@@ -254,7 +254,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
protected abstract void writeToArchive(ZipEntry entry, EntryWriter entryWriter) throws IOException; protected abstract void writeToArchive(ZipEntry entry, EntryWriter entryWriter) throws IOException;
private void writeParentFolderEntries(String name) throws IOException { private void writeParentDirectoryEntries(String name) throws IOException {
String parent = name.endsWith("/") ? name.substring(0, name.length() - 1) : name; String parent = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
while (parent.lastIndexOf('/') != -1) { while (parent.lastIndexOf('/') != -1) {
parent = parent.substring(0, parent.lastIndexOf('/')); parent = parent.substring(0, parent.lastIndexOf('/'));
......
...@@ -36,9 +36,10 @@ import org.springframework.util.MultiValueMap; ...@@ -36,9 +36,10 @@ import org.springframework.util.MultiValueMap;
* text files that should be read from top to bottom. Each file defines the layers and * text files that should be read from top to bottom. Each file defines the layers and
* their content. Layer names are written as quoted strings prefixed by a dash space * their content. Layer names are written as quoted strings prefixed by a dash space
* ({@code "- "}) and with a colon ({@code ":"}) suffix. Layer content is either a file or * ({@code "- "}) and with a colon ({@code ":"}) suffix. Layer content is either a file or
* folder name written as a quoted string prefixed by space space dash space * directory name written as a quoted string prefixed by space space dash space
* ({@code " - "}). A folder name ends with {@code /}, a file name does not. When a * ({@code " - "}). A directory name ends with {@code /}, a file name does not. When a
* folder name is used it means that all files inside that folder are in the same layer. * directory name is used it means that all files inside that directory are in the same
* layer.
* <p> * <p>
* Index files are designed to be compatible with YAML and may be read into a list of * Index files are designed to be compatible with YAML and may be read into a list of
* `Map&lt;String, List&lt;String&gt;&gt;` instances. * `Map&lt;String, List&lt;String&gt;&gt;` instances.
...@@ -79,8 +80,8 @@ public class LayersIndex { ...@@ -79,8 +80,8 @@ public class LayersIndex {
String[] segments = name.split("/"); String[] segments = name.split("/");
Node node = this.root; Node node = this.root;
for (int i = 0; i < segments.length; i++) { for (int i = 0; i < segments.length; i++) {
boolean isFolder = i < (segments.length - 1); boolean isDirectory = i < (segments.length - 1);
node = node.updateOrAddNode(segments[i], isFolder, layer); node = node.updateOrAddNode(segments[i], isDirectory, layer);
} }
} }
...@@ -127,8 +128,8 @@ public class LayersIndex { ...@@ -127,8 +128,8 @@ public class LayersIndex {
this.layers = new HashSet<>(Collections.singleton(layer)); this.layers = new HashSet<>(Collections.singleton(layer));
} }
Node updateOrAddNode(String segment, boolean isFolder, Layer layer) { Node updateOrAddNode(String segment, boolean isDirectory, Layer layer) {
String name = segment + (isFolder ? "/" : ""); String name = segment + (isDirectory ? "/" : "");
for (Node child : this.children) { for (Node child : this.children) {
if (name.equals(child.name)) { if (name.equals(child.name)) {
child.layers.add(layer); child.layers.add(layer);
......
...@@ -64,71 +64,71 @@ public abstract class MainClassFinder { ...@@ -64,71 +64,71 @@ public abstract class MainClassFinder {
private static final FileFilter CLASS_FILE_FILTER = MainClassFinder::isClassFile; private static final FileFilter CLASS_FILE_FILTER = MainClassFinder::isClassFile;
private static final FileFilter PACKAGE_FOLDER_FILTER = MainClassFinder::isPackageFolder; private static final FileFilter PACKAGE_DIRECTORY_FILTER = MainClassFinder::isPackageDirectory;
private static boolean isClassFile(File file) { private static boolean isClassFile(File file) {
return file.isFile() && file.getName().endsWith(DOT_CLASS); return file.isFile() && file.getName().endsWith(DOT_CLASS);
} }
private static boolean isPackageFolder(File file) { private static boolean isPackageDirectory(File file) {
return file.isDirectory() && !file.getName().startsWith("."); return file.isDirectory() && !file.getName().startsWith(".");
} }
/** /**
* Find the main class from a given folder. * Find the main class from a given directory.
* @param rootFolder the root folder to search * @param rootDirectory the root directory to search
* @return the main class or {@code null} * @return the main class or {@code null}
* @throws IOException if the folder cannot be read * @throws IOException if the directory cannot be read
*/ */
public static String findMainClass(File rootFolder) throws IOException { public static String findMainClass(File rootDirectory) throws IOException {
return doWithMainClasses(rootFolder, MainClass::getName); return doWithMainClasses(rootDirectory, MainClass::getName);
} }
/** /**
* Find a single main class from the given {@code rootFolder}. * Find a single main class from the given {@code rootDirectory}.
* @param rootFolder the root folder to search * @param rootDirectory the root directory to search
* @return the main class or {@code null} * @return the main class or {@code null}
* @throws IOException if the folder cannot be read * @throws IOException if the directory cannot be read
*/ */
public static String findSingleMainClass(File rootFolder) throws IOException { public static String findSingleMainClass(File rootDirectory) throws IOException {
return findSingleMainClass(rootFolder, null); return findSingleMainClass(rootDirectory, null);
} }
/** /**
* Find a single main class from the given {@code rootFolder}. A main class annotated * Find a single main class from the given {@code rootDirectory}. A main class
* with an annotation with the given {@code annotationName} will be preferred over a * annotated with an annotation with the given {@code annotationName} will be
* main class with no such annotation. * preferred over a main class with no such annotation.
* @param rootFolder the root folder to search * @param rootDirectory the root directory to search
* @param annotationName the name of the annotation that may be present on the main * @param annotationName the name of the annotation that may be present on the main
* class * class
* @return the main class or {@code null} * @return the main class or {@code null}
* @throws IOException if the folder cannot be read * @throws IOException if the directory cannot be read
*/ */
public static String findSingleMainClass(File rootFolder, String annotationName) throws IOException { public static String findSingleMainClass(File rootDirectory, String annotationName) throws IOException {
SingleMainClassCallback callback = new SingleMainClassCallback(annotationName); SingleMainClassCallback callback = new SingleMainClassCallback(annotationName);
MainClassFinder.doWithMainClasses(rootFolder, callback); MainClassFinder.doWithMainClasses(rootDirectory, callback);
return callback.getMainClassName(); return callback.getMainClassName();
} }
/** /**
* Perform the given callback operation on all main classes from the given root * Perform the given callback operation on all main classes from the given root
* folder. * directory.
* @param <T> the result type * @param <T> the result type
* @param rootFolder the root folder * @param rootDirectory the root directory
* @param callback the callback * @param callback the callback
* @return the first callback result or {@code null} * @return the first callback result or {@code null}
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
*/ */
static <T> T doWithMainClasses(File rootFolder, MainClassCallback<T> callback) throws IOException { static <T> T doWithMainClasses(File rootDirectory, MainClassCallback<T> callback) throws IOException {
if (!rootFolder.exists()) { if (!rootDirectory.exists()) {
return null; // nothing to do return null; // nothing to do
} }
if (!rootFolder.isDirectory()) { if (!rootDirectory.isDirectory()) {
throw new IllegalArgumentException("Invalid root folder '" + rootFolder + "'"); throw new IllegalArgumentException("Invalid root directory '" + rootDirectory + "'");
} }
String prefix = rootFolder.getAbsolutePath() + "/"; String prefix = rootDirectory.getAbsolutePath() + "/";
Deque<File> stack = new ArrayDeque<>(); Deque<File> stack = new ArrayDeque<>();
stack.push(rootFolder); stack.push(rootDirectory);
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
File file = stack.pop(); File file = stack.pop();
if (file.isFile()) { if (file.isFile()) {
...@@ -144,7 +144,7 @@ public abstract class MainClassFinder { ...@@ -144,7 +144,7 @@ public abstract class MainClassFinder {
} }
} }
if (file.isDirectory()) { if (file.isDirectory()) {
pushAllSorted(stack, file.listFiles(PACKAGE_FOLDER_FILTER)); pushAllSorted(stack, file.listFiles(PACKAGE_DIRECTORY_FILTER));
pushAllSorted(stack, file.listFiles(CLASS_FILE_FILTER)); pushAllSorted(stack, file.listFiles(CLASS_FILE_FILTER));
} }
} }
......
...@@ -85,7 +85,7 @@ class LayersIndexTests { ...@@ -85,7 +85,7 @@ class LayersIndexTests {
} }
@Test @Test
void writeToWhenAllFilesInFolderAreInSameLayerUsesFolder() { void writeToWhenAllFilesInDirectoryAreInSameLayerUsesDirectory() {
LayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C); LayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C);
index.add(LAYER_A, "a1/b1/c1"); index.add(LAYER_A, "a1/b1/c1");
index.add(LAYER_A, "a1/b1/c2"); index.add(LAYER_A, "a1/b1/c2");
...@@ -96,7 +96,7 @@ class LayersIndexTests { ...@@ -96,7 +96,7 @@ class LayersIndexTests {
} }
@Test @Test
void writeToWhenAllFilesInFolderAreInNotInSameLayerUsesFiles() { void writeToWhenAllFilesInDirectoryAreInNotInSameLayerUsesFiles() {
LayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C); LayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C);
index.add(LAYER_A, "a1/b1/c1"); index.add(LAYER_A, "a1/b1/c1");
index.add(LAYER_B, "a1/b1/c2"); index.add(LAYER_B, "a1/b1/c2");
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -60,7 +60,7 @@ class MainClassFinderTests { ...@@ -60,7 +60,7 @@ class MainClassFinderTests {
} }
@Test @Test
void findMainClassInJarSubFolder() throws Exception { void findMainClassInJarSubDirectory() throws Exception {
this.testJarFile.addClass("a/b/c/D.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/b/c/D.class", ClassWithMainMethod.class);
this.testJarFile.addClass("a/b/c/E.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("a/b/c/E.class", ClassWithoutMainMethod.class);
this.testJarFile.addClass("a/b/F.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("a/b/F.class", ClassWithoutMainMethod.class);
...@@ -114,7 +114,7 @@ class MainClassFinderTests { ...@@ -114,7 +114,7 @@ class MainClassFinderTests {
} }
@Test @Test
void findMainClassInFolder() throws Exception { void findMainClassInDirectory() throws Exception {
this.testJarFile.addClass("B.class", ClassWithMainMethod.class); this.testJarFile.addClass("B.class", ClassWithMainMethod.class);
this.testJarFile.addClass("A.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("A.class", ClassWithoutMainMethod.class);
String actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource()); String actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource());
...@@ -122,7 +122,7 @@ class MainClassFinderTests { ...@@ -122,7 +122,7 @@ class MainClassFinderTests {
} }
@Test @Test
void findMainClassInSubFolder() throws Exception { void findMainClassInSubDirectory() throws Exception {
this.testJarFile.addClass("a/b/c/D.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/b/c/D.class", ClassWithMainMethod.class);
this.testJarFile.addClass("a/b/c/E.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("a/b/c/E.class", ClassWithoutMainMethod.class);
this.testJarFile.addClass("a/b/F.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("a/b/F.class", ClassWithoutMainMethod.class);
...@@ -131,7 +131,7 @@ class MainClassFinderTests { ...@@ -131,7 +131,7 @@ class MainClassFinderTests {
} }
@Test @Test
void usesBreadthFirstFolderSearch() throws Exception { void usesBreadthFirstDirectorySearch() throws Exception {
this.testJarFile.addClass("a/B.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/B.class", ClassWithMainMethod.class);
this.testJarFile.addClass("a/b/c/E.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/b/c/E.class", ClassWithMainMethod.class);
String actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource()); String actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource());
...@@ -139,7 +139,7 @@ class MainClassFinderTests { ...@@ -139,7 +139,7 @@ class MainClassFinderTests {
} }
@Test @Test
void findSingleFolderSearch() throws Exception { void findSingleDirectorySearch() throws Exception {
this.testJarFile.addClass("a/B.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/B.class", ClassWithMainMethod.class);
this.testJarFile.addClass("a/b/c/E.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/b/c/E.class", ClassWithMainMethod.class);
assertThatIllegalStateException() assertThatIllegalStateException()
...@@ -149,7 +149,7 @@ class MainClassFinderTests { ...@@ -149,7 +149,7 @@ class MainClassFinderTests {
} }
@Test @Test
void findSingleFolderSearchPrefersAnnotatedMainClass() throws Exception { void findSingleDirectorySearchPrefersAnnotatedMainClass() throws Exception {
this.testJarFile.addClass("a/B.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/B.class", ClassWithMainMethod.class);
this.testJarFile.addClass("a/b/c/E.class", AnnotatedClassWithMainMethod.class); this.testJarFile.addClass("a/b/c/E.class", AnnotatedClassWithMainMethod.class);
String mainClass = MainClassFinder.findSingleMainClass(this.testJarFile.getJarSource(), String mainClass = MainClassFinder.findSingleMainClass(this.testJarFile.getJarSource(),
...@@ -158,7 +158,7 @@ class MainClassFinderTests { ...@@ -158,7 +158,7 @@ class MainClassFinderTests {
} }
@Test @Test
void doWithFolderMainMethods() throws Exception { void doWithDirectoryMainMethods() throws Exception {
this.testJarFile.addClass("a/b/c/D.class", ClassWithMainMethod.class); this.testJarFile.addClass("a/b/c/D.class", ClassWithMainMethod.class);
this.testJarFile.addClass("a/b/c/E.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("a/b/c/E.class", ClassWithoutMainMethod.class);
this.testJarFile.addClass("a/b/F.class", ClassWithoutMainMethod.class); this.testJarFile.addClass("a/b/F.class", ClassWithoutMainMethod.class);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -40,15 +40,15 @@ public class TestJarFile { ...@@ -40,15 +40,15 @@ public class TestJarFile {
private final byte[] buffer = new byte[4096]; private final byte[] buffer = new byte[4096];
private final File temporaryFolder; private final File temporaryDirectory;
private final File jarSource; private final File jarSource;
private final List<ZipEntrySource> entries = new ArrayList<>(); private final List<ZipEntrySource> entries = new ArrayList<>();
public TestJarFile(File temporaryFolder) throws IOException { public TestJarFile(File temporaryDirectory) throws IOException {
this.temporaryFolder = temporaryFolder; this.temporaryDirectory = temporaryDirectory;
this.jarSource = new File(temporaryFolder, "jar-source"); this.jarSource = new File(temporaryDirectory, "jar-source");
} }
public void addClass(String filename, Class<?> classToCopy) throws IOException { public void addClass(String filename, Class<?> classToCopy) throws IOException {
...@@ -120,7 +120,7 @@ public class TestJarFile { ...@@ -120,7 +120,7 @@ public class TestJarFile {
} }
public File getFile(String extension) throws IOException { public File getFile(String extension) throws IOException {
File file = new File(this.temporaryFolder, UUID.randomUUID() + "." + extension); File file = new File(this.temporaryDirectory, UUID.randomUUID() + "." + extension);
ZipUtil.pack(this.entries.toArray(new ZipEntrySource[0]), file); ZipUtil.pack(this.entries.toArray(new ZipEntrySource[0]), file);
return file; return file;
} }
......
...@@ -139,7 +139,7 @@ public abstract class ExecutableArchiveLauncher extends Launcher { ...@@ -139,7 +139,7 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
* Determine if the specified entry is a nested item that should be added to the * Determine if the specified entry is a nested item that should be added to the
* classpath. * classpath.
* @param entry the entry to check * @param entry the entry to check
* @return {@code true} if the entry is a nested item (jar or folder) * @return {@code true} if the entry is a nested item (jar or directory)
*/ */
protected abstract boolean isNestedArchive(Archive.Entry entry); protected abstract boolean isNestedArchive(Archive.Entry entry);
......
...@@ -55,7 +55,7 @@ public class ExplodedArchive implements Archive { ...@@ -55,7 +55,7 @@ public class ExplodedArchive implements Archive {
/** /**
* Create a new {@link ExplodedArchive} instance. * Create a new {@link ExplodedArchive} instance.
* @param root the root folder * @param root the root directory
*/ */
public ExplodedArchive(File root) { public ExplodedArchive(File root) {
this(root, true); this(root, true);
...@@ -63,15 +63,14 @@ public class ExplodedArchive implements Archive { ...@@ -63,15 +63,14 @@ public class ExplodedArchive implements Archive {
/** /**
* Create a new {@link ExplodedArchive} instance. * Create a new {@link ExplodedArchive} instance.
* @param root the root folder * @param root the root directory
* @param recursive if recursive searching should be used to locate the manifest. * @param recursive if recursive searching should be used to locate the manifest.
* Defaults to {@code true}, folders with a large tree might want to set this to * Defaults to {@code true}, directories with a large tree might want to set this to
* {@code * {@code false}.
* false}.
*/ */
public ExplodedArchive(File root, boolean recursive) { public ExplodedArchive(File root, boolean recursive) {
if (!root.exists() || !root.isDirectory()) { if (!root.exists() || !root.isDirectory()) {
throw new IllegalArgumentException("Invalid source folder " + root); throw new IllegalArgumentException("Invalid source directory " + root);
} }
this.root = root; this.root = root;
this.recursive = recursive; this.recursive = recursive;
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -47,7 +47,7 @@ public class JarFileArchive implements Archive { ...@@ -47,7 +47,7 @@ public class JarFileArchive implements Archive {
private URL url; private URL url;
private File tempUnpackFolder; private File tempUnpackDirectory;
public JarFileArchive(File file) throws IOException { public JarFileArchive(File file) throws IOException {
this(file, file.toURI().toURL()); this(file, file.toURI().toURL());
...@@ -109,31 +109,31 @@ public class JarFileArchive implements Archive { ...@@ -109,31 +109,31 @@ public class JarFileArchive implements Archive {
if (name.lastIndexOf('/') != -1) { if (name.lastIndexOf('/') != -1) {
name = name.substring(name.lastIndexOf('/') + 1); name = name.substring(name.lastIndexOf('/') + 1);
} }
File file = new File(getTempUnpackFolder(), name); File file = new File(getTempUnpackDirectory(), name);
if (!file.exists() || file.length() != jarEntry.getSize()) { if (!file.exists() || file.length() != jarEntry.getSize()) {
unpack(jarEntry, file); unpack(jarEntry, file);
} }
return new JarFileArchive(file, file.toURI().toURL()); return new JarFileArchive(file, file.toURI().toURL());
} }
private File getTempUnpackFolder() { private File getTempUnpackDirectory() {
if (this.tempUnpackFolder == null) { if (this.tempUnpackDirectory == null) {
File tempFolder = new File(System.getProperty("java.io.tmpdir")); File tempDirectory = new File(System.getProperty("java.io.tmpdir"));
this.tempUnpackFolder = createUnpackFolder(tempFolder); this.tempUnpackDirectory = createUnpackDirectory(tempDirectory);
} }
return this.tempUnpackFolder; return this.tempUnpackDirectory;
} }
private File createUnpackFolder(File parent) { private File createUnpackDirectory(File parent) {
int attempts = 0; int attempts = 0;
while (attempts++ < 1000) { while (attempts++ < 1000) {
String fileName = new File(this.jarFile.getName()).getName(); String fileName = new File(this.jarFile.getName()).getName();
File unpackFolder = new File(parent, fileName + "-spring-boot-libs-" + UUID.randomUUID()); File unpackDirectory = new File(parent, fileName + "-spring-boot-libs-" + UUID.randomUUID());
if (unpackFolder.mkdirs()) { if (unpackDirectory.mkdirs()) {
return unpackFolder; return unpackDirectory;
} }
} }
throw new IllegalStateException("Failed to create unpack folder in directory '" + parent + "'"); throw new IllegalStateException("Failed to create unpack directory in directory '" + parent + "'");
} }
private void unpack(JarEntry entry, File file) throws IOException { private void unpack(JarEntry entry, File file) throws IOException {
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
/** /**
* Abstraction over logical Archives be they backed by a JAR file or unpacked into a * Abstraction over logical Archives be they backed by a JAR file or unpacked into a
* folder. * directory.
* *
* @see org.springframework.boot.loader.archive.Archive * @see org.springframework.boot.loader.archive.Archive
*/ */
......
...@@ -55,8 +55,8 @@ class ClassPathIndexFileTests { ...@@ -55,8 +55,8 @@ class ClassPathIndexFileTests {
} }
@Test @Test
void loadIfPossibleWhenRootIsFolderThrowsException() throws Exception { void loadIfPossibleWhenRootIsDirectoryThrowsException() throws Exception {
File root = new File(this.temp, "folder"); File root = new File(this.temp, "directory");
root.mkdirs(); root.mkdirs();
assertThat(ClassPathIndexFile.loadIfPossible(root.toURI().toURL(), "test.idx")).isNull(); assertThat(ClassPathIndexFile.loadIfPossible(root.toURI().toURL(), "test.idx")).isNull();
} }
......
...@@ -102,7 +102,7 @@ class PropertiesLauncherTests { ...@@ -102,7 +102,7 @@ class PropertiesLauncherTests {
void testNonExistentHome() { void testNonExistentHome() {
System.setProperty("loader.home", "src/test/resources/nonexistent"); System.setProperty("loader.home", "src/test/resources/nonexistent");
assertThatIllegalStateException().isThrownBy(PropertiesLauncher::new) assertThatIllegalStateException().isThrownBy(PropertiesLauncher::new)
.withMessageContaining("Invalid source folder").withCauseInstanceOf(IllegalArgumentException.class); .withMessageContaining("Invalid source directory").withCauseInstanceOf(IllegalArgumentException.class);
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -51,7 +51,7 @@ class ExplodedArchiveTests { ...@@ -51,7 +51,7 @@ class ExplodedArchiveTests {
@TempDir @TempDir
File tempDir; File tempDir;
private File rootFolder; private File rootDirectory;
private ExplodedArchive archive; private ExplodedArchive archive;
...@@ -71,16 +71,16 @@ class ExplodedArchiveTests { ...@@ -71,16 +71,16 @@ class ExplodedArchiveTests {
createArchive(null); createArchive(null);
} }
private void createArchive(String folderName) throws Exception { private void createArchive(String directoryName) throws Exception {
File file = new File(this.tempDir, "test.jar"); File file = new File(this.tempDir, "test.jar");
TestJarCreator.createTestJar(file); TestJarCreator.createTestJar(file);
this.rootFolder = (StringUtils.hasText(folderName) ? new File(this.tempDir, folderName) this.rootDirectory = (StringUtils.hasText(directoryName) ? new File(this.tempDir, directoryName)
: new File(this.tempDir, UUID.randomUUID().toString())); : new File(this.tempDir, UUID.randomUUID().toString()));
JarFile jarFile = new JarFile(file); JarFile jarFile = new JarFile(file);
Enumeration<JarEntry> entries = jarFile.entries(); Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement(); JarEntry entry = entries.nextElement();
File destination = new File(this.rootFolder.getAbsolutePath() + File.separator + entry.getName()); File destination = new File(this.rootDirectory.getAbsolutePath() + File.separator + entry.getName());
destination.getParentFile().mkdirs(); destination.getParentFile().mkdirs();
if (entry.isDirectory()) { if (entry.isDirectory()) {
destination.mkdir(); destination.mkdir();
...@@ -89,7 +89,7 @@ class ExplodedArchiveTests { ...@@ -89,7 +89,7 @@ class ExplodedArchiveTests {
FileCopyUtils.copy(jarFile.getInputStream(entry), new FileOutputStream(destination)); FileCopyUtils.copy(jarFile.getInputStream(entry), new FileOutputStream(destination));
} }
} }
this.archive = new ExplodedArchive(this.rootFolder); this.archive = new ExplodedArchive(this.rootDirectory);
jarFile.close(); jarFile.close();
} }
...@@ -106,20 +106,20 @@ class ExplodedArchiveTests { ...@@ -106,20 +106,20 @@ class ExplodedArchiveTests {
@Test @Test
void getUrl() throws Exception { void getUrl() throws Exception {
assertThat(this.archive.getUrl()).isEqualTo(this.rootFolder.toURI().toURL()); assertThat(this.archive.getUrl()).isEqualTo(this.rootDirectory.toURI().toURL());
} }
@Test @Test
void getUrlWithSpaceInPath() throws Exception { void getUrlWithSpaceInPath() throws Exception {
createArchive("spaces in the name"); createArchive("spaces in the name");
assertThat(this.archive.getUrl()).isEqualTo(this.rootFolder.toURI().toURL()); assertThat(this.archive.getUrl()).isEqualTo(this.rootDirectory.toURI().toURL());
} }
@Test @Test
void getNestedArchive() throws Exception { void getNestedArchive() throws Exception {
Entry entry = getEntriesMap(this.archive).get("nested.jar"); Entry entry = getEntriesMap(this.archive).get("nested.jar");
Archive nested = this.archive.getNestedArchive(entry); Archive nested = this.archive.getNestedArchive(entry);
assertThat(nested.getUrl().toString()).isEqualTo(this.rootFolder.toURI() + "nested.jar"); assertThat(nested.getUrl().toString()).isEqualTo(this.rootDirectory.toURI() + "nested.jar");
nested.close(); nested.close();
} }
...@@ -129,7 +129,7 @@ class ExplodedArchiveTests { ...@@ -129,7 +129,7 @@ class ExplodedArchiveTests {
Archive nested = this.archive.getNestedArchive(entry); Archive nested = this.archive.getNestedArchive(entry);
Map<String, Entry> nestedEntries = getEntriesMap(nested); Map<String, Entry> nestedEntries = getEntriesMap(nested);
assertThat(nestedEntries.size()).isEqualTo(1); assertThat(nestedEntries.size()).isEqualTo(1);
assertThat(nested.getUrl().toString()).isEqualTo("file:" + this.rootFolder.toURI().getPath() + "d/"); assertThat(nested.getUrl().toString()).isEqualTo("file:" + this.rootDirectory.toURI().getPath() + "d/");
} }
@Test @Test
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -126,20 +126,20 @@ class HandlerTests { ...@@ -126,20 +126,20 @@ class HandlerTests {
@Test @Test
void urlWithSpecReferencingParentDirectory() throws MalformedURLException { void urlWithSpecReferencingParentDirectory() throws MalformedURLException {
assertStandardAndCustomHandlerUrlsAreEqual("file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd", assertStandardAndCustomHandlerUrlsAreEqual("file:/test.jar!/BOOT-INF/classes!/xsd/directoryA/a.xsd",
"../folderB/c/d/e.xsd"); "../directoryB/c/d/e.xsd");
} }
@Test @Test
void urlWithSpecReferencingAncestorDirectoryOutsideJarStopsAtJarRoot() throws MalformedURLException { void urlWithSpecReferencingAncestorDirectoryOutsideJarStopsAtJarRoot() throws MalformedURLException {
assertStandardAndCustomHandlerUrlsAreEqual("file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd", assertStandardAndCustomHandlerUrlsAreEqual("file:/test.jar!/BOOT-INF/classes!/xsd/directoryA/a.xsd",
"../../../../../../folderB/b.xsd"); "../../../../../../directoryB/b.xsd");
} }
@Test @Test
void urlWithSpecReferencingCurrentDirectory() throws MalformedURLException { void urlWithSpecReferencingCurrentDirectory() throws MalformedURLException {
assertStandardAndCustomHandlerUrlsAreEqual("file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd", assertStandardAndCustomHandlerUrlsAreEqual("file:/test.jar!/BOOT-INF/classes!/xsd/directoryA/a.xsd",
"./folderB/c/d/e.xsd"); "./directoryB/c/d/e.xsd");
} }
@Test @Test
......
...@@ -77,7 +77,7 @@ The `layout` property defaults to a value determined by the archive type (`jar` ...@@ -77,7 +77,7 @@ The `layout` property defaults to a value determined by the archive type (`jar`
[[repackage-layers]] [[repackage-layers]]
=== Layered Jars === Layered Jars
A repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively. A repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.
For cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these folders further so that they can be written into distinct layers. For cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these directories further so that they can be written into distinct layers.
Layered jars use the same layout as regular repackaged jars, but include an additional meta-data file that describes each layer. Layered jars use the same layout as regular repackaged jars, but include an additional meta-data file that describes each layer.
To use this feature, the layering feature must be enabled: To use this feature, the layering feature must be enabled:
......
...@@ -64,7 +64,7 @@ You can restore it at any time by configuring your project: ...@@ -64,7 +64,7 @@ You can restore it at any time by configuring your project:
</build> </build>
---- ----
When `addResources` is enabled, any `src/main/resources` folder will be added to the application classpath when you run the application and any duplicate found in `target/classes` will be removed. When `addResources` is enabled, any `src/main/resources` directory will be added to the application classpath when you run the application and any duplicate found in `target/classes` will be removed.
This allows hot refreshing of resources which can be very useful when developing web applications. This allows hot refreshing of resources which can be very useful when developing web applications.
For example, you can work on HTML, CSS or JavaScript files and see your changes immediately without recompiling your application. For example, you can work on HTML, CSS or JavaScript files and see your changes immediately without recompiling your application.
It is also a helpful way of allowing your front end developers to work without needing to download and install a Java IDE. It is also a helpful way of allowing your front end developers to work without needing to download and install a Java IDE.
......
...@@ -212,7 +212,7 @@ class MavenBuild { ...@@ -212,7 +212,7 @@ class MavenBuild {
} }
/** /**
* Action to take on a maven project folder. * Action to take on a maven project directory.
*/ */
@FunctionalInterface @FunctionalInterface
public interface ProjectCallback { public interface ProjectCallback {
......
...@@ -176,13 +176,23 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -176,13 +176,23 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
private String mainClass; private String mainClass;
/** /**
* Additional folders besides the classes directory that should be added to the * Additional directories besides the classes directory that should be added to the
* classpath. * classpath.
* @since 1.0.0 * @since 1.0.0
* @deprecated since 2.3.0 in favor of {@code directories}
*/ */
@Deprecated
@Parameter(property = "spring-boot.run.folders") @Parameter(property = "spring-boot.run.folders")
private String[] folders; private String[] folders;
/**
* Additional directories besides the classes directory that should be added to the
* classpath.
* @since 1.0.0
*/
@Parameter(property = "spring-boot.run.directories")
private String[] directories;
/** /**
* Directory containing the classes and resource files that should be packaged into * Directory containing the classes and resource files that should be packaged into
* the archive. * the archive.
...@@ -440,7 +450,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -440,7 +450,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
protected URL[] getClassPathUrls() throws MojoExecutionException { protected URL[] getClassPathUrls() throws MojoExecutionException {
try { try {
List<URL> urls = new ArrayList<>(); List<URL> urls = new ArrayList<>();
addUserDefinedFolders(urls); addUserDefinedDirectories(urls);
addResources(urls); addResources(urls);
addProjectClasses(urls); addProjectClasses(urls);
addDependencies(urls); addDependencies(urls);
...@@ -451,12 +461,17 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -451,12 +461,17 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
} }
} }
private void addUserDefinedFolders(List<URL> urls) throws MalformedURLException { private void addUserDefinedDirectories(List<URL> urls) throws MalformedURLException {
if (this.folders != null) { if (this.folders != null) {
for (String folder : this.folders) { for (String folder : this.folders) {
urls.add(new File(folder).toURI().toURL()); urls.add(new File(folder).toURI().toURL());
} }
} }
if (this.directories != null) {
for (String directory : this.directories) {
urls.add(new File(directory).toURI().toURL());
}
}
} }
private void addResources(List<URL> urls) throws IOException { private void addResources(List<URL> urls) throws IOException {
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -41,9 +41,9 @@ import javax.tools.ToolProvider; ...@@ -41,9 +41,9 @@ import javax.tools.ToolProvider;
public class TestCompiler { public class TestCompiler {
/** /**
* The default source folder. * The default source directory.
*/ */
public static final File SOURCE_FOLDER = new File("src/test/java"); public static final File SOURCE_DIRECTORY = new File("src/test/java");
private final JavaCompiler compiler; private final JavaCompiler compiler;
...@@ -93,15 +93,15 @@ public class TestCompiler { ...@@ -93,15 +93,15 @@ public class TestCompiler {
} }
protected File getFile(Class<?> type) { protected File getFile(Class<?> type) {
return new File(getSourceFolder(), sourcePathFor(type)); return new File(getSourceDirectory(), sourcePathFor(type));
} }
public static String sourcePathFor(Class<?> type) { public static String sourcePathFor(Class<?> type) {
return type.getName().replace('.', '/') + ".java"; return type.getName().replace('.', '/') + ".java";
} }
protected File getSourceFolder() { protected File getSourceDirectory() {
return SOURCE_FOLDER; return SOURCE_DIRECTORY;
} }
/** /**
......
...@@ -439,8 +439,8 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, ...@@ -439,8 +439,8 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) { private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
getSearchLocations().forEach((location) -> { getSearchLocations().forEach((location) -> {
boolean isFolder = location.endsWith("/"); boolean isDirectory = location.endsWith("/");
Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES; Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach((name) -> load(location, name, profile, filterFactory, consumer)); names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
}); });
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -88,7 +88,7 @@ public class ApplicationPid { ...@@ -88,7 +88,7 @@ public class ApplicationPid {
*/ */
public void write(File file) throws IOException { public void write(File file) throws IOException {
Assert.state(this.pid != null, "No PID available"); Assert.state(this.pid != null, "No PID available");
createParentFolder(file); createParentDirectory(file);
if (file.exists()) { if (file.exists()) {
assertCanOverwrite(file); assertCanOverwrite(file);
} }
...@@ -97,7 +97,7 @@ public class ApplicationPid { ...@@ -97,7 +97,7 @@ public class ApplicationPid {
} }
} }
private void createParentFolder(File file) { private void createParentDirectory(File file) {
File parent = file.getParentFile(); File parent = file.getParentFile();
if (parent != null) { if (parent != null) {
parent.mkdirs(); parent.mkdirs();
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -87,7 +87,7 @@ public class WebServerPortFileWriter implements ApplicationListener<WebServerIni ...@@ -87,7 +87,7 @@ public class WebServerPortFileWriter implements ApplicationListener<WebServerIni
File portFile = getPortFile(event.getApplicationContext()); File portFile = getPortFile(event.getApplicationContext());
try { try {
String port = String.valueOf(event.getWebServer().getPort()); String port = String.valueOf(event.getWebServer().getPort());
createParentFolder(portFile); createParentDirectory(portFile);
FileCopyUtils.copy(port.getBytes(), portFile); FileCopyUtils.copy(port.getBytes(), portFile);
portFile.deleteOnExit(); portFile.deleteOnExit();
} }
...@@ -139,7 +139,7 @@ public class WebServerPortFileWriter implements ApplicationListener<WebServerIni ...@@ -139,7 +139,7 @@ public class WebServerPortFileWriter implements ApplicationListener<WebServerIni
return true; return true;
} }
private void createParentFolder(File file) { private void createParentDirectory(File file) {
File parent = file.getParentFile(); File parent = file.getParentFile();
if (parent != null) { if (parent != null) {
parent.mkdirs(); parent.mkdirs();
......
...@@ -1025,7 +1025,7 @@ class ConfigFileApplicationListenerTests { ...@@ -1025,7 +1025,7 @@ class ConfigFileApplicationListenerTests {
} }
@Test @Test
void whenConfigLocationSpecifiesFolderConfigFileProcessingContinues() { void whenConfigLocationSpecifiesDirectoryConfigFileProcessingContinues() {
String location = "classpath:application.unknown/"; String location = "classpath:application.unknown/";
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.location=" + location); "spring.config.location=" + location);
...@@ -1033,7 +1033,7 @@ class ConfigFileApplicationListenerTests { ...@@ -1033,7 +1033,7 @@ class ConfigFileApplicationListenerTests {
} }
@Test @Test
void locationsWithWildcardFoldersShouldLoadAllFilesThatMatch() { void locationsWithWildcardDirectoriesShouldLoadAllFilesThatMatch() {
String location = "file:src/test/resources/config/*/"; String location = "file:src/test/resources/config/*/";
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.location=" + location); "spring.config.location=" + location);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -35,17 +35,17 @@ public abstract class AbstractLoggingSystemTests { ...@@ -35,17 +35,17 @@ public abstract class AbstractLoggingSystemTests {
private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";
private String originalTempFolder; private String originalTempDirectory;
@BeforeEach @BeforeEach
void configureTempDir(@TempDir Path temp) { void configureTempDir(@TempDir Path temp) {
this.originalTempFolder = System.getProperty(JAVA_IO_TMPDIR); this.originalTempDirectory = System.getProperty(JAVA_IO_TMPDIR);
System.setProperty(JAVA_IO_TMPDIR, temp.toAbsolutePath().toString()); System.setProperty(JAVA_IO_TMPDIR, temp.toAbsolutePath().toString());
} }
@AfterEach @AfterEach
void reinstateTempDir() { void reinstateTempDir() {
System.setProperty(JAVA_IO_TMPDIR, this.originalTempFolder); System.setProperty(JAVA_IO_TMPDIR, this.originalTempDirectory);
} }
@AfterEach @AfterEach
......
...@@ -59,11 +59,11 @@ class ApplicationBuilder { ...@@ -59,11 +59,11 @@ class ApplicationBuilder {
} }
File buildApplication() throws Exception { File buildApplication() throws Exception {
File containerFolder = new File(this.temp.toFile(), this.container); File containerDirectory = new File(this.temp.toFile(), this.container);
if (containerFolder.exists()) { if (containerDirectory.exists()) {
return new File(containerFolder, "app/target/app-0.0.1." + this.packaging); return new File(containerDirectory, "app/target/app-0.0.1." + this.packaging);
} }
return doBuildApplication(containerFolder); return doBuildApplication(containerDirectory);
} }
String getPackaging() { String getPackaging() {
...@@ -74,15 +74,15 @@ class ApplicationBuilder { ...@@ -74,15 +74,15 @@ class ApplicationBuilder {
return this.container; return this.container;
} }
private File doBuildApplication(File containerFolder) throws IOException, MavenInvocationException { private File doBuildApplication(File containerDirectory) throws IOException, MavenInvocationException {
File resourcesJar = createResourcesJar(); File resourcesJar = createResourcesJar();
File appFolder = new File(containerFolder, "app"); File appDirectory = new File(containerDirectory, "app");
appFolder.mkdirs(); appDirectory.mkdirs();
File settingsXml = writeSettingsXml(appFolder); File settingsXml = writeSettingsXml(appDirectory);
writePom(appFolder, resourcesJar); writePom(appDirectory, resourcesJar);
copyApplicationSource(appFolder); copyApplicationSource(appDirectory);
packageApplication(appFolder, settingsXml); packageApplication(appDirectory, settingsXml);
return new File(appFolder, "target/app-0.0.1." + this.packaging); return new File(appDirectory, "target/app-0.0.1." + this.packaging);
} }
private File createResourcesJar() throws IOException { private File createResourcesJar() throws IOException {
...@@ -106,23 +106,23 @@ class ApplicationBuilder { ...@@ -106,23 +106,23 @@ class ApplicationBuilder {
} }
} }
private void writePom(File appFolder, File resourcesJar) throws IOException { private void writePom(File appDirectory, File resourcesJar) throws IOException {
Map<String, Object> context = new HashMap<>(); Map<String, Object> context = new HashMap<>();
context.put("packaging", this.packaging); context.put("packaging", this.packaging);
context.put("container", this.container); context.put("container", this.container);
context.put("bootVersion", Versions.getBootVersion()); context.put("bootVersion", Versions.getBootVersion());
context.put("resourcesJarPath", resourcesJar.getAbsolutePath()); context.put("resourcesJarPath", resourcesJar.getAbsolutePath());
try (FileWriter out = new FileWriter(new File(appFolder, "pom.xml")); try (FileWriter out = new FileWriter(new File(appDirectory, "pom.xml"));
FileReader templateReader = new FileReader("src/test/resources/pom-template.xml")) { FileReader templateReader = new FileReader("src/test/resources/pom-template.xml")) {
Mustache.compiler().escapeHTML(false).compile(templateReader).execute(context, out); Mustache.compiler().escapeHTML(false).compile(templateReader).execute(context, out);
} }
} }
private File writeSettingsXml(File appFolder) throws IOException { private File writeSettingsXml(File appDirectory) throws IOException {
Map<String, Object> context = new HashMap<>(); Map<String, Object> context = new HashMap<>();
context.put("repository", new File("build/test-repository").toURI().toURL()); context.put("repository", new File("build/test-repository").toURI().toURL());
context.put("localRepository", new File("build/local-m2-repository").getAbsolutePath()); context.put("localRepository", new File("build/local-m2-repository").getAbsolutePath());
File settingsXml = new File(appFolder, "settings.xml"); File settingsXml = new File(appDirectory, "settings.xml");
try (FileWriter out = new FileWriter(settingsXml); try (FileWriter out = new FileWriter(settingsXml);
FileReader templateReader = new FileReader("src/test/resources/settings-template.xml")) { FileReader templateReader = new FileReader("src/test/resources/settings-template.xml")) {
Mustache.compiler().escapeHTML(false).compile(templateReader).execute(context, out); Mustache.compiler().escapeHTML(false).compile(templateReader).execute(context, out);
...@@ -130,8 +130,8 @@ class ApplicationBuilder { ...@@ -130,8 +130,8 @@ class ApplicationBuilder {
return settingsXml; return settingsXml;
} }
private void copyApplicationSource(File appFolder) throws IOException { private void copyApplicationSource(File appDirectory) throws IOException {
File examplePackage = new File(appFolder, "src/main/java/com/example"); File examplePackage = new File(appDirectory, "src/main/java/com/example");
examplePackage.mkdirs(); examplePackage.mkdirs();
FileCopyUtils.copy(new File("src/test/java/com/example/ResourceHandlingApplication.java"), FileCopyUtils.copy(new File("src/test/java/com/example/ResourceHandlingApplication.java"),
new File(examplePackage, "ResourceHandlingApplication.java")); new File(examplePackage, "ResourceHandlingApplication.java"));
...@@ -142,20 +142,20 @@ class ApplicationBuilder { ...@@ -142,20 +142,20 @@ class ApplicationBuilder {
new File(examplePackage, "JettyServerCustomizerConfig.java")); new File(examplePackage, "JettyServerCustomizerConfig.java"));
} }
if ("war".equals(this.packaging)) { if ("war".equals(this.packaging)) {
File srcMainWebapp = new File(appFolder, "src/main/webapp"); File srcMainWebapp = new File(appDirectory, "src/main/webapp");
srcMainWebapp.mkdirs(); srcMainWebapp.mkdirs();
FileCopyUtils.copy("webapp resource", new FileWriter(new File(srcMainWebapp, "webapp-resource.txt"))); FileCopyUtils.copy("webapp resource", new FileWriter(new File(srcMainWebapp, "webapp-resource.txt")));
} }
copyAutoConfigurationFiles(appFolder); copyAutoConfigurationFiles(appDirectory);
return; return;
} }
private void copyAutoConfigurationFiles(File appFolder) throws IOException { private void copyAutoConfigurationFiles(File appDirectory) throws IOException {
File autoConfigPackage = new File(appFolder, "src/main/java/com/autoconfig"); File autoConfigPackage = new File(appDirectory, "src/main/java/com/autoconfig");
autoConfigPackage.mkdirs(); autoConfigPackage.mkdirs();
FileCopyUtils.copy(new File("src/test/java/com/autoconfig/ExampleAutoConfiguration.java"), FileCopyUtils.copy(new File("src/test/java/com/autoconfig/ExampleAutoConfiguration.java"),
new File(autoConfigPackage, "ExampleAutoConfiguration.java")); new File(autoConfigPackage, "ExampleAutoConfiguration.java"));
File srcMainResources = new File(appFolder, "src/main/resources"); File srcMainResources = new File(appDirectory, "src/main/resources");
srcMainResources.mkdirs(); srcMainResources.mkdirs();
File metaInf = new File(srcMainResources, "META-INF"); File metaInf = new File(srcMainResources, "META-INF");
metaInf.mkdirs(); metaInf.mkdirs();
...@@ -165,9 +165,9 @@ class ApplicationBuilder { ...@@ -165,9 +165,9 @@ class ApplicationBuilder {
new File(srcMainResources, "application.yml")); new File(srcMainResources, "application.yml"));
} }
private void packageApplication(File appFolder, File settingsXml) throws MavenInvocationException { private void packageApplication(File appDirectory, File settingsXml) throws MavenInvocationException {
InvocationRequest invocation = new DefaultInvocationRequest(); InvocationRequest invocation = new DefaultInvocationRequest();
invocation.setBaseDirectory(appFolder); invocation.setBaseDirectory(appDirectory);
invocation.setGoals(Collections.singletonList("package")); invocation.setGoals(Collections.singletonList("package"));
if (settingsXml != null) { if (settingsXml != null) {
invocation.setUserSettingsFile(settingsXml); invocation.setUserSettingsFile(settingsXml);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment