Author: brianf Date: Thu Jul 5 19:02:11 2007 New Revision: 553696 URL: http://svn.apache.org/viewvc?view=rev&rev=553696 Log: MENFORCER-8 - new rule for banning certain dependencies
Added: maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/BannedDependencies.java maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/util/ maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/util/EnforcerUtils.java maven/plugins/trunk/maven-enforcer-plugin/src/test/java/org/apache/maven/plugin/enforcer/TestBannedDependencies.java Modified: maven/plugins/trunk/maven-enforcer-plugin/pom.xml Modified: maven/plugins/trunk/maven-enforcer-plugin/pom.xml URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-enforcer-plugin/pom.xml?view=diff&rev=553696&r1=553695&r2=553696 ============================================================================== --- maven/plugins/trunk/maven-enforcer-plugin/pom.xml (original) +++ maven/plugins/trunk/maven-enforcer-plugin/pom.xml Thu Jul 5 19:02:11 2007 @@ -121,5 +121,11 @@ <artifactId>bsh</artifactId> <version>2.0b4</version> </dependency> + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-plugin-testing-harness</artifactId> + <scope>test</scope> + <version>1.1-SNAPSHOT</version> + </dependency> </dependencies> </project> Added: maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/BannedDependencies.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/BannedDependencies.java?view=auto&rev=553696 ============================================================================== --- maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/BannedDependencies.java (added) +++ maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/BannedDependencies.java Thu Jul 5 19:02:11 2007 @@ -0,0 +1,261 @@ +package org.apache.maven.plugin.enforcer; + +/* + * 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.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.plugin.enforcer.util.EnforcerUtils; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.enforcer.rule.api.EnforcerRule; +import org.apache.maven.shared.enforcer.rule.api.EnforcerRuleException; +import org.apache.maven.shared.enforcer.rule.api.EnforcerRuleHelper; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; +import org.codehaus.plexus.util.StringUtils; + +/** + * This rule checks that lists of dependencies are not + * included. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Brian Fox</a> + * @version $Id$ + * + */ +public class BannedDependencies + implements EnforcerRule +{ + + /** + * Specify the banned dependencies. This can be a list + * of artifacts in the format + * groupId[:artifactId][:version] + * Any of the sections can be a wildcard by using '*' (ie group:*:1.0) + * + * @parameter + * @required + */ + public ArrayList excludes = null; + + /** + * Specify if transitive dependencies should be searched + * (default) or only look at direct dependencies + * + * @parameter + */ + public boolean searchTransitive = true; + + /** + * Specify a friendly message if the rule fails. + * + * @parameter + */ + public String message = null; + + /** + * Execute the rule. + */ + public void execute( EnforcerRuleHelper helper ) + throws EnforcerRuleException + { + + // get the project + MavenProject project = null; + try + { + project = (MavenProject) helper.evaluate( "${project}" ); + } + catch ( ExpressionEvaluationException eee ) + { + throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", eee ); + } + + // get the correct list of dependencies + Set dependencies = null; + if ( searchTransitive ) + { + dependencies = project.getArtifacts(); + } + else + { + dependencies = project.getDependencyArtifacts(); + } + + // look for banned dependencies + Set foundExcludes = checkDependencies( dependencies, excludes ); + + // if any are found, fail the check but list all of + // them + if ( !foundExcludes.isEmpty() ) + { + if ( message == null ) + { + StringBuffer buf = new StringBuffer(); + Iterator iter = foundExcludes.iterator(); + while ( iter.hasNext() ) + { + buf.append( "Found Banned Dependency: " + ( (Artifact) iter.next() ).getId() + "\n" ); + } + message = buf.toString(); + } + throw new EnforcerRuleException( message ); + } + + } + + /** + * Checks the set of dependencies against the list of + * excludes + * + * @param dependencies + * @return + * @throws EnforcerRuleException + */ + protected Set checkDependencies( Set dependencies, List theExcludes ) + throws EnforcerRuleException + { + Set foundExcludes = new HashSet(); + + Iterator iter = theExcludes.iterator(); + while ( iter.hasNext() ) + { + String exclude = (String) iter.next(); + + String[] subStrings = exclude.split( ":" ); + subStrings = StringUtils.stripAll(subStrings); + + Iterator DependencyIter = dependencies.iterator(); + while ( DependencyIter.hasNext() ) + { + Artifact artifact = (Artifact) DependencyIter.next(); + + if ( compareDependency( subStrings, artifact ) ) + { + foundExcludes.add( artifact ); + } + } + } + return foundExcludes; + } + + /** + * Compares the parsed array of substrings against the + * artifact + * + * @param exclude + * @param artifact + * @return + * @throws EnforcerRuleException + */ + protected boolean compareDependency( String[] exclude, Artifact artifact ) + throws EnforcerRuleException + { + + boolean result = false; + if ( exclude.length > 0 ) + { + result = exclude[0].equals( "*" ) || artifact.getGroupId().equals( exclude[0] ); + } + + if ( result && exclude.length > 1 ) + { + result = exclude[1].equals( "*" ) || artifact.getArtifactId().equals( exclude[1] ); + } + + if ( result && exclude.length > 2 ) + { + // short circuit if the versions are exactly the + // same + if ( exclude[2].equals( "*" ) || artifact.getVersion().equals( exclude[2] ) ) + { + result = true; + } + else + { + try + { + result = EnforcerUtils.containsVersion( VersionRange.createFromVersionSpec( exclude[2] ), + new DefaultArtifactVersion( artifact.getVersion() ) ); + } + catch ( InvalidVersionSpecificationException e ) + { + throw new EnforcerRuleException( "Invalid Version Range: ", e ); + } + } + } + + return result; + + } + + /** + * @return the excludes + */ + public ArrayList getExcludes() + { + return this.excludes; + } + + /** + * @param theExcludes the excludes to set + */ + public void setExcludes( ArrayList theExcludes ) + { + this.excludes = theExcludes; + } + + /** + * @return the message + */ + public String getMessage() + { + return this.message; + } + + /** + * @param theMessage the message to set + */ + public void setMessage( String theMessage ) + { + this.message = theMessage; + } + + /** + * @return the searchTransitive + */ + public boolean isSearchTransitive() + { + return this.searchTransitive; + } + + /** + * @param theSearchTransitive the searchTransitive to set + */ + public void setSearchTransitive( boolean theSearchTransitive ) + { + this.searchTransitive = theSearchTransitive; + } +} Added: maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/util/EnforcerUtils.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/util/EnforcerUtils.java?view=auto&rev=553696 ============================================================================== --- maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/util/EnforcerUtils.java (added) +++ maven/plugins/trunk/maven-enforcer-plugin/src/main/java/org/apache/maven/plugin/enforcer/util/EnforcerUtils.java Thu Jul 5 19:02:11 2007 @@ -0,0 +1,39 @@ +package org.apache.maven.plugin.enforcer.util; + +import java.util.Iterator; + +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.Restriction; +import org.apache.maven.artifact.versioning.VersionRange; + +/** + * @author <a href="mailto:[EMAIL PROTECTED]">Brian Fox</a> + * + */ +public class EnforcerUtils +{ + public static synchronized boolean containsVersion( VersionRange allowedRange, ArtifactVersion theVersion ) + { + boolean matched = false; + ArtifactVersion recommendedVersion = allowedRange.getRecommendedVersion(); + if ( recommendedVersion == null ) + { + + for ( Iterator i = allowedRange.getRestrictions().iterator(); i.hasNext() && !matched; ) + { + Restriction restriction = (Restriction) i.next(); + if ( restriction.containsVersion( theVersion ) ) + { + matched = true; + } + } + } + else + { + // only singular versions ever have a recommendedVersion + int compareTo = recommendedVersion.compareTo( theVersion ); + matched = ( compareTo <= 0 ); + } + return matched; + } +} Added: maven/plugins/trunk/maven-enforcer-plugin/src/test/java/org/apache/maven/plugin/enforcer/TestBannedDependencies.java URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-enforcer-plugin/src/test/java/org/apache/maven/plugin/enforcer/TestBannedDependencies.java?view=auto&rev=553696 ============================================================================== --- maven/plugins/trunk/maven-enforcer-plugin/src/test/java/org/apache/maven/plugin/enforcer/TestBannedDependencies.java (added) +++ maven/plugins/trunk/maven-enforcer-plugin/src/test/java/org/apache/maven/plugin/enforcer/TestBannedDependencies.java Thu Jul 5 19:02:11 2007 @@ -0,0 +1,155 @@ +package org.apache.maven.plugin.enforcer; + +/* + * 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.io.IOException; +import java.util.ArrayList; + +import junit.framework.TestCase; + +import org.apache.maven.plugin.testing.ArtifactStubFactory; +import org.apache.maven.shared.enforcer.rule.api.EnforcerRule; +import org.apache.maven.shared.enforcer.rule.api.EnforcerRuleException; +import org.apache.maven.shared.enforcer.rule.api.EnforcerRuleHelper; + +/** + * + * @author <a href="mailto:[EMAIL PROTECTED]">Brian Fox</a> + * + */ +public class TestBannedDependencies + extends TestCase +{ + + public void testRule() + throws IOException + { + ArtifactStubFactory factory = new ArtifactStubFactory( null, false ); + MockProject project = new MockProject(); + EnforcerRuleHelper helper = EnforcerTestUtils.getHelper( project ); + project.setArtifacts( factory.getMixedArtifacts() ); + project.setDependencyArtifacts( factory.getScopedArtifacts() ); + BannedDependencies rule = new BannedDependencies(); + + ArrayList excludes = new ArrayList(); + rule.setSearchTransitive( false ); + + // test whole name + excludes.add( "testGroupId:release:1.0" ); + rule.setExcludes( excludes ); + + execute( rule, helper, false ); + + // test group:artifact + excludes.clear(); + excludes.add( "testGroupId:release" ); + execute( rule, helper, false ); + + // test group + excludes.clear(); + excludes.add( "testGroupId" ); + execute( rule, helper, false ); + + // now check one that should be found in direct + // dependencies + excludes.clear(); + excludes.add( "g:compile:1.0" ); + execute( rule, helper, true ); + rule.setSearchTransitive( true ); + + // whole name + excludes.clear(); + excludes.add( "testGroupId:release:1.0" ); + execute( rule, helper, true ); + + // group:artifact + excludes.clear(); + excludes.add( "testGroupId:release" ); + execute( rule, helper, true ); + + // group + excludes.clear(); + excludes.add( "testGroupId" ); + execute( rule, helper, true ); + + // now check wildcards + excludes.clear(); + excludes.add( "*:release" ); + execute( rule, helper, true ); + + // now check wildcards + excludes.clear(); + excludes.add( "*:*:1.0" ); + execute( rule, helper, true ); + + // now check wildcards + excludes.clear(); + excludes.add( "*:release:*" ); + execute( rule, helper, true ); + + // now check wildcards + excludes.clear(); + excludes.add( "*:release:1.2" ); + execute( rule, helper, false ); + + //now check multiple excludes + excludes.add( "*:release:*"); + execute( rule, helper, true ); + + //now check space trimming + excludes.clear(); + excludes.add( " testGroupId : release : 1.0 " ); + execute( rule, helper, true ); + + //now check weirdness + excludes.clear(); + excludes.add( ":::" ); //null entry, won't match anything + execute( rule, helper, false ); + } + + /** + * Simpler wrapper to execute and deal with the expected + * result. + * + * @param rule + * @param helper + * @param shouldFail + */ + private void execute( BannedDependencies rule, EnforcerRuleHelper helper, boolean shouldFail ) + { + try + { + rule.message = null; + rule.execute( helper ); + if ( shouldFail ) + { + fail( "Exception expected." ); + } + } + catch ( EnforcerRuleException e ) + { + if ( !shouldFail ) + { + fail( "No Exception expected:" + e.getLocalizedMessage() ); + } + //helper.getLog().debug(e.getMessage()); + } + } +}