Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.services;

import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.Collection;

import org.apache.maven.api.Service;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;

/**
* Service for creating {@link PathMatcher} objects that can be used to filter files
* based on include/exclude patterns. This service provides a clean API for plugins
* to create path matchers without directly depending on implementation classes.
* <p>
* The path matchers created by this service support Maven's traditional include/exclude
* pattern syntax, which is compatible with the behavior of Maven 3 plugins like
* maven-compiler-plugin and maven-clean-plugin.
* <p>
* Pattern syntax supports:
* <ul>
* <li>Standard glob patterns with {@code *}, {@code ?}, and {@code **} wildcards</li>
* <li>Explicit syntax prefixes like {@code "glob:"} or {@code "regex:"}</li>
* <li>Maven 3 compatible behavior for patterns without explicit syntax</li>
* <li>Default exclusion patterns for SCM files when requested</li>
* </ul>
*
* @since 4.0.0
* @see PathMatcher
*/
@Experimental
public interface PathMatcherFactory extends Service {

/**
* Creates a path matcher for filtering files based on include and exclude patterns.
* <p>
* The pathnames used for matching will be relative to the specified base directory
* and use {@code '/'} as separator, regardless of the hosting operating system.
*
* @param baseDirectory the base directory for relativizing paths during matching
* @param includes the patterns of files to include, or null/empty for including all files
* @param excludes the patterns of files to exclude, or null/empty for no exclusion
* @param useDefaultExcludes whether to augment excludes with default SCM exclusion patterns
* @return a PathMatcher that can be used to test if paths should be included
* @throws NullPointerException if baseDirectory is null
*/
@Nonnull
PathMatcher createPathMatcher(
@Nonnull Path baseDirectory,
Collection<String> includes,
Collection<String> excludes,
boolean useDefaultExcludes);

/**
* Creates a path matcher for filtering files based on include and exclude patterns,
* without using default exclusion patterns.
* <p>
* This is equivalent to calling {@link #createPathMatcher(Path, Collection, Collection, boolean)}
* with {@code useDefaultExcludes = false}.
*
* @param baseDirectory the base directory for relativizing paths during matching
* @param includes the patterns of files to include, or null/empty for including all files
* @param excludes the patterns of files to exclude, or null/empty for no exclusion
* @return a PathMatcher that can be used to test if paths should be included
* @throws NullPointerException if baseDirectory is null
*/
@Nonnull
default PathMatcher createPathMatcher(
@Nonnull Path baseDirectory, Collection<String> includes, Collection<String> excludes) {
return createPathMatcher(baseDirectory, includes, excludes, false);
}

/**
* Creates a path matcher that includes all files except those matching the exclude patterns.
* <p>
* This is equivalent to calling {@link #createPathMatcher(Path, Collection, Collection, boolean)}
* with {@code includes = null}.
*
* @param baseDirectory the base directory for relativizing paths during matching
* @param excludes the patterns of files to exclude, or null/empty for no exclusion
* @param useDefaultExcludes whether to augment excludes with default SCM exclusion patterns
* @return a PathMatcher that can be used to test if paths should be included
* @throws NullPointerException if baseDirectory is null
*/
@Nonnull
default PathMatcher createExcludeOnlyMatcher(
@Nonnull Path baseDirectory, Collection<String> excludes, boolean useDefaultExcludes) {
return createPathMatcher(baseDirectory, null, excludes, useDefaultExcludes);
}

/**
* Creates a path matcher that only includes files matching the include patterns.
* <p>
* This is equivalent to calling {@link #createPathMatcher(Path, Collection, Collection, boolean)}
* with {@code excludes = null} and {@code useDefaultExcludes = false}.
*
* @param baseDirectory the base directory for relativizing paths during matching
* @param includes the patterns of files to include, or null/empty for including all files
* @return a PathMatcher that can be used to test if paths should be included
* @throws NullPointerException if baseDirectory is null
*/
@Nonnull
default PathMatcher createIncludeOnlyMatcher(@Nonnull Path baseDirectory, Collection<String> includes) {
return createPathMatcher(baseDirectory, includes, null, false);
}

/**
* Returns a filter for directories that may contain paths accepted by the given matcher.
* The given path matcher should be an instance created by this service.
* The path matcher returned by this method expects <em>directory</em> paths.
* If that matcher returns {@code false}, then the directory will definitively not contain
* the paths selected by the matcher given in argument to this method.
* In such case, the whole directory and all its sub-directories can be skipped.
* In case of doubt, or if the matcher given in argument is not recognized by this method,
* then the matcher returned by this method will return {@code true}.
*
* @param fileMatcher a matcher created by one of the other methods of this interface
* @return filter for directories that may contain the selected files
* @throws NullPointerException if fileMatcher is null
*/
@Nonnull
PathMatcher deriveDirectoryMatcher(@Nonnull PathMatcher fileMatcher);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.impl;

import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.Collection;
import java.util.Objects;

import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.di.Singleton;
import org.apache.maven.api.services.PathMatcherFactory;

import static java.util.Objects.requireNonNull;

/**
* Default implementation of {@link PathMatcherFactory} that creates {@link PathSelector}
* instances for filtering files based on include/exclude patterns.
* <p>
* This implementation provides Maven's traditional include/exclude pattern behavior,
* compatible with Maven 3 plugins like maven-compiler-plugin and maven-clean-plugin.
*
* @since 4.0.0
*/
@Named
@Singleton
public class DefaultPathMatcherFactory implements PathMatcherFactory {

@Nonnull
@Override
public PathMatcher createPathMatcher(
@Nonnull Path baseDirectory,
Collection<String> includes,
Collection<String> excludes,
boolean useDefaultExcludes) {
requireNonNull(baseDirectory, "baseDirectory cannot be null");

return new PathSelector(baseDirectory, includes, excludes, useDefaultExcludes);
}

@Nonnull
@Override
public PathMatcher createExcludeOnlyMatcher(
@Nonnull Path baseDirectory, Collection<String> excludes, boolean useDefaultExcludes) {
return createPathMatcher(baseDirectory, null, excludes, useDefaultExcludes);
}

@Nonnull
@Override
public PathMatcher deriveDirectoryMatcher(@Nonnull PathMatcher fileMatcher) {
if (Objects.requireNonNull(fileMatcher) instanceof PathSelector selector) {
if (selector.canFilterDirectories()) {
return selector::couldHoldSelected;
}
}
return PathSelector.INCLUDES_ALL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.apache.maven.api.annotations.Nonnull;

/**
* Determines whether a path is selected according to include/exclude patterns.
* The pathnames used for method parameters will be relative to some base directory
Expand Down Expand Up @@ -163,7 +166,7 @@ public class PathSelector implements PathMatcher {
*
* @see #simplify()
*/
private static final PathMatcher INCLUDES_ALL = (path) -> true;
static final PathMatcher INCLUDES_ALL = (path) -> true;

/**
* String representations of the normalized include filters.
Expand Down Expand Up @@ -219,13 +222,17 @@ public class PathSelector implements PathMatcher {
* @param includes the patterns of the files to include, or null or empty for including all files
* @param excludes the patterns of the files to exclude, or null or empty for no exclusion
* @param useDefaultExcludes whether to augment the excludes with a default set of <abbr>SCM</abbr> patterns
* @throws NullPointerException if directory is null
*/
public PathSelector(
Path directory, Collection<String> includes, Collection<String> excludes, boolean useDefaultExcludes) {
@Nonnull Path directory,
Collection<String> includes,
Collection<String> excludes,
boolean useDefaultExcludes) {
baseDirectory = Objects.requireNonNull(directory, "directory cannot be null");
includePatterns = normalizePatterns(includes, false);
excludePatterns = normalizePatterns(effectiveExcludes(excludes, includePatterns, useDefaultExcludes), true);
baseDirectory = directory;
FileSystem system = directory.getFileSystem();
FileSystem system = baseDirectory.getFileSystem();
this.includes = matchers(system, includePatterns);
this.excludes = matchers(system, excludePatterns);
dirIncludes = matchers(system, directoryPatterns(includePatterns, false));
Expand Down Expand Up @@ -570,6 +577,17 @@ private static boolean isMatched(Path path, PathMatcher[] matchers) {
return false;
}

/**
* Returns whether {@link #couldHoldSelected(Path)} may return {@code false} for some directories.
* This method can be used to determine if directory filtering optimization is possible.
*
* @return {@code true} if directory filtering is possible, {@code false} if all directories
* will be considered as potentially containing selected files
*/
boolean canFilterDirectories() {
return dirIncludes.length != 0 || dirExcludes.length != 0;
}

/**
* Determines whether a directory could contain selected paths.
*
Expand Down
Loading
Loading