You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by GitBox <gi...@apache.org> on 2021/01/25 12:57:20 UTC

[GitHub] [maven-common-artifact-filters] gnodet commented on a change in pull request #15: Big speed improvements for patterns that do not contain any wildcard

gnodet commented on a change in pull request #15:
URL: https://github.com/apache/maven-common-artifact-filters/pull/15#discussion_r563702687



##########
File path: src/test/java/org/apache/maven/shared/artifact/filter/OldPatternIncludesArtifactFilter.java
##########
@@ -0,0 +1,428 @@
+package org.apache.maven.shared.artifact.filter;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.codehaus.plexus.logging.Logger;
+
+/**
+ * TODO: include in maven-artifact in future
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @see StrictPatternIncludesArtifactFilter
+ */
+public class OldPatternIncludesArtifactFilter
+        implements ArtifactFilter, StatisticsReportingArtifactFilter
+{
+    private final List<String> positivePatterns;
+
+    private final List<String> negativePatterns;
+
+    private final boolean actTransitively;
+
+    private final Set<String> patternsTriggered = new HashSet<>();
+
+    private final List<String> filteredArtifactIds = new ArrayList<>();
+
+    /**
+     * @param patterns The pattern to be used.
+     */
+    public OldPatternIncludesArtifactFilter( final Collection<String> patterns )
+    {
+        this( patterns, false );
+    }
+
+    /**
+     * @param patterns The pattern to be used.
+     * @param actTransitively transitive yes/no.
+     */
+    public OldPatternIncludesArtifactFilter( final Collection<String> patterns, final boolean actTransitively )
+    {
+        this.actTransitively = actTransitively;
+        final List<String> pos = new ArrayList<>();
+        final List<String> neg = new ArrayList<>();
+        if ( patterns != null && !patterns.isEmpty() )
+        {
+            for ( String pattern : patterns )
+            {
+                if ( pattern.startsWith( "!" ) )
+                {
+                    neg.add( pattern.substring( 1 ) );
+                }
+                else
+                {
+                    pos.add( pattern );
+                }
+            }
+        }
+
+        positivePatterns = pos;
+        negativePatterns = neg;
+    }
+
+    /** {@inheritDoc} */
+    public boolean include( final Artifact artifact )
+    {
+        final boolean shouldInclude = patternMatches( artifact );
+
+        if ( !shouldInclude )
+        {
+            addFilteredArtifactId( artifact.getId() );
+        }
+
+        return shouldInclude;
+    }
+
+    /**
+     * @param artifact to check for.
+     * @return true if the match is true false otherwise.
+     */
+    protected boolean patternMatches( final Artifact artifact )
+    {
+        return positiveMatch( artifact ) == Boolean.TRUE || negativeMatch( artifact ) == Boolean.FALSE;
+    }
+
+    /**
+     * @param artifactId add artifact to the filtered artifacts list.
+     */
+    protected void addFilteredArtifactId( final String artifactId )
+    {
+        filteredArtifactIds.add( artifactId );
+    }
+
+    private Boolean negativeMatch( final Artifact artifact )
+    {
+        if ( negativePatterns == null || negativePatterns.isEmpty() )
+        {
+            return null;
+        }
+        else
+        {
+            return match( artifact, negativePatterns );
+        }
+    }
+
+    /**
+     * @param artifact check for positive match.
+     * @return true/false.
+     */
+    protected Boolean positiveMatch( final Artifact artifact )
+    {
+        if ( positivePatterns == null || positivePatterns.isEmpty() )
+        {
+            return null;
+        }
+        else
+        {
+            return match( artifact, positivePatterns );
+        }
+    }
+
+    private boolean match( final Artifact artifact, final List<String> patterns )
+    {
+        final String shortId = ArtifactUtils.versionlessKey( artifact );
+        final String id = artifact.getDependencyConflictId();
+        final String wholeId = artifact.getId();
+
+        if ( matchAgainst( wholeId, patterns, false ) )
+        {
+            return true;
+        }
+
+        if ( matchAgainst( id, patterns, false ) )
+        {
+            return true;
+        }
+
+        if ( matchAgainst( shortId, patterns, false ) )
+        {
+            return true;
+        }
+
+        if ( actTransitively )
+        {
+            final List<String> depTrail = artifact.getDependencyTrail();
+
+            if ( depTrail != null && depTrail.size() > 1 )
+            {
+                for ( String trailItem : depTrail )
+                {
+                    if ( matchAgainst( trailItem, patterns, true ) )
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private boolean matchAgainst( final String value, final List<String> patterns, final boolean regionMatch )
+    {
+        final String[] tokens = value.split( ":" );
+        for ( String pattern : patterns )
+        {
+            String[] patternTokens = pattern.split( ":" );
+
+            if ( patternTokens.length == 5 && tokens.length < 5 )
+            {
+                // 4th element is the classifier
+                if ( !"*".equals( patternTokens[3] ) )
+                {
+                    // classifier required, cannot be a match
+                    return false;
+                }
+                patternTokens = new String[] { patternTokens[0], patternTokens[1], patternTokens[2], patternTokens[4] };
+            }
+
+            // fail immediately if pattern tokens outnumber tokens to match
+            boolean matched = patternTokens.length <= tokens.length;
+
+            for ( int i = 0; matched && i < patternTokens.length; i++ )
+            {
+                matched = matches( tokens[i], patternTokens[i] );
+            }
+
+            // case of starting '*' like '*:jar:*'
+            // This really only matches from the end instead.....
+            if ( !matched && patternTokens.length < tokens.length && isFirstPatternWildcard( patternTokens ) )
+            {
+                matched = true;
+                int tokenOffset = tokens.length - patternTokens.length;
+                for ( int i = 0; matched && i < patternTokens.length; i++ )
+                {
+                    matched = matches( tokens[i + tokenOffset], patternTokens[i] );
+                }
+            }
+
+            if ( matched )
+            {
+                patternsTriggered.add( pattern );
+                return true;
+            }
+
+            if ( regionMatch && value.contains( pattern ) )
+            {
+                patternsTriggered.add( pattern );
+                return true;
+            }
+
+        }
+        return false;
+
+    }
+
+    private boolean isFirstPatternWildcard( String[] patternTokens )
+    {
+        return patternTokens.length > 0 && "*".equals( patternTokens[0] );
+    }
+
+    /**
+     * Gets whether the specified token matches the specified pattern segment.
+     *
+     * @param token the token to check
+     * @param pattern the pattern segment to match, as defined above
+     * @return <code>true</code> if the specified token is matched by the specified pattern segment
+     */
+    private boolean matches( final String token, final String pattern )
+    {
+        boolean matches;
+
+        // support full wildcard and implied wildcard
+        if ( "*".equals( pattern ) || pattern.length() == 0 )
+        {
+            matches = true;
+        }
+        // support contains wildcard
+        else if ( pattern.startsWith( "*" ) && pattern.endsWith( "*" ) )
+        {
+            final String contains = pattern.substring( 1, pattern.length() - 1 );
+
+            matches = token.contains( contains );
+        }
+        // support leading wildcard
+        else if ( pattern.startsWith( "*" ) )
+        {
+            final String suffix = pattern.substring( 1 );
+
+            matches = token.endsWith( suffix );
+        }
+        // support trailing wildcard
+        else if ( pattern.endsWith( "*" ) )
+        {
+            final String prefix = pattern.substring( 0, pattern.length() - 1 );
+
+            matches = token.startsWith( prefix );
+        }
+        // support wildcards in the middle of a pattern segment
+        else if ( pattern.indexOf( '*' ) > -1 )
+        {
+            String[] parts = pattern.split( "\\*" );
+            int lastPartEnd = -1;
+            boolean match = true;
+
+            for ( String part : parts )
+            {
+                int idx = token.indexOf( part );
+                if ( idx <= lastPartEnd )
+                {
+                    match = false;
+                    break;
+                }
+
+                lastPartEnd = idx + part.length();
+            }
+
+            matches = match;
+        }
+        // support versions range
+        else if ( pattern.startsWith( "[" ) || pattern.startsWith( "(" ) )
+        {
+            matches = isVersionIncludedInRange( token, pattern );
+        }
+        // support exact match
+        else
+        {
+            matches = token.equals( pattern );
+        }
+
+        return matches;
+    }
+
+    private boolean isVersionIncludedInRange( final String version, final String range )
+    {
+        try
+        {
+            return VersionRange.createFromVersionSpec( range ).containsVersion( new DefaultArtifactVersion( version ) );
+        }
+        catch ( final InvalidVersionSpecificationException e )
+        {
+            return false;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void reportMissedCriteria( final Logger logger )
+    {
+        // if there are no patterns, there is nothing to report.
+        if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
+        {
+            final List<String> missed = new ArrayList<>();
+            missed.addAll( positivePatterns );
+            missed.addAll( negativePatterns );
+
+            missed.removeAll( patternsTriggered );
+
+            if ( !missed.isEmpty() && logger.isWarnEnabled() )
+            {
+                final StringBuilder buffer = new StringBuilder();
+
+                buffer.append( "The following patterns were never triggered in this " );
+                buffer.append( getFilterDescription() );
+                buffer.append( ':' );
+
+                for ( String pattern : missed )
+                {
+                    buffer.append( "\no  '" ).append( pattern ).append( "'" );

Review comment:
       See https://github.com/apache/maven-common-artifact-filters/pull/15#issuecomment-766796366
   I'm trying to minimise the refactoring in my commits, so don't blame me because the current code is not up to your standards :-)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org