This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch maven-4.0.x in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-4.0.x by this push: new f1a8e5a0b5 [maven-4.0.x] Port the bug fixes identified when using that class in Maven clean and compiler plugin (#10935) (#10936) f1a8e5a0b5 is described below commit f1a8e5a0b53d406c6f6ef172cebbfdcce8a2cc4b Author: Guillaume Nodet <gno...@gmail.com> AuthorDate: Thu Jul 24 11:53:22 2025 +0200 [maven-4.0.x] Port the bug fixes identified when using that class in Maven clean and compiler plugin (#10935) (#10936) * Port the bug fixes identified when using that class in Maven clean and compiler plugin (#10935) Co-authored-by: Martin Desruisseaux <martin.desruisse...@geomatys.com> (cherry picked from commit 012ea25636738b4b3661dc1b13af5d2fa65aa5a4) * Fixes --------- Co-authored-by: Martin Desruisseaux <martin.desruisse...@geomatys.com> --- .../java/org/apache/maven/impl/PathSelector.java | 66 +++++++++++++++++----- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/PathSelector.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/PathSelector.java index 490739c935..348d47887b 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/PathSelector.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/PathSelector.java @@ -59,9 +59,6 @@ * If above changes are not desired, put an explicit {@code "glob:"} prefix before the pattern. * Note that putting such a prefix is recommended anyway for better performances. * - * @author Benjamin Bentmann - * @author Martin Desruisseaux - * * @see java.nio.file.FileSystem#getPathMatcher(String) */ public class PathSelector implements PathMatcher { @@ -171,6 +168,7 @@ public class PathSelector implements PathMatcher { /** * String representations of the normalized include filters. * Each pattern shall be prefixed by its syntax, which is {@value #DEFAULT_SYNTAX} by default. + * An empty array means to include all files. * * @see #toString() */ @@ -178,7 +176,8 @@ public class PathSelector implements PathMatcher { /** * String representations of the normalized exclude filters. - * Each pattern shall be prefixed by its syntax, which is {@value #DEFAULT_SYNTAX} by default. + * Each pattern shall be prefixed by its syntax. If no syntax is specified, + * the default is a Maven 3 syntax similar, but not identical, to {@value #DEFAULT_SYNTAX}. * This array may be longer or shorter than the user-supplied excludes, depending on whether * default excludes have been added and whether some unnecessary excludes have been omitted. * @@ -188,6 +187,7 @@ public class PathSelector implements PathMatcher { /** * The matcher for includes. The length of this array is equal to {@link #includePatterns} array length. + * An empty array means to include all files. */ private final PathMatcher[] includes; @@ -200,6 +200,7 @@ public class PathSelector implements PathMatcher { * The matcher for all directories to include. This array includes the parents of all those directories, * because they need to be accepted before we can walk to the sub-directories. * This is an optimization for skipping whole directories when possible. + * An empty array means to include all directories. */ private final PathMatcher[] dirIncludes; @@ -215,6 +216,13 @@ public class PathSelector implements PathMatcher { */ private final Path baseDirectory; + /** + * Whether paths must be relativized before being given to a matcher. If {@code true}, then every paths + * will be made relative to {@link #baseDirectory} for allowing patterns like {@code "foo/bar/*.java"} + * to work. As a slight optimization, we can skip this step if all patterns start with {@code "**"}. + */ + private final boolean needRelativize; + /** * Creates a new selector from the given includes and excludes. * @@ -232,17 +240,18 @@ public PathSelector( baseDirectory = Objects.requireNonNull(directory, "directory cannot be null"); includePatterns = normalizePatterns(includes, false); excludePatterns = normalizePatterns(effectiveExcludes(excludes, includePatterns, useDefaultExcludes), true); - FileSystem system = baseDirectory.getFileSystem(); - this.includes = matchers(system, includePatterns); - this.excludes = matchers(system, excludePatterns); - dirIncludes = matchers(system, directoryPatterns(includePatterns, false)); - dirExcludes = matchers(system, directoryPatterns(excludePatterns, true)); + FileSystem fileSystem = baseDirectory.getFileSystem(); + this.includes = matchers(fileSystem, includePatterns); + this.excludes = matchers(fileSystem, excludePatterns); + dirIncludes = matchers(fileSystem, directoryPatterns(includePatterns, false)); + dirExcludes = matchers(fileSystem, directoryPatterns(excludePatterns, true)); + needRelativize = needRelativize(includePatterns) || needRelativize(excludePatterns); } /** * Returns the given array of excludes, optionally expanded with a default set of excludes, * then with unnecessary excludes omitted. An unnecessary exclude is an exclude which will never - * match a file because there is no include which would accept a file that could match the exclude. + * match a file because there are no includes which would accept a file that could match the exclude. * For example, if the only include is {@code "*.java"}, then the <code>"**/project.pj"</code>, * <code>"**/.DS_Store"</code> and other excludes will never match a file and can be omitted. * Because the list of {@linkplain #DEFAULT_EXCLUDES default excludes} contains many elements, @@ -269,10 +278,14 @@ private static Collection<String> effectiveExcludes( } } else { excludes = new ArrayList<>(excludes); + excludes.removeIf(Objects::isNull); if (useDefaultExcludes) { excludes.addAll(DEFAULT_EXCLUDES); } } + if (includes.length == 0) { + return excludes; + } /* * Get the prefixes and suffixes of all includes, stopping at the first special character. * Redundant prefixes and suffixes are omitted. @@ -473,7 +486,7 @@ private static void addPatternsWithOneDirRemoved(final Set<String> patterns, fin * Applies some heuristic rules for simplifying the set of patterns, * then returns the patterns as an array. * - * @param patterns the patterns to simplify and return asarray + * @param patterns the patterns to simplify and return as an array * @param excludes whether the patterns are exclude patterns * @return the set content as an array, after simplification */ @@ -497,7 +510,7 @@ private static String[] simplify(Set<String> patterns, boolean excludes) { * * @param patterns the normalized include or exclude patterns * @param excludes whether the patterns are exclude patterns - * @return pattens of directories to include or exclude + * @return patterns of directories to include or exclude */ private static String[] directoryPatterns(final String[] patterns, final boolean excludes) { // TODO: use `LinkedHashSet.newLinkedHashSet(int)` instead with JDK19. @@ -523,6 +536,21 @@ private static String[] directoryPatterns(final String[] patterns, final boolean return simplify(directories, excludes); } + /** + * Returns {@code true} if at least one pattern requires path being relativized before to be matched. + * + * @param patterns include or exclude patterns + * @return whether at least one pattern require relativization + */ + private static boolean needRelativize(String[] patterns) { + for (String pattern : patterns) { + if (!pattern.startsWith(DEFAULT_SYNTAX + "**/")) { + return true; + } + } + return false; + } + /** * Creates the path matchers for the given patterns. * The syntax (usually {@value #DEFAULT_SYNTAX}) must be specified for each pattern. @@ -535,12 +563,20 @@ private static PathMatcher[] matchers(final FileSystem fs, final String[] patter return matchers; } + /** + * {@return whether there are no include or exclude filters}. + * In such case, this {@code PathSelector} instance should be ignored. + */ + public boolean isEmpty() { + return includes.length == 0 && excludes.length == 0; + } + /** * {@return a potentially simpler matcher equivalent to this matcher}. */ @SuppressWarnings("checkstyle:MissingSwitchDefault") public PathMatcher simplify() { - if (excludes.length == 0) { + if (!needRelativize && excludes.length == 0) { switch (includes.length) { case 0: return INCLUDES_ALL; @@ -560,7 +596,9 @@ public PathMatcher simplify() { */ @Override public boolean matches(Path path) { - path = baseDirectory.relativize(path); + if (needRelativize) { + path = baseDirectory.relativize(path); + } return (includes.length == 0 || isMatched(path, includes)) && (excludes.length == 0 || !isMatched(path, excludes)); }