From 7bcd6567bad67296a6afb36428b2f25575399dc2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 8 Jun 2015 22:07:22 -0700 Subject: [PATCH] Allow reload to use a trigger file Update `FileSystemWatcher` to support the concept of a "trigger file" which could be written by an IDE when a reload needs to occur. Fixes gh-3157 --- .../autoconfigure/DevToolsProperties.java | 14 +++++ .../LocalDevToolsAutoConfiguration.java | 23 ++++--- .../autoconfigure/TriggerFileFilter.java | 44 +++++++++++++ .../devtools/filewatch/FileSystemWatcher.java | 49 ++++++++++++--- .../devtools/filewatch/FolderSnapshot.java | 51 +++++++++++++--- .../client/RemoteClientConfiguration.java | 16 ++++- .../LocalDevToolsAutoConfigurationTests.java | 19 ++++-- .../autoconfigure/TriggerFileFilterTests.java | 61 +++++++++++++++++++ .../filewatch/FileSystemWatcherTests.java | 32 ++++++++-- .../filewatch/FolderSnapshotTests.java | 12 ++-- .../src/main/resources/application.properties | 3 +- 11 files changed, 280 insertions(+), 44 deletions(-) create mode 100644 spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilter.java create mode 100644 spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java index e21e4b870db..b860698a784 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java @@ -62,6 +62,12 @@ public class DevToolsProperties { */ private String exclude = DEFAULT_RESTART_EXCLUDES; + /** + * The name of specific that that when changed will will trigger the restart. If + * not specified any classpath file change will trigger the restart. + */ + private String triggerFile; + public boolean isEnabled() { return this.enabled; } @@ -78,6 +84,14 @@ public class DevToolsProperties { this.exclude = exclude; } + public String getTriggerFile() { + return this.triggerFile; + } + + public void setTriggerFile(String triggerFile) { + this.triggerFile = triggerFile; + } + } /** diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java index 36da42b6471..41b1423bbc3 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java @@ -36,6 +36,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; +import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for local development support. @@ -104,13 +105,19 @@ public class LocalDevToolsAutoConfiguration { @Autowired private DevToolsProperties properties; - private final FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(); + @EventListener + public void onClassPathChanged(ClassPathChangedEvent event) { + if (event.isRestartRequired()) { + getFileSystemWatcher().stop(); + Restarter.getInstance().restart(); + } + } @Bean @ConditionalOnMissingBean public ClassPathFileSystemWatcher classPathFileSystemWatcher() { URL[] urls = Restarter.getInstance().getInitialUrls(); - return new ClassPathFileSystemWatcher(this.fileSystemWatcher, + return new ClassPathFileSystemWatcher(getFileSystemWatcher(), classPathRestartStrategy(), urls); } @@ -121,12 +128,14 @@ public class LocalDevToolsAutoConfiguration { .getExclude()); } - @EventListener - public void onClassPathChanged(ClassPathChangedEvent event) { - if (event.isRestartRequired()) { - this.fileSystemWatcher.stop(); - Restarter.getInstance().restart(); + @Bean + public FileSystemWatcher getFileSystemWatcher() { + FileSystemWatcher watcher = new FileSystemWatcher(); + String triggerFile = this.properties.getRestart().getTriggerFile(); + if (StringUtils.hasLength(triggerFile)) { + watcher.setTriggerFilter(new TriggerFileFilter(triggerFile)); } + return watcher; } } diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilter.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilter.java new file mode 100644 index 00000000000..a22be47b4be --- /dev/null +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.devtools.autoconfigure; + +import java.io.File; +import java.io.FileFilter; + +import org.springframework.util.Assert; + +/** + * {@link FileFilter} that accepts only a specific "trigger" file. + * + * @author Phillip Webb + * @since 1.3.0 + */ +public class TriggerFileFilter implements FileFilter { + + private final String name; + + public TriggerFileFilter(String name) { + Assert.notNull(name, "Name must not be null"); + this.name = name; + } + + @Override + public boolean accept(File file) { + return file.getName().equals(this.name); + } + +} diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcher.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcher.java index 722807e9586..81e3c992ea6 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcher.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcher.java @@ -17,9 +17,10 @@ package org.springframework.boot.devtools.filewatch; import java.io.File; +import java.io.FileFilter; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -57,6 +58,8 @@ public class FileSystemWatcher { private Map folders = new LinkedHashMap(); + private FileFilter triggerFilter; + /** * Create a new {@link FileSystemWatcher} instance. */ @@ -100,6 +103,14 @@ public class FileSystemWatcher { this.folders.put(folder, null); } + /** + * Set an optional {@link FileFilter} used to limit the files that trigger a change. + * @param triggerFilter a trigger filter or null + */ + public synchronized void setTriggerFilter(FileFilter triggerFilter) { + this.triggerFilter = triggerFilter; + } + private void checkNotStarted() { Assert.state(this.watchThread == null, "FileSystemWatcher already started"); } @@ -142,32 +153,50 @@ public class FileSystemWatcher { private void scan() throws InterruptedException { Thread.sleep(this.idleTime - this.quietTime); - Set previous; - Set current = new HashSet(this.folders.values()); + Map previous; + Map current = this.folders; do { previous = current; current = getCurrentSnapshots(); Thread.sleep(this.quietTime); } - while (!previous.equals(current)); - updateSnapshots(current); + while (isDifferent(previous, current)); + if (isDifferent(this.folders, current)) { + updateSnapshots(current.values()); + } + } + + private boolean isDifferent(Map previous, + Map current) { + if (!previous.keySet().equals(current.keySet())) { + return true; + } + for (Map.Entry entry : previous.entrySet()) { + FolderSnapshot previousFolder = entry.getValue(); + FolderSnapshot currentFolder = current.get(entry.getKey()); + if (!previousFolder.equals(currentFolder, this.triggerFilter)) { + return true; + } + } + return false; } - private Set getCurrentSnapshots() { - Set snapshots = new LinkedHashSet(); + private Map getCurrentSnapshots() { + Map snapshots = new LinkedHashMap(); for (File folder : this.folders.keySet()) { - snapshots.add(new FolderSnapshot(folder)); + snapshots.put(folder, new FolderSnapshot(folder)); } return snapshots; } - private void updateSnapshots(Set snapshots) { + private void updateSnapshots(Collection snapshots) { Map updated = new LinkedHashMap(); Set changeSet = new LinkedHashSet(); for (FolderSnapshot snapshot : snapshots) { FolderSnapshot previous = this.folders.get(snapshot.getFolder()); updated.put(snapshot.getFolder(), snapshot); - ChangedFiles changedFiles = previous.getChangedFiles(snapshot); + ChangedFiles changedFiles = previous.getChangedFiles(snapshot, + this.triggerFilter); if (!changedFiles.getFiles().isEmpty()) { changeSet.add(changedFiles); } diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FolderSnapshot.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FolderSnapshot.java index 0f3ea03363a..e672759394e 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FolderSnapshot.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FolderSnapshot.java @@ -17,6 +17,7 @@ package org.springframework.boot.devtools.filewatch; import java.io.File; +import java.io.FileFilter; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -73,7 +74,7 @@ class FolderSnapshot { } } - public ChangedFiles getChangedFiles(FolderSnapshot snapshot) { + public ChangedFiles getChangedFiles(FolderSnapshot snapshot, FileFilter triggerFilter) { Assert.notNull(snapshot, "Snapshot must not be null"); File folder = this.folder; Assert.isTrue(snapshot.folder.equals(folder), "Snapshot source folder must be '" @@ -81,20 +82,29 @@ class FolderSnapshot { Set changes = new LinkedHashSet(); Map previousFiles = getFilesMap(); for (FileSnapshot currentFile : snapshot.files) { - FileSnapshot previousFile = previousFiles.remove(currentFile.getFile()); - if (previousFile == null) { - changes.add(new ChangedFile(folder, currentFile.getFile(), Type.ADD)); - } - else if (!previousFile.equals(currentFile)) { - changes.add(new ChangedFile(folder, currentFile.getFile(), Type.MODIFY)); + if (acceptChangedFile(triggerFilter, currentFile)) { + FileSnapshot previousFile = previousFiles.remove(currentFile.getFile()); + if (previousFile == null) { + changes.add(new ChangedFile(folder, currentFile.getFile(), Type.ADD)); + } + else if (!previousFile.equals(currentFile)) { + changes.add(new ChangedFile(folder, currentFile.getFile(), + Type.MODIFY)); + } } } for (FileSnapshot previousFile : previousFiles.values()) { - changes.add(new ChangedFile(folder, previousFile.getFile(), Type.DELETE)); + if (acceptChangedFile(triggerFilter, previousFile)) { + changes.add(new ChangedFile(folder, previousFile.getFile(), Type.DELETE)); + } } return new ChangedFiles(folder, changes); } + private boolean acceptChangedFile(FileFilter triggerFilter, FileSnapshot file) { + return (triggerFilter == null || !triggerFilter.accept(file.getFile())); + } + private Map getFilesMap() { Map files = new LinkedHashMap(); for (FileSnapshot file : this.files) { @@ -112,12 +122,33 @@ class FolderSnapshot { return false; } if (obj instanceof FolderSnapshot) { - FolderSnapshot other = (FolderSnapshot) obj; - return this.folder.equals(other.folder) && this.files.equals(other.files); + return equals((FolderSnapshot) obj, null); } return super.equals(obj); } + public boolean equals(FolderSnapshot other, FileFilter filter) { + if (this.folder.equals(other.folder)) { + Set ourFiles = filter(this.files, filter); + Set otherFiles = filter(other.files, filter); + return ourFiles.equals(otherFiles); + } + return false; + } + + private Set filter(Set source, FileFilter filter) { + if (filter == null) { + return source; + } + Set filtered = new LinkedHashSet(); + for (FileSnapshot file : source) { + if (filter.accept(file.getFile())) { + filtered.add(file); + } + } + return filtered; + } + @Override public int hashCode() { int hashCode = this.folder.hashCode(); diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java index cbaec0b4404..d23fd03e153 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java @@ -36,10 +36,12 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.devtools.autoconfigure.DevToolsProperties; import org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer; import org.springframework.boot.devtools.autoconfigure.RemoteDevToolsProperties; +import org.springframework.boot.devtools.autoconfigure.TriggerFileFilter; import org.springframework.boot.devtools.classpath.ClassPathChangedEvent; import org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher; import org.springframework.boot.devtools.classpath.ClassPathRestartStrategy; import org.springframework.boot.devtools.classpath.PatternClassPathRestartStrategy; +import org.springframework.boot.devtools.filewatch.FileSystemWatcher; import org.springframework.boot.devtools.livereload.LiveReloadServer; import org.springframework.boot.devtools.restart.DefaultRestartInitializer; import org.springframework.boot.devtools.restart.RestartScope; @@ -57,6 +59,7 @@ import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.InterceptingClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Configuration used to connect to remote Spring Boot applications. @@ -178,7 +181,18 @@ public class RemoteClientConfiguration { if (urls == null) { urls = new URL[0]; } - return new ClassPathFileSystemWatcher(classPathRestartStrategy(), urls); + return new ClassPathFileSystemWatcher(getFileSystemWather(), + classPathRestartStrategy(), urls); + } + + @Bean + public FileSystemWatcher getFileSystemWather() { + FileSystemWatcher watcher = new FileSystemWatcher(); + String triggerFile = this.properties.getRestart().getTriggerFile(); + if (StringUtils.hasLength(triggerFile)) { + watcher.setTriggerFilter(new TriggerFileFilter(triggerFile)); + } + return watcher; } @Bean diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java index dbe29c901c8..1b2b5bf1bef 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java @@ -30,6 +30,7 @@ import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfigurati import org.springframework.boot.devtools.classpath.ClassPathChangedEvent; import org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher; import org.springframework.boot.devtools.filewatch.ChangedFiles; +import org.springframework.boot.devtools.filewatch.FileSystemWatcher; import org.springframework.boot.devtools.livereload.LiveReloadServer; import org.springframework.boot.devtools.restart.MockRestartInitializer; import org.springframework.boot.devtools.restart.MockRestarter; @@ -39,10 +40,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.SocketUtils; import org.thymeleaf.templateresolver.TemplateResolver; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; @@ -164,6 +167,16 @@ public class LocalDevToolsAutoConfigurationTests { this.context.getBean(ClassPathFileSystemWatcher.class); } + @Test + public void restartWithTriggerFile() throws Exception { + Map properties = new HashMap(); + properties.put("spring.devtools.restart.trigger-file", "somefile.txt"); + this.context = initializeAndRun(Config.class, properties); + FileSystemWatcher watcher = this.context.getBean(FileSystemWatcher.class); + Object filter = ReflectionTestUtils.getField(watcher, "triggerFilter"); + assertThat(filter, instanceOf(TriggerFileFilter.class)); + } + private ConfigurableApplicationContext initializeAndRun(Class config) { return initializeAndRun(config, Collections. emptyMap()); } @@ -188,15 +201,13 @@ public class LocalDevToolsAutoConfigurationTests { } @Configuration - @Import({ LocalDevToolsAutoConfiguration.class, - ThymeleafAutoConfiguration.class }) + @Import({ LocalDevToolsAutoConfiguration.class, ThymeleafAutoConfiguration.class }) public static class Config { } @Configuration - @Import({ LocalDevToolsAutoConfiguration.class, - ThymeleafAutoConfiguration.class }) + @Import({ LocalDevToolsAutoConfiguration.class, ThymeleafAutoConfiguration.class }) public static class ConfigWithMockLiveReload { @Bean diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java new file mode 100644 index 00000000000..d2a604f19aa --- /dev/null +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.devtools.autoconfigure; + +import java.io.File; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link TriggerFileFilter}. + * + * @author Phillip Webb + */ +public class TriggerFileFilterTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void nameMustNotBeNull() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Name must not be null"); + new TriggerFileFilter(null); + } + + @Test + public void acceptNameMatch() throws Exception { + File file = this.temp.newFile("thefile.txt"); + assertThat(new TriggerFileFilter("thefile.txt").accept(file), equalTo(true)); + } + + @Test + public void doesNotAcceptNameMismatch() throws Exception { + File file = this.temp.newFile("notthefile.txt"); + assertThat(new TriggerFileFilter("thefile.txt").accept(file), equalTo(false)); + } + +} diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java index 734aa1949ca..a7d884f50c8 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.devtools.filewatch; import java.io.File; +import java.io.FileFilter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -32,10 +33,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import org.springframework.boot.devtools.filewatch.ChangedFile; -import org.springframework.boot.devtools.filewatch.ChangedFiles; -import org.springframework.boot.devtools.filewatch.FileChangeListener; -import org.springframework.boot.devtools.filewatch.FileSystemWatcher; import org.springframework.boot.devtools.filewatch.ChangedFile.Type; import org.springframework.util.FileCopyUtils; @@ -221,6 +218,33 @@ public class FileSystemWatcherTests { assertEquals(expected, actual); } + @Test + public void withTriggerFilter() throws Exception { + File folder = this.temp.newFolder(); + File file = touch(new File(folder, "file.txt")); + File trigger = touch(new File(folder, "trigger.txt")); + this.watcher.addSourceFolder(folder); + this.watcher.setTriggerFilter(new FileFilter() { + + @Override + public boolean accept(File file) { + return file.getName().equals("trigger.txt"); + } + + }); + this.watcher.start(); + FileCopyUtils.copy("abc".getBytes(), file); + Thread.sleep(100); + assertThat(this.changes.size(), equalTo(0)); + FileCopyUtils.copy("abc".getBytes(), trigger); + this.watcher.stopAfter(1); + ChangedFiles changedFiles = getSingleChangedFiles(); + Set actual = changedFiles.getFiles(); + Set expected = new HashSet(); + expected.add(new ChangedFile(folder, file, Type.MODIFY)); + assertEquals(expected, actual); + } + private void setupWatcher(long idleTime, long quietTime) { this.watcher = new FileSystemWatcher(false, idleTime, quietTime); this.watcher.addListener(new FileChangeListener() { diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FolderSnapshotTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FolderSnapshotTests.java index 67c018933e3..3772bc87e3b 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FolderSnapshotTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FolderSnapshotTests.java @@ -24,9 +24,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import org.springframework.boot.devtools.filewatch.ChangedFile; -import org.springframework.boot.devtools.filewatch.ChangedFiles; -import org.springframework.boot.devtools.filewatch.FolderSnapshot; import org.springframework.boot.devtools.filewatch.ChangedFile.Type; import org.springframework.util.FileCopyUtils; @@ -104,7 +101,7 @@ public class FolderSnapshotTests { public void getChangedFilesSnapshotMustNotBeNull() throws Exception { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Snapshot must not be null"); - this.initialSnapshot.getChangedFiles(null); + this.initialSnapshot.getChangedFiles(null, null); } @Test @@ -112,13 +109,13 @@ public class FolderSnapshotTests { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Snapshot source folder must be '" + this.folder + "'"); this.initialSnapshot.getChangedFiles(new FolderSnapshot( - createTestFolderStructure())); + createTestFolderStructure()), null); } @Test public void getChangedFilesWhenNothingHasChanged() throws Exception { FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); - this.initialSnapshot.getChangedFiles(updatedSnapshot); + this.initialSnapshot.getChangedFiles(updatedSnapshot, null); } @Test @@ -131,7 +128,8 @@ public class FolderSnapshotTests { file2.delete(); newFile.createNewFile(); FolderSnapshot updatedSnapshot = new FolderSnapshot(this.folder); - ChangedFiles changedFiles = this.initialSnapshot.getChangedFiles(updatedSnapshot); + ChangedFiles changedFiles = this.initialSnapshot.getChangedFiles(updatedSnapshot, + null); assertThat(changedFiles.getSourceFolder(), equalTo(this.folder)); assertThat(getChangedFile(changedFiles, file1).getType(), equalTo(Type.MODIFY)); assertThat(getChangedFile(changedFiles, file2).getType(), equalTo(Type.DELETE)); diff --git a/spring-boot-samples/spring-boot-sample-devtools/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-devtools/src/main/resources/application.properties index fcd8b00e721..e82dc814f80 100644 --- a/spring-boot-samples/spring-boot-sample-devtools/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-devtools/src/main/resources/application.properties @@ -1 +1,2 @@ -spring.developertools.remote.secret=secret +spring.devtools.remote.secret=secret +# spring.devtools.restart.trigger-file=.reloadtrigger