diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentWatchedFileBuildStep.java similarity index 89% rename from core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java rename to core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentWatchedFileBuildStep.java index 9e5fa01ad8238..d4b832420f7cb 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentConfigFileBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/HotDeploymentWatchedFileBuildStep.java @@ -10,10 +10,10 @@ import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.dev.testing.TestWatchedFiles; -public class HotDeploymentConfigFileBuildStep { +public class HotDeploymentWatchedFileBuildStep { @BuildStep - ServiceStartBuildItem setupConfigFileHotDeployment(List files, + ServiceStartBuildItem setupWatchedFileHotDeployment(List files, LaunchModeBuildItem launchModeBuildItem) { // TODO: this should really be an output of the RuntimeRunner RuntimeUpdatesProcessor processor = RuntimeUpdatesProcessor.INSTANCE; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 7f0765dad1be8..e58f35fbca804 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -874,6 +874,7 @@ Set checkForFileChange(Function roots = rootPaths.stream() .filter(Files::exists) .filter(Files::isReadable) @@ -883,7 +884,6 @@ Set checkForFileChange(Function seen = new HashSet<>(moduleResources); try { for (Path root : roots) { - Path outputDir = Paths.get(outputPath); //since the stream is Closeable, use a try with resources so the underlying iterator is closed try (final Stream walk = Files.walk(root)) { walk.forEach(path -> { @@ -927,11 +927,13 @@ Set checkForFileChange(Function checkForFileChange(Function 0); + } + } + if (!pathCurrentlyExisting) { + if (pathPreviouslyExisting) { + ret.add(path); + } + + Path target = outputDir.resolve(path); + try { + FileUtil.deleteIfExists(target); + } catch (IOException e) { + throw new UncheckedIOException(e); } } } @@ -1011,7 +1020,12 @@ Set checkForFileChange(Function 0) { + ret.add(watchedFilePath); + } } } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java index 9916dd8092978..711072d50b166 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/util/FileUtil.java @@ -13,10 +13,29 @@ public class FileUtil { + public static void deleteIfExists(final Path path) throws IOException { + BasicFileAttributes attributes; + try { + attributes = Files.readAttributes(path, BasicFileAttributes.class); + } catch (IOException ignored) { + // Files.isDirectory is also simply returning when any IOException occurs, same behaviour is fine + return; + } + if (attributes.isDirectory()) { + deleteDirectoryIfExists(path); + } else if (attributes.isRegularFile()) { + Files.deleteIfExists(path); + } + } + public static void deleteDirectory(final Path directory) throws IOException { if (!Files.isDirectory(directory)) { return; } + deleteDirectoryIfExists(directory); + } + + private static void deleteDirectoryIfExists(final Path directory) throws IOException { Files.walkFileTree(directory, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java index f8c7e7f4b2d3d..b92b59023c098 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java @@ -927,6 +927,25 @@ public void testThatNewResourcesAreServed() throws MavenInvocationException, IOE .until(() -> DevModeTestUtils.getHttpResponse("/lorem.txt", 404)); } + @Test + public void testThatConfigFileDeletionsAreDetected() throws MavenInvocationException, IOException { + testDir = initProject("projects/dev-mode-file-deletion"); + runAndCheck(); + + await() + .pollDelay(100, TimeUnit.MILLISECONDS) + .atMost(1, TimeUnit.MINUTES) + .until(() -> DevModeTestUtils.getHttpResponse("/app/hello/greetings").contains("Bonjour")); + + File source = new File(testDir, "src/main/resources/application.properties"); + FileUtils.delete(source); + + await() + .pollDelay(100, TimeUnit.MILLISECONDS) + .atMost(1, TimeUnit.MINUTES) + .until(() -> DevModeTestUtils.getHttpResponse("/app/hello/greetings").contains("Guten Morgen")); + } + @Test public void testThatMultipleResourceDirectoriesAreSupported() throws MavenInvocationException, IOException { testDir = initProject("projects/dev-mode-multiple-resource-dirs"); diff --git a/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/pom.xml new file mode 100644 index 0000000000000..bab60d0fcaeaf --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + org.acme + acme + 1.0-SNAPSHOT + + io.quarkus + quarkus-bom + @project.version@ + @project.version@ + 11 + UTF-8 + 11 + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + src/main/resources + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus-plugin.version} + + + + generate-code + generate-code-tests + build + + + + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/java/org/acme/HelloResource.java b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/java/org/acme/HelloResource.java new file mode 100644 index 0000000000000..dacee899bd8f4 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/java/org/acme/HelloResource.java @@ -0,0 +1,28 @@ +package org.acme; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/hello") +public class HelloResource { + + @ConfigProperty(name = "greeting", defaultValue = "Guten Morgen") + String greeting; + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "hello"; + } + + @GET + @Path("/greetings") + @Produces(MediaType.TEXT_PLAIN) + public String greetings() { + return greeting; + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/java/org/acme/MyApplication.java b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/java/org/acme/MyApplication.java new file mode 100644 index 0000000000000..2b41cd0385afb --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/java/org/acme/MyApplication.java @@ -0,0 +1,9 @@ +package org.acme; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/app") +public class MyApplication extends Application { + +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/resources/META-INF/resources/index.html b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/resources/META-INF/resources/index.html new file mode 100644 index 0000000000000..c09bb5c96b869 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/resources/META-INF/resources/index.html @@ -0,0 +1,156 @@ + + + + + acme - 1.0-SNAPSHOT + + + + + + +
+
+

Congratulations, you have created a new Quarkus application.

+ +

Why do you see this?

+ +

This page is served by Quarkus. The source is in + src/main/resources/META-INF/resources/index.html.

+ +

What can I do from here?

+ +

If not already done, run the application in dev mode using: mvn compile quarkus:dev. +

+
    +
  • Add REST resources, Servlets, functions and other services in src/main/java.
  • +
  • Your static assets are located in src/main/resources/META-INF/resources.
  • +
  • Configure your application in src/main/resources/application.properties. +
  • +
+ +

Do you like Quarkus?

+

Go give it a star on GitHub.

+ +

How do I get rid of this page?

+

Just delete the src/main/resources/META-INF/resources/index.html file.

+
+
+
+

Application

+
    +
  • GroupId: org.acme
  • +
  • ArtifactId: acme
  • +
  • Version: 1.0-SNAPSHOT
  • +
  • Quarkus Version: 999-SNAPSHOT
  • +
+
+
+

Next steps

+ +
+
+
+ + + + \ No newline at end of file diff --git a/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/resources/application.properties b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/resources/application.properties new file mode 100644 index 0000000000000..acb0268bff21d --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/dev-mode-file-deletion/src/main/resources/application.properties @@ -0,0 +1,2 @@ +# Configuration file +greeting=Bonjour