blob: ce9d9e5c61ca9813b9b0379febbd38b7e15d5670 [file] [log] [blame]
/*
* 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.shared.artifact.filter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
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.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.StringUtils;
/**
* TODO: include in maven-artifact in future
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @see StrictPatternIncludesArtifactFilter
*/
public class PatternIncludesArtifactFilter
implements ArtifactFilter, StatisticsReportingArtifactFilter
{
private final List positivePatterns;
private final List negativePatterns;
private final boolean actTransitively;
private Set patternsTriggered = new HashSet();
private List filteredArtifactIds = new ArrayList();
public PatternIncludesArtifactFilter( List patterns )
{
this( patterns, false );
}
public PatternIncludesArtifactFilter( List patterns, boolean actTransitively )
{
this.actTransitively = actTransitively;
List pos = new ArrayList();
List neg = new ArrayList();
if ( ( patterns != null ) && !patterns.isEmpty() )
{
for ( Iterator it = patterns.iterator(); it.hasNext(); )
{
String pattern = (String) it.next();
if ( pattern.startsWith( "!" ) )
{
neg.add( pattern.substring( 1 ) );
}
else
{
pos.add( pattern );
}
}
}
positivePatterns = pos;
negativePatterns = neg;
}
public boolean include( Artifact artifact )
{
boolean shouldInclude = patternMatches( artifact );
if ( !shouldInclude )
{
addFilteredArtifactId( artifact.getId() );
}
return shouldInclude;
}
protected boolean patternMatches( Artifact artifact )
{
return ( positiveMatch( artifact ) == Boolean.TRUE ) || ( negativeMatch( artifact ) == Boolean.FALSE );
}
protected void addFilteredArtifactId( String artifactId )
{
filteredArtifactIds.add( artifactId );
}
private Boolean negativeMatch( Artifact artifact )
{
if ( ( negativePatterns == null ) || negativePatterns.isEmpty() )
{
return null;
}
else
{
return Boolean.valueOf( match( artifact, negativePatterns ) );
}
}
protected Boolean positiveMatch( Artifact artifact )
{
if ( ( positivePatterns == null ) || positivePatterns.isEmpty() )
{
return null;
}
else
{
return Boolean.valueOf( match( artifact, positivePatterns ) );
}
}
private boolean match( Artifact artifact, List patterns )
{
String shortId = ArtifactUtils.versionlessKey( artifact );
String id = artifact.getDependencyConflictId();
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 )
{
List depTrail = artifact.getDependencyTrail();
if ( ( depTrail != null ) && !depTrail.isEmpty() )
{
String trailStr = "," + StringUtils.join( depTrail.iterator(), "," );
return matchAgainst( trailStr, patterns, true );
}
}
return false;
}
private boolean matchAgainst( String value, List patterns, boolean regionMatch )
{
patternLoop:
for ( Iterator i = patterns.iterator(); i.hasNext(); )
{
// TODO: what about wildcards? Just specifying groups? versions?
String pattern = (String) i.next();
// don't allow wildcards in region-matched searches...i.e. in transitive dependencies.
// if ( regionMatch && ( pattern.indexOf( '*' ) > -1 ) )
// {
// continue;
// }
if ( value.equals( pattern ) )
{
patternsTriggered.add( pattern );
return true;
}
else if ( pattern.indexOf( '*' ) > -1 )
{
String[] subPatterns = pattern.split( "\\*" );
int[] idxes = new int[subPatterns.length];
for ( int j = 0; j < subPatterns.length; j++ )
{
String subPattern = subPatterns[j];
if ( subPattern.endsWith( "*" ) )
{
subPattern = subPattern.substring( 0, subPattern.length() - 1 );
}
if ( ( subPattern == null ) || ( subPattern.length() < 1 ) )
{
idxes[j] = j == 0 ? 0 : idxes[j - 1];
continue;
}
int lastIdx = j == 0 ? 0 : idxes[j - 1];
idxes[j] = value.indexOf( subPattern, lastIdx );
if ( idxes[j] < 0 )
{
patternsTriggered.add( pattern );
continue patternLoop;
}
}
return true;
}
else if ( regionMatch && value.indexOf( pattern ) > -1 )
{
patternsTriggered.add( pattern );
return true;
}
}
return false;
}
public void reportMissedCriteria( Logger logger )
{
// if there are no patterns, there is nothing to report.
if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
{
List missed = new ArrayList();
missed.addAll( positivePatterns );
missed.addAll( negativePatterns );
missed.removeAll( patternsTriggered );
if ( !missed.isEmpty() && logger.isWarnEnabled() )
{
StringBuffer buffer = new StringBuffer();
buffer.append( "The following patterns were never triggered in this " );
buffer.append( getFilterDescription() );
buffer.append( ':' );
for ( Iterator it = missed.iterator(); it.hasNext(); )
{
String pattern = (String) it.next();
buffer.append( "\no \'" ).append( pattern ).append( "\'" );
}
buffer.append( "\n" );
logger.warn( buffer.toString() );
}
}
}
public String toString()
{
return "Includes filter:" + getPatternsAsString();
}
protected String getPatternsAsString()
{
StringBuffer buffer = new StringBuffer();
for ( Iterator it = positivePatterns.iterator(); it.hasNext(); )
{
String pattern = (String) it.next();
buffer.append( "\no \'" ).append( pattern ).append( "\'" );
}
return buffer.toString();
}
protected String getFilterDescription()
{
return "artifact inclusion filter";
}
public void reportFilteredArtifacts( Logger logger )
{
if ( !filteredArtifactIds.isEmpty() && logger.isDebugEnabled() )
{
StringBuffer buffer = new StringBuffer( "The following artifacts were removed by this "
+ getFilterDescription() + ": " );
for ( Iterator it = filteredArtifactIds.iterator(); it.hasNext(); )
{
String artifactId = (String) it.next();
buffer.append( '\n' ).append( artifactId );
}
logger.debug( buffer.toString() );
}
}
public boolean hasMissedCriteria()
{
// if there are no patterns, there is nothing to report.
if ( !positivePatterns.isEmpty() || !negativePatterns.isEmpty() )
{
List missed = new ArrayList();
missed.addAll( positivePatterns );
missed.addAll( negativePatterns );
missed.removeAll( patternsTriggered );
return !missed.isEmpty();
}
return false;
}
}