From 4832b1caa7554598a45d185897b1769a24e78f45 Mon Sep 17 00:00:00 2001 From: Leo Camus Date: Thu, 17 Sep 2026 15:35:18 +0200 Subject: [PATCH 1/2] Fix glob patterns in exists()/missing() profile conditions on Windows DefaultProfileActivationContext aligned the whole pattern to the project directory before splitting it into a fixed directory and a glob. On Windows this breaks both kinds of pattern: - an absolute pattern such as '${project.basedir}/src/**/*.xsd' leaves a glob with backslash separators ('**\*.xsd'), and the glob syntax reads '\' as an escape character, so nothing ever matches: exists() is always false and missing() always true; - a relative pattern such as '**/*.xsd' is resolved with Path.resolve(), which throws InvalidPathException because '*' is not a valid Windows path character. Split the interpolated pattern first, align only the fixed part, and use '/' as the separator in the glob. testFileWilcards, disabled since the condition activator was added, passes on Linux and Windows now and is enabled again. --- .../DefaultProfileActivationContext.java | 27 ++++++++++--------- .../ConditionProfileActivatorTest.java | 3 ++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java index 0fa7765d147f..25dc8000b6d3 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java @@ -18,7 +18,6 @@ */ package org.apache.maven.impl.model; -import java.io.File; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -366,10 +365,14 @@ public DefaultProfileActivationContext setModel(Model model) { @Override public String interpolatePath(String path) throws InterpolatorException { + return pathTranslator.alignToBaseDirectory(interpolate(path), model.getProjectDirectory()); + } + + private String interpolate(String path) throws InterpolatorException { if (path == null) { return null; } - String absolutePath = interpolator.interpolate(path, s -> { + return interpolator.interpolate(path, s -> { if ("basedir".equals(s) || "project.basedir".equals(s)) { return getModelBaseDirectory(); } @@ -385,7 +388,6 @@ public String interpolatePath(String path) throws InterpolatorException { } return r; }); - return pathTranslator.alignToBaseDirectory(absolutePath, model.getProjectDirectory()); } @Override @@ -399,9 +401,10 @@ public boolean exists(String path, boolean enableGlob) throws ModelBuilderExcept } private boolean doExists(String path, boolean enableGlob) throws ModelBuilderException { - String pattern = interpolatePath(path); String fixed, glob; if (enableGlob) { + // split before aligning to the base directory: '*' and '?' are not valid in a Windows path + String pattern = interpolate(path); int asteriskIndex = pattern.indexOf('*'); int questionMarkIndex = pattern.indexOf('?'); int firstWildcardIndex = questionMarkIndex < 0 @@ -411,17 +414,15 @@ private boolean doExists(String path, boolean enableGlob) throws ModelBuilderExc fixed = pattern; glob = ""; } else { - int lastSep = pattern.substring(0, firstWildcardIndex).lastIndexOf(File.separatorChar); - if (lastSep < 0) { - fixed = ""; - glob = pattern; - } else { - fixed = pattern.substring(0, lastSep); - glob = pattern.substring(lastSep + 1); - } + String prefix = pattern.substring(0, firstWildcardIndex); + int lastSep = Math.max(prefix.lastIndexOf('/'), prefix.lastIndexOf('\\')); + fixed = pattern.substring(0, lastSep + 1); + // '\' is an escape character in the glob syntax, on Windows too, where '/' matches the separator + glob = pattern.substring(lastSep + 1).replace('\\', '/'); } + fixed = pathTranslator.alignToBaseDirectory(fixed, model.getProjectDirectory()); } else { - fixed = pattern; + fixed = interpolatePath(path); glob = ""; } Path fixedPath = Paths.get(fixed); diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java index 5d371c2fc3cc..8451375f5174 100644 --- a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java +++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java @@ -401,13 +401,14 @@ void testFileRootDirectory() { } @Test - @Disabled void testFileWilcards() { assertActivation(true, newProfile("exists('${project.rootDirectory}/**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("exists('${project.basedir}/**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("exists('${project.basedir}/**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("exists('**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("missing('**/*.xml')"), newFileContext()); + assertActivation(false, newProfile("missing('${project.basedir}/**/*.xsd')"), newFileContext()); + assertActivation(false, newProfile("exists('${project.basedir}/**/*.xml')"), newFileContext()); } @Test From 475f72640b83d7dc1b0f9f761abf504646037927 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 17 Sep 2026 15:38:08 +0000 Subject: [PATCH 2/2] Remove duplicate assertion in testFileWilcards --- .../maven/impl/model/profile/ConditionProfileActivatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java index 8451375f5174..ca9194f02428 100644 --- a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java +++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/profile/ConditionProfileActivatorTest.java @@ -404,7 +404,6 @@ void testFileRootDirectory() { void testFileWilcards() { assertActivation(true, newProfile("exists('${project.rootDirectory}/**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("exists('${project.basedir}/**/*.xsd')"), newFileContext()); - assertActivation(true, newProfile("exists('${project.basedir}/**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("exists('**/*.xsd')"), newFileContext()); assertActivation(true, newProfile("missing('**/*.xml')"), newFileContext()); assertActivation(false, newProfile("missing('${project.basedir}/**/*.xsd')"), newFileContext());