You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/10/22 20:44:05 UTC
(maven) branch maven-3.9.x updated: Resolve multiModuleProjectDirectory lexically instead of canonically (fix #11167) (#13676)
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch maven-3.9.x
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-3.9.x by this push:
new 9c299cba8a Resolve multiModuleProjectDirectory lexically instead of canonically (fix #11167) (#13676)
9c299cba8a is described below
commit 9c299cba8a3ae6a8ee6d39b77791edf02feddec9
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Oct 22 22:43:59 2026 +0200
Resolve multiModuleProjectDirectory lexically instead of canonically (fix #11167) (#13676)
getCanonicalFile() asks the OS to resolve the path, which can follow a
symlink, a junction, or (since JDK-8355342, on JDK 25+) a mapped
Windows network drive to a different location, corrupting the reactor
root that every module/parent path is resolved against.
Routed through the same getCanonicalPath(Path) helper this class
already uses elsewhere since #11250, which only normalizes the path
lexically (toAbsolutePath().normalize()).
Backport of #13650 to maven-3.9.x; also fixes the toRealPath() issue
in the getCanonicalPath() helper which was not addressed by #11250 on
this branch.
---
.../main/java/org/apache/maven/cli/MavenCli.java | 17 ++++++--------
.../java/org/apache/maven/cli/MavenCliTest.java | 27 ++++++++++++++++++++++
2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 5a8bb5523d..0fa53a26af 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -315,11 +315,12 @@ void initialize(CliRequest cliRequest) throws ExitException {
throw new ExitException(1);
}
File basedir = basedirProperty != null ? new File(basedirProperty) : new File("");
- try {
- cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
- } catch (IOException e) {
- cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
- }
+ // Resolve lexically rather than through getCanonicalFile(), which asks the OS to resolve the path
+ // and can substitute it with a different one when a segment is a symlink, junction, or (on Windows)
+ // a mapped network drive, corrupting the reactor root that every relative module/parent path is
+ // later resolved against (MNG-11167).
+ cliRequest.multiModuleProjectDirectory =
+ getCanonicalPath(basedir.toPath()).toFile();
}
// We need to locate the top level project which may be pointed at using
@@ -1623,11 +1624,7 @@ private static String stripLeadingAndTrailingQuotes(String str) {
}
private static Path getCanonicalPath(Path path) {
- try {
- return path.toRealPath();
- } catch (IOException e) {
- return getCanonicalPath(path.getParent()).resolve(path.getFileName());
- }
+ return path.toAbsolutePath().normalize();
}
static class ExitException extends Exception {
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index 108667ed07..564b1fb465 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -20,8 +20,11 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.cli.ParseException;
@@ -34,6 +37,7 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import org.mockito.InOrder;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@@ -132,6 +136,29 @@ public void testMavenConfigInvalid() throws Exception {
}
}
+ /**
+ * MNG-11167: {@code multiModuleProjectDirectory} must keep the path as given, not the path that
+ * {@link File#getCanonicalFile()} resolves a symlinked (or, on Windows, a mapped network drive)
+ * segment to, or every module/parent path resolved relative to it inherits the wrong base.
+ */
+ @Test
+ public void testMultiModuleProjectDirectoryIsNotResolvedThroughASymlink(@TempDir Path tempDir) throws Exception {
+ Path real = Files.createDirectories(tempDir.resolve("real"));
+ Path link = tempDir.resolve("link");
+ try {
+ Files.createSymbolicLink(link, real);
+ } catch (IOException | UnsupportedOperationException e) {
+ assumeTrue(false, "symbolic links are not supported on this machine");
+ }
+
+ System.setProperty(MavenCli.MULTIMODULE_PROJECT_DIRECTORY, link.toString());
+ CliRequest request = new CliRequest(new String[0], null);
+
+ cli.initialize(request);
+
+ assertEquals(link.toString(), request.multiModuleProjectDirectory.getPath());
+ }
+
/**
* Read .mvn/maven.config with the following definitions:
* <pre>