From 4800a5a9d900466ef67c85917c65781464dc4478 Mon Sep 17 00:00:00 2001 From: Edgar Espina Date: Sun, 19 May 2024 21:04:09 -0300 Subject: [PATCH] joobyRun: improve lookup of logging configuration file on multi-module project fix #3428 --- .../main/java/io/jooby/LoggingService.java | 21 ++++++++++-- .../main/java/io/jooby/gradle/RunTask.java | 1 + .../src/main/java/io/jooby/maven/RunMojo.java | 1 + .../test/java/io/jooby/maven/RunMojoTest.java | 4 ++- .../src/main/java/io/jooby/run/JoobyRun.java | 33 +++++++++++++++++-- .../java/io/jooby/run/JoobyRunOptions.java | 9 +++++ .../test/java/io/jooby/run/BaseDirTest.java | 21 ++++++++++++ 7 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 modules/jooby-run/src/test/java/io/jooby/run/BaseDirTest.java diff --git a/jooby/src/main/java/io/jooby/LoggingService.java b/jooby/src/main/java/io/jooby/LoggingService.java index 926d8fad5d..7fff3aad37 100644 --- a/jooby/src/main/java/io/jooby/LoggingService.java +++ b/jooby/src/main/java/io/jooby/LoggingService.java @@ -16,6 +16,8 @@ import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import edu.umd.cs.findbugs.annotations.NonNull; @@ -80,7 +82,13 @@ static String configure(@NonNull ClassLoader classLoader, @NonNull List // We could throw an exception here but nope, let user choose any other way of setup logging. return null; } - Path userdir = Paths.get(System.getProperty("user.dir")); + // Helps logging lookup on multi-module project, prefer logback from main module + Path userdir = + Stream.of(System.getProperty("jooby.dir"), System.getProperty("user.dir")) + .filter(Objects::nonNull) + .map(Paths::get) + .findFirst() + .orElseThrow((() -> new IllegalStateException("No base directory found"))); var loggingService = lookup.get(); var resources = logFiles(userdir, names, loggingService.getLogFileName()); @@ -95,8 +103,10 @@ static String configure(@NonNull ClassLoader classLoader, @NonNull List .filter(Path.class::isInstance) .map(Path.class::cast) .filter(Files::exists) - .findFirst() - .map(Path::toAbsolutePath); + .map(Path::toAbsolutePath) + // Skip build directories from maven/gradle + .filter(it -> !isBinary(it, "target") && !isBinary(it, "build")) + .findFirst(); if (logPath.isPresent()) { System.setProperty(loggingService.getPropertyName(), logPath.get().toString()); return logPath.get().toString(); @@ -126,6 +136,11 @@ static String configure(@NonNull ClassLoader classLoader, @NonNull List return null; } + static boolean isBinary(Path path, String segment) { + return StreamSupport.stream(path.spliterator(), false) + .anyMatch(it -> it.toString().equals(segment)); + } + private static List logFiles( Path basedir, List profiles, List logFileNames) { for (String logFileName : logFileNames) { diff --git a/modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/RunTask.java b/modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/RunTask.java index d48be9d455..0ed58f5e74 100644 --- a/modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/RunTask.java +++ b/modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/RunTask.java @@ -88,6 +88,7 @@ public void run() throws Throwable { JoobyRunOptions config = new JoobyRunOptions(); config.setUseSingleClassLoader(useSingleClassLoader = Boolean.TRUE); + config.setBasedir(current.getProjectDir().toPath()); config.setMainClass(mainClass); config.setPort(port); if (compileExtensions != null) { diff --git a/modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java b/modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java index 9bfb09d946..b9951c8bb8 100644 --- a/modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java +++ b/modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java @@ -136,6 +136,7 @@ protected void doExecute(List projects, String mainClass) throws T private JoobyRunOptions createOptions(String mainClass) { JoobyRunOptions options = new JoobyRunOptions(); + options.setBasedir(project.getBasedir().toPath()); options.setMainClass(mainClass); if (compileExtensions != null) { options.setCompileExtensions(compileExtensions); diff --git a/modules/jooby-maven-plugin/src/test/java/io/jooby/maven/RunMojoTest.java b/modules/jooby-maven-plugin/src/test/java/io/jooby/maven/RunMojoTest.java index 266c48ea72..d27a9c1d98 100644 --- a/modules/jooby-maven-plugin/src/test/java/io/jooby/maven/RunMojoTest.java +++ b/modules/jooby-maven-plugin/src/test/java/io/jooby/maven/RunMojoTest.java @@ -23,7 +23,9 @@ public void ensureConfigurationOptions() { Stream.of(JoobyRunOptions.class.getDeclaredFields()) .filter( field -> - !field.getName().equals("projectName") && !Modifier.isStatic(field.getModifiers())) + !field.getName().equals("projectName") + && !field.getName().equals("basedir") + && !Modifier.isStatic(field.getModifiers())) .forEach( field -> { try { diff --git a/modules/jooby-run/src/main/java/io/jooby/run/JoobyRun.java b/modules/jooby-run/src/main/java/io/jooby/run/JoobyRun.java index f8fb54cfa4..42b7ec587a 100644 --- a/modules/jooby-run/src/main/java/io/jooby/run/JoobyRun.java +++ b/modules/jooby-run/src/main/java/io/jooby/run/JoobyRun.java @@ -11,6 +11,7 @@ import java.nio.file.ClosedWatchServiceException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Clock; import java.util.ArrayList; import java.util.HashMap; @@ -89,9 +90,11 @@ public Exception start() { ModuleClassLoader classLoader = module.getClassLoader(); Thread.currentThread().setContextClassLoader(classLoader); - if (counter == 0) { - // main class must exists - module.getClassLoader().loadClass(conf.getMainClass()); + // main class must exists + var mainClass = module.getClassLoader().loadClass(conf.getMainClass()); + var projectdir = baseDir(conf.getBasedir(), mainClass); + if (projectdir != null) { + System.setProperty("jooby.dir", projectdir.toString()); } System.setProperty("___jooby_run_hook__", SERVER_REF); @@ -458,6 +461,30 @@ public void shutdown() { } } + static Path baseDir(Path root, Class clazz) { + var resource = clazz.getResource("."); + if (resource != null) { + if ("file".equals(resource.getProtocol())) { + var buildFiles = new String[] {"pom.xml", "build.gradle", "build.gradle.kts"}; + var path = Paths.get(resource.getFile()); + while (path.startsWith(root)) { + + var buildFile = + Stream.of(buildFiles) + .map(path::resolve) + .filter(Files::exists) + .findFirst() + .orElse(null); + if (buildFile != null) { + return buildFile.getParent().toAbsolutePath(); + } + path = path.getParent(); + } + } + } + return null; + } + private DirectoryWatcher newWatcher() throws IOException { List paths = new ArrayList<>(watchDirs.size()); paths.addAll(watchDirs.keySet()); diff --git a/modules/jooby-run/src/main/java/io/jooby/run/JoobyRunOptions.java b/modules/jooby-run/src/main/java/io/jooby/run/JoobyRunOptions.java index 153956bf5c..e29ae29dd5 100644 --- a/modules/jooby-run/src/main/java/io/jooby/run/JoobyRunOptions.java +++ b/modules/jooby-run/src/main/java/io/jooby/run/JoobyRunOptions.java @@ -27,6 +27,7 @@ public class JoobyRunOptions { private List compileExtensions = Arrays.asList("java", "kt"); private Integer port = null; + private Path basedir; private Long waitTimeBeforeRestart = DEFAULT_WAIT_TIME_BEFORE_RESTART; @@ -180,6 +181,14 @@ public boolean isRestartExtension(Path path) { return containsExtension(restartExtensions, path); } + public Path getBasedir() { + return basedir; + } + + public void setBasedir(Path basedir) { + this.basedir = basedir; + } + private boolean containsExtension(List extensions, Path path) { String filename = path.getFileName().toString(); return extensions.stream().anyMatch(ext -> filename.endsWith("." + ext)); diff --git a/modules/jooby-run/src/test/java/io/jooby/run/BaseDirTest.java b/modules/jooby-run/src/test/java/io/jooby/run/BaseDirTest.java new file mode 100644 index 0000000000..8351ad70a5 --- /dev/null +++ b/modules/jooby-run/src/test/java/io/jooby/run/BaseDirTest.java @@ -0,0 +1,21 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.run; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; + +public class BaseDirTest { + @Test + public void findBaseDir() { + var basedir = Paths.get(System.getProperty("user.dir")); + var path = JoobyRun.baseDir(basedir, JoobyRun.class); + assertEquals(basedir, path); + } +}