MSHADE-12:  Ability to filter contents of the archives added to the shaded jar


git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/trunk@612350 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java b/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
index 99d1099..bec2b97 100644
--- a/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
+++ b/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
@@ -28,6 +28,7 @@
 import java.util.Iterator;

 import java.util.List;

 import java.util.Set;

+import java.util.ArrayList;

 import java.util.jar.JarEntry;

 import java.util.jar.JarFile;

 import java.util.jar.JarOutputStream;

@@ -35,6 +36,7 @@
 

 import org.apache.maven.plugins.shade.relocation.Relocator;

 import org.apache.maven.plugins.shade.resource.ResourceTransformer;

+import org.apache.maven.plugins.shade.filter.Filter;

 import org.codehaus.plexus.logging.AbstractLogEnabled;

 import org.codehaus.plexus.util.IOUtil;

 import org.objectweb.asm.ClassReader;

@@ -51,8 +53,8 @@
     extends AbstractLogEnabled

     implements Shader

 {

-    public void shade( Set jars, File uberJar, List relocators, List resourceTransformers )

-        throws IOException

+    public void shade( Set jars, File uberJar, List filters, List relocators, List resourceTransformers )

+    throws IOException

     {

         Set resources = new HashSet();

 

@@ -64,6 +66,8 @@
         {

             File jar = (File) i.next();

 

+            List jarFilters = getFilters( jar, filters );

+

             JarFile jarFile = new JarFile( jar );

 

             for ( Enumeration j = jarFile.entries(); j.hasMoreElements(); )

@@ -74,7 +78,7 @@
                 String mappedName = remapper.map( name );

 

                 InputStream is = jarFile.getInputStream( entry );

-                if ( !entry.isDirectory() )

+                if ( !entry.isDirectory() && !isFiltered( jarFilters, name ) )

                 {

                     int idx = mappedName.lastIndexOf('/');

                     if ( idx != -1 )

@@ -125,6 +129,24 @@
         IOUtil.close( jos );

     }

 

+    private List getFilters(File jar, List filters)

+    {

+        List list = new ArrayList();

+

+        for ( int i = 0; i < filters.size(); i++ )

+        {

+            Filter filter = (Filter) filters.get( i );

+

+            if ( filter.canFilter( jar ) )

+            {

+                list.add( filter );

+            }

+

+        }

+

+        return list;

+    }

+

     private void addDirectory( Set resources, JarOutputStream jos, String name )

         throws IOException

     {

@@ -184,6 +206,21 @@
         }

     }

 

+    private boolean isFiltered( List filters, String name )

+    {

+        for ( int i = 0; i < filters.size(); i++ )

+        {

+            Filter filter = (Filter) filters.get( i );

+

+            if ( filter.isFiltered( name ) )

+            {

+                return true;

+            }

+        }

+

+        return false;

+    }

+

     private boolean resourceTransformed( List resourceTransformers, String name, InputStream is )

         throws IOException

     {

diff --git a/src/main/java/org/apache/maven/plugins/shade/Shader.java b/src/main/java/org/apache/maven/plugins/shade/Shader.java
index 3cff990..864d1ac 100644
--- a/src/main/java/org/apache/maven/plugins/shade/Shader.java
+++ b/src/main/java/org/apache/maven/plugins/shade/Shader.java
@@ -29,9 +29,10 @@
 {

     String ROLE = Shader.class.getName();

 

-    public void shade( Set jars,

-                       File uberJar,

-                       List relocators,

-                       List resourceTransformers )

+    public void shade(Set jars,

+                      File uberJar,

+                      List filters,

+                      List relocators,

+                      List resourceTransformers)

         throws IOException;

 }

diff --git a/src/main/java/org/apache/maven/plugins/shade/filter/Filter.java b/src/main/java/org/apache/maven/plugins/shade/filter/Filter.java
new file mode 100644
index 0000000..4a305a4
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/shade/filter/Filter.java
@@ -0,0 +1,29 @@
+/**
+ * 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.plugins.shade.filter;
+
+import java.io.File;
+
+/**
+ * @author David Blevins
+ */
+public interface Filter
+{
+    boolean canFilter( File jar );
+
+    boolean isFiltered( String classFile );
+}
diff --git a/src/main/java/org/apache/maven/plugins/shade/filter/SimpleFilter.java b/src/main/java/org/apache/maven/plugins/shade/filter/SimpleFilter.java
new file mode 100644
index 0000000..e0a5513
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/shade/filter/SimpleFilter.java
@@ -0,0 +1,89 @@
+/**
+ * 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.plugins.shade.filter;
+
+import org.codehaus.plexus.util.SelectorUtils;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author David Blevins
+ */
+public class SimpleFilter
+    implements Filter
+{
+    private File jar;
+
+    private Set includes;
+
+    private Set excludes;
+
+    public SimpleFilter( File jar, Set includes, Set excludes )
+    {
+        this.jar = jar;
+        this.includes = includes;
+        this.excludes = excludes;
+    }
+
+    public boolean canFilter( File jar )
+    {
+        return this.jar.equals( jar );
+    }
+
+    public boolean isFiltered( String classFile )
+    {
+
+        return !( isIncluded( classFile ) && !isExcluded( classFile ) );
+    }
+
+    private boolean isIncluded( String classFile )
+    {
+        if ( includes == null || includes.size() == 0 )
+        {
+            return true;
+        }
+
+        return matchPaths( includes, classFile );
+    }
+
+    private boolean isExcluded( String classFile )
+    {
+        if ( excludes == null || excludes.size() == 0 )
+        {
+            return false;
+        }
+
+        return matchPaths( excludes, classFile );
+    }
+
+    private boolean matchPaths( Set patterns, String classFile )
+    {
+        for ( Iterator iterator = patterns.iterator(); iterator.hasNext(); )
+        {
+            String pattern = (String) iterator.next();
+
+            if ( SelectorUtils.matchPath( pattern, classFile ) )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugins/shade/mojo/ArchiveFilter.java b/src/main/java/org/apache/maven/plugins/shade/mojo/ArchiveFilter.java
new file mode 100644
index 0000000..d95d595
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/shade/mojo/ArchiveFilter.java
@@ -0,0 +1,46 @@
+/**
+ * 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.plugins.shade.mojo;
+
+import java.util.Set;
+
+/**
+ * @author David Blevins
+ */
+public class ArchiveFilter
+{
+    private String artifact;
+
+    private Set includes;
+
+    private Set excludes;
+
+    public String getArtifact()
+    {
+        return artifact;
+    }
+
+    public Set getIncludes()
+    {
+        return includes;
+    }
+
+    public Set getExcludes()
+    {
+        return excludes;
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java b/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
index 3a642cf..fec4cdf 100644
--- a/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
+++ b/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
@@ -32,6 +32,8 @@
 import java.util.LinkedHashSet;

 import java.util.List;

 import java.util.Set;

+import java.util.Map;

+import java.util.HashMap;

 

 import org.apache.maven.artifact.Artifact;

 import org.apache.maven.artifact.factory.ArtifactFactory;

@@ -44,6 +46,7 @@
 import org.apache.maven.plugin.AbstractMojo;

 import org.apache.maven.plugin.MojoExecutionException;

 import org.apache.maven.plugins.shade.Shader;

+import org.apache.maven.plugins.shade.filter.SimpleFilter;

 import org.apache.maven.plugins.shade.pom.PomWriter;

 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;

 import org.apache.maven.plugins.shade.resource.ResourceTransformer;

@@ -56,6 +59,7 @@
  *

  * @author Jason van Zyl

  * @author Mauro Talevi

+ * @author David Blevins

  * @goal shade

  * @phase package

  * @requiresDependencyResolution runtime

@@ -132,6 +136,18 @@
      */

     private ResourceTransformer[] transformers;

 

+    /**

+     * Archive Filters to be used.  Allows you to specify an artifact in the form of

+     * groupId:artifactId and a set of include/exclude file patterns for filtering which

+     * contents of the archive are added to the shaded jar.  From a logical perspective,

+     * includes are processed before excludes, thus it's possible to use an include to

+     * collect a set of files from the archive then use excludes to further reduce the set.

+     * By default, all files are included and no files are excluded.

+     *

+     * @parameter

+     */

+    private ArchiveFilter[] filters;

+

     /** @parameter expression="${project.build.directory}" */

     private File outputDirectory;

 

@@ -259,15 +275,17 @@
         // Now add our extra resources

         try

         {

+            List filters = getFilters();

+

             List relocators = getRelocators();

 

             List resourceTransformers = getResourceTrasformers();

 

-            shader.shade( artifacts, outputJar, relocators, resourceTransformers );

+            shader.shade( artifacts, outputJar, filters, relocators, resourceTransformers );

 

             if (createSourcesJar)

             {

-                shader.shade( sourceArtifacts, sourcesJar, relocators, resourceTransformers );

+                shader.shade( artifacts, outputJar, filters, relocators, resourceTransformers );

             }

 

             if ( shadedArtifactAttached )

@@ -476,6 +494,46 @@
         return Arrays.asList( transformers );

     }

 

+    private List getFilters()

+    {

+        List filters = new ArrayList();

+

+        if ( this.filters == null )

+        {

+            return filters;

+        }

+

+        Map artifacts = new HashMap();

+

+        artifacts.put( getId( project.getArtifact() ), project.getArtifact().getFile() );

+

+        for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )

+        {

+            Artifact artifact = (Artifact) it.next();

+

+            artifacts.put( getId( artifact ), artifact.getFile() );

+        }

+

+        for ( int i = 0; i < this.filters.length; i++ )

+        {

+            ArchiveFilter f = this.filters[i];

+

+            File jar = (File) artifacts.get( f.getArtifact() );

+

+            if ( jar == null )

+            {

+                getLog().info( "No artifact matching filter " + f.getArtifact() );

+

+                continue;

+            }

+

+            filters.add( new SimpleFilter( jar, f.getIncludes(), f.getExcludes() ) );

+

+        }

+

+        return filters;

+    }

+

     private File shadedArtifactFileWithClassifier()

     {

         Artifact artifact = project.getArtifact();

diff --git a/src/site/apt/examples.apt b/src/site/apt/examples.apt
index 314ff5e..d081d5a 100644
--- a/src/site/apt/examples.apt
+++ b/src/site/apt/examples.apt
@@ -203,4 +203,119 @@
   </build>
   ...
 </project>
++-----
+
+ * Shade Plugin with artifact filtering using includes
+
++-----
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+            <filters>
+              <filter>
+                <artifact>junit:junit</artifact>
+                <includes>
+                  <include>junit/framework/**</include>
+                  <include>org/junit/**</include>
+                </includes>
+              </filter>
+            </filters>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+</project>
++-----
+
+ * Shade Plugin with artifact filtering using includes and excludes
+
++-----
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+            <filters>
+              <filter>
+                <artifact>junit:junit</artifact>
+                <includes>
+                  <include>junit/framework/**</include>
+                  <include>org/junit/**</include>
+                </includes>
+                <excludes>
+                  <exclude>org/junit/experimental/**</include>
+                  <exclude>org/junit/runners/**</include>
+                </excludes>
+              </filter>
+            </filters>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+</project>
++-----
+
+ * Shade Plugin with artifact filtering using excludes only
+
++-----
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+            <filters>
+              <filter>
+                <artifact>junit:junit</artifact>
+                <excludes>
+                  <exclude>junit/textui/**</include>
+                  <exclude>junit/runner/**</include>
+                  <exclude>junit/extensions/**</include>
+                  <exclude>org/junit/experimental/**</include>
+                  <exclude>org/junit/runners/**</include>
+                </excludes>
+              </filter>
+            </filters>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+</project>
 +-----
\ No newline at end of file
diff --git a/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java b/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java
index a6d7ebe..535ef79 100644
--- a/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java
@@ -80,7 +80,9 @@
 

         resourceTransformers.add( new ComponentsXmlResourceTransformer() );

 

-        s.shade( set, jar, relocators, resourceTransformers );

+        List filters = new ArrayList();

+

+        s.shade( set, jar, filters, relocators, resourceTransformers );

     }

 

 }

diff --git a/src/test/java/org/apache/maven/plugins/shade/mojo/ShadeMojoTest.java b/src/test/java/org/apache/maven/plugins/shade/mojo/ShadeMojoTest.java
index f973afc..8bf6722 100644
--- a/src/test/java/org/apache/maven/plugins/shade/mojo/ShadeMojoTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/mojo/ShadeMojoTest.java
@@ -71,7 +71,9 @@
 

         resourceTransformers.add( new ComponentsXmlResourceTransformer() );

 

-        s.shade( set, jar, relocators, resourceTransformers );

+        List filters = new ArrayList();

+

+        s.shade( set, jar, filters, relocators, resourceTransformers );

     }

 

 }