Skip to content

Commit

Permalink
Improve artifact filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexisJehan committed Sep 25, 2024
1 parent ab65555 commit e5730a1
Show file tree
Hide file tree
Showing 13 changed files with 864 additions and 171 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

### Improvements
- Improve the _Maven Artifact Resolver_ usage by migrating from `Eclipse Sisu` to `Supplier`
- Improve artifact filtering, wildcard characters are now supported in the group identifier and the artifact identifier
as well as in the update version
- Build files from output directories (`target` for _Maven_ and `build` for _Gradle_) are now excluded by default

### Notes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
package com.github.alexisjehan.mvncheck;

import com.github.alexisjehan.javanilla.lang.Strings;
import com.github.alexisjehan.javanilla.lang.Throwables;
import com.github.alexisjehan.javanilla.misc.quality.Ensure;
import com.github.alexisjehan.javanilla.misc.quality.ToString;
Expand Down Expand Up @@ -411,7 +412,7 @@ void run(
.a(toString(artifact.getType()))
.reset()
.a("] ")
.a(artifact.isVersionInherited() ? "(" : "")
.a(artifact.isVersionInherited() ? "(" : Strings.EMPTY)
.a(toString(artifact.getIdentifier()))
.a(" ")
.fgBrightYellow()
Expand All @@ -421,7 +422,7 @@ void run(
.fgBrightGreen()
.a(updateVersion)
.reset()
.a(artifact.isVersionInherited() ? ")" : "")
.a(artifact.isVersionInherited() ? ")" : Strings.EMPTY)
);
++artifactsUpdatesCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public List<ArtifactUpdateVersion> findArtifactUpdateVersions(
final boolean ignoreSnapshots
) throws IOException {
Ensure.notNull("build", build);
final var artifactFilter = new CompositeArtifactFilter(
final var artifactFilter = CompositeArtifactFilter.all(
userArtifactFilter,
createBuildArtifactFilter(build.getFile())
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,23 @@

import java.util.Arrays;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* <p>Class that describes a composite artifact filter.</p>
* @since 1.0.0
*/
public final class CompositeArtifactFilter implements ArtifactFilter {

/**
* <p>Match {@link BiFunction}.</p>
* @since 1.7.0
*/
private final BiFunction<Stream<ArtifactFilter>, Predicate<ArtifactFilter>, Boolean> matchFunction;

/**
* <p>{@link Set} of artifact filters.</p>
* @since 1.0.0
Expand All @@ -47,11 +56,28 @@ public final class CompositeArtifactFilter implements ArtifactFilter {
* @param filters an array of artifact filters
* @throws NullPointerException if the array of artifacts or any of them is {@code null}
* @throws IllegalArgumentException if the array of artifacts is empty
* @deprecated since 1.7.0, use {@link #all(ArtifactFilter...)} instead
* @since 1.0.0
*/
@Deprecated(since = "1.7.0")
public CompositeArtifactFilter(final ArtifactFilter... filters) {
Ensure.notNullAndNotEmpty("filters", filters);
Ensure.notNullAndNotNullElements("filters", filters);
this(
Stream::allMatch,
Ensure.notNullAndNotNullElements("filters", Ensure.notNullAndNotEmpty("filters", filters))
);
}

/**
* <p>Private constructor.</p>
* @param matchFunction a match {@link BiFunction}
* @param filters an array of artifact filters
* @since 1.7.0
*/
private CompositeArtifactFilter(
final BiFunction<Stream<ArtifactFilter>, Predicate<ArtifactFilter>, Boolean> matchFunction,
final ArtifactFilter... filters
) {
this.matchFunction = matchFunction;
this.filters = Arrays.stream(filters)
.collect(Collectors.toUnmodifiableSet());
}
Expand All @@ -64,8 +90,7 @@ public CompositeArtifactFilter(final ArtifactFilter... filters) {
@Override
public boolean accept(final Artifact<?> artifact) {
Ensure.notNull("artifact", artifact);
return filters.stream()
.allMatch(filter -> filter.accept(artifact));
return matchFunction.apply(filters.stream(), filter -> filter.accept(artifact));
}

/**
Expand All @@ -78,7 +103,48 @@ public boolean accept(final Artifact<?> artifact) {
public boolean accept(final Artifact<?> artifact, final String updateVersion) {
Ensure.notNull("artifact", artifact);
Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
return filters.stream()
.allMatch(filter -> filter.accept(artifact, updateVersion));
return matchFunction.apply(filters.stream(), filter -> filter.accept(artifact, updateVersion));
}

/**
* <p>Create an instance that test whether all filters are accepted.</p>
* @param filters an array of artifact filters
* @return the created instance
* @throws NullPointerException if the array of artifacts or any of them is {@code null}
* @throws IllegalArgumentException if the array of artifacts is empty
* @since 1.7.0
*/
public static CompositeArtifactFilter all(final ArtifactFilter... filters) {
Ensure.notNullAndNotEmpty("filters", filters);
Ensure.notNullAndNotNullElements("filters", filters);
return new CompositeArtifactFilter(Stream::allMatch, filters);
}

/**
* <p>Create an instance that test whether any filters are accepted.</p>
* @param filters an array of artifact filters
* @return the created instance
* @throws NullPointerException if the array of artifacts or any of them is {@code null}
* @throws IllegalArgumentException if the array of artifacts is empty
* @since 1.7.0
*/
public static CompositeArtifactFilter any(final ArtifactFilter... filters) {
Ensure.notNullAndNotEmpty("filters", filters);
Ensure.notNullAndNotNullElements("filters", filters);
return new CompositeArtifactFilter(Stream::anyMatch, filters);
}

/**
* <p>Create an instance that test whether no filters are accepted.</p>
* @param filters an array of artifact filters
* @return the created instance
* @throws NullPointerException if the array of artifacts or any of them is {@code null}
* @throws IllegalArgumentException if the array of artifacts is empty
* @since 1.7.0
*/
public static CompositeArtifactFilter none(final ArtifactFilter... filters) {
Ensure.notNullAndNotEmpty("filters", filters);
Ensure.notNullAndNotNullElements("filters", filters);
return new CompositeArtifactFilter(Stream::noneMatch, filters);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Alexis Jehan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.alexisjehan.mvncheck.core.component.filter.artifact;

import com.github.alexisjehan.javanilla.misc.quality.Ensure;
import com.github.alexisjehan.mvncheck.core.component.artifact.Artifact;

import java.util.regex.Pattern;

/**
* <p>Class that describes an artifact filter based on expressions that can contain wildcard characters.</p>
* @since 1.7.0
*/
public final class WildcardArtifactFilter implements ArtifactFilter {

/**
* <p>Single character wildcard.</p>
* @since 1.7.0
*/
private static final char WILDCARD_SINGLE = '?';

/**
* <p>Any characters wildcard.</p>
* @since 1.7.0
*/
private static final char WILDCARD_ANY = '*';

/**
* <p>{@link Pattern} of the group identifier.</p>
* @since 1.7.0
*/
private final Pattern groupIdPattern;

/**
* <p>{@link Pattern} of the artifact identifier or {@code null}.</p>
* @since 1.7.0
*/
private final Pattern artifactIdPattern;

/**
* <p>{@link Pattern} of the update version or {@code null}.</p>
* @since 1.7.0
*/
private final Pattern updateVersionPattern;

/**
* <p>Constructor with a group identifier expression.</p>
* @param groupIdExpression a group identifier expression
* @throws NullPointerException if the group identifier expression is {@code null}
* @throws IllegalArgumentException if the group identifier expression is empty
* @since 1.7.0
*/
public WildcardArtifactFilter(
final String groupIdExpression
) {
this(groupIdExpression, null);
}

/**
* <p>Constructor with a group identifier expression and an artifact identifier expression.</p>
* @param groupIdExpression a group identifier expression
* @param artifactIdExpression an artifact identifier expression or {@code null}
* @throws NullPointerException if the group identifier expression is {@code null}
* @throws IllegalArgumentException if the group identifier expression or the artifact identifier expression is
* empty
* @since 1.7.0
*/
public WildcardArtifactFilter(
final String groupIdExpression,
final String artifactIdExpression
) {
this(groupIdExpression, artifactIdExpression, null);
}

/**
* <p>Constructor with a group identifier expression, an artifact identifier expression and an update version
* expression.</p>
* @param groupIdExpression a group identifier expression
* @param artifactIdExpression an artifact identifier expression or {@code null}
* @param updateVersionExpression an update version expression or {@code null}
* @throws NullPointerException if the group identifier expression is {@code null}
* @throws IllegalArgumentException if the group identifier expression, the artifact identifier expression or the
* update version expression is empty
* @since 1.7.0
*/
public WildcardArtifactFilter(
final String groupIdExpression,
final String artifactIdExpression,
final String updateVersionExpression
) {
Ensure.notNullAndNotEmpty("groupIdExpression", groupIdExpression);
groupIdPattern = createPattern(groupIdExpression);
if (null != artifactIdExpression) {
Ensure.notNullAndNotEmpty("artifactIdExpression", artifactIdExpression);
artifactIdPattern = createPattern(artifactIdExpression);
} else {
artifactIdPattern = null;
}
if (null != updateVersionExpression) {
Ensure.notNullAndNotEmpty("updateVersionExpression", updateVersionExpression);
updateVersionPattern = createPattern(updateVersionExpression);
} else {
updateVersionPattern = null;
}
}

/**
* {@inheritDoc}
* @throws NullPointerException if the artifact is {@code null}
* @since 1.7.0
*/
@Override
public boolean accept(final Artifact<?> artifact) {
Ensure.notNull("artifact", artifact);
final var artifactIdentifier = artifact.getIdentifier();
final var groupId = artifactIdentifier.getGroupId();
final var artifactId = artifactIdentifier.getArtifactId();
return groupIdPattern.matcher(groupId).matches()
&& (null == artifactIdPattern || artifactIdPattern.matcher(artifactId).matches());
}

/**
* {@inheritDoc}
* @throws NullPointerException if the artifact or the update version is {@code null}
* @throws IllegalArgumentException if the update version is empty
* @since 1.7.0
*/
@Override
public boolean accept(final Artifact<?> artifact, final String updateVersion) {
Ensure.notNull("artifact", artifact);
Ensure.notNullAndNotEmpty("updateVersion", updateVersion);
return accept(artifact)
&& (null == updateVersionPattern || updateVersionPattern.matcher(updateVersion).matches());
}

/**
* <p>Create a {@link Pattern} from an expression.</p>
* @param expression an expression
* @return the {@link Pattern}
* @since 1.7.0
*/
private static Pattern createPattern(final String expression) {
return Pattern.compile(
"^" + Pattern.quote(expression)
.replace(String.valueOf(WILDCARD_SINGLE), "\\E.\\Q")
.replace(String.valueOf(WILDCARD_ANY), "\\E.*\\Q") + "$",
Pattern.CASE_INSENSITIVE
);
}
}
Loading

0 comments on commit e5730a1

Please sign in to comment.