From 6300425532d0a4b0cb0dd2bc8aa652e2c01784d2 Mon Sep 17 00:00:00 2001 From: Romain Manni-Bucau Date: Sat, 15 Dec 2018 21:38:44 +0100 Subject: [PATCH] [MSHADE-307] - adding useDefaultConfiguration flag in ShadeMojo --- .../plugins/shade/mojo/ArchiveFilter.java | 11 ++ .../maven/plugins/shade/mojo/ShadeMojo.java | 149 ++++++++++++++++-- .../plugins/shade/mojo/ShadeMojoTest.java | 111 +++++++++---- 3 files changed, 229 insertions(+), 42 deletions(-) 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 index 8c8b5d1e..99783c96 100644 --- a/src/main/java/org/apache/maven/plugins/shade/mojo/ArchiveFilter.java +++ b/src/main/java/org/apache/maven/plugins/shade/mojo/ArchiveFilter.java @@ -34,6 +34,17 @@ public class ArchiveFilter private boolean excludeDefaults = true; + public ArchiveFilter() + { + // no-op + } + + public ArchiveFilter( Set includes, Set excludes ) + { + this.includes = includes; + this.excludes = excludes; + } + public String getArtifact() { return artifact; 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 30d1b6ea..08037d9d 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 @@ -40,7 +40,9 @@ import org.apache.maven.plugins.shade.pom.PomWriter; import org.apache.maven.plugins.shade.relocation.Relocator; import org.apache.maven.plugins.shade.relocation.SimpleRelocator; +import org.apache.maven.plugins.shade.resource.ManifestResourceTransformer; import org.apache.maven.plugins.shade.resource.ResourceTransformer; +import org.apache.maven.plugins.shade.resource.ServicesResourceTransformer; import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectHelper; @@ -76,8 +78,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.ServiceLoader; import java.util.Set; /** @@ -490,7 +494,7 @@ public void execute() replaceFile( finalFile, testJar ); testJar = finalFile; } - + renamed = true; } @@ -752,30 +756,66 @@ private List getRelocators() private List getResourceTransformers() { + final List resourceTransformers = new LinkedList<>( getDefaultResourceTransformers() ); if ( transformers == null ) { - return Collections.emptyList(); + return resourceTransformers; } + resourceTransformers.addAll( Arrays.asList( transformers ) ); + return resourceTransformers; + } - return Arrays.asList( transformers ); + private List getDefaultResourceTransformers() + { + final List transformers = new LinkedList<>(); + if ( missTransformer( ServicesResourceTransformer.class ) ) + { + getLog().debug( "Adding ServicesResourceTransformer transformer" ); + transformers.add( new ServicesResourceTransformer() ); + } + if ( missTransformer( ManifestResourceTransformer.class ) ) + { + getLog().debug( "Adding ManifestResourceTransformer transformer" ); + transformers.add( new ManifestResourceTransformer() ); + } + for ( final ResourceTransformer transformer : ServiceLoader.load( ResourceTransformer.class ) ) + { + if ( !missTransformer( transformer.getClass() ) ) + { + continue; + } + getLog().debug( "Adding " + transformer.getClass().getName() + " transformer" ); + transformers.add( transformer ); + } + return transformers; + } + + private boolean missTransformer( final Class type ) + { + if ( transformers == null ) + { + return true; + } + for ( final ResourceTransformer transformer : transformers ) + { + if ( type.isInstance( transformer ) ) + { + return false; + } + } + return true; } private List getFilters() throws MojoExecutionException { - List filters = new ArrayList<>(); - List simpleFilters = new ArrayList<>(); + List filters = new LinkedList<>(); + List simpleFilters = new LinkedList<>(); + Map artifacts = null; if ( this.filters != null && this.filters.length > 0 ) { - Map artifacts = new HashMap<>(); - - artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) ); - - for ( Artifact artifact : project.getArtifacts() ) - { - artifacts.put( artifact, new ArtifactId( artifact ) ); - } + artifacts = getArtifactIds(); for ( ArchiveFilter filter : this.filters ) { @@ -813,6 +853,51 @@ private List getFilters() } } + // first check for backward compatibility this is not already configured explicitly + boolean addExclusion = true; + if ( this.filters != null ) + { + for ( final ArchiveFilter filter : this.filters ) + { + if ( filter.getExcludes() != null + && filter.getExcludes().contains( "META-INF/*.SF" ) + && filter.getExcludes().contains( "META-INF/*.DSA" ) + && filter.getExcludes().contains( "META-INF/*.RSA" ) + && "*:*".equals( filter.getArtifact() ) ) + { + addExclusion = false; + break; + } + } + } + if ( addExclusion ) + { + getLog().debug( "Adding META-INF/*.SF, META-INF/*.DSA and META-INF/*.RSA exclusion" ); + + if ( artifacts == null ) + { + artifacts = getArtifactIds(); + } + simpleFilters.add( new SimpleFilter( + getMatchingJars( artifacts , new ArtifactId( "*:*" ) ), + new ArchiveFilter( + Collections.emptySet(), + new HashSet<>( Arrays.asList( "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA" ) ) ) ) ); + } + + for ( final Filter filter : ServiceLoader.load( Filter.class ) ) + { + getLog().debug( "Adding " + filter.getClass().getName() + " filter" ); + if ( SimpleFilter.class.isInstance( filter ) ) + { + simpleFilters.add( SimpleFilter.class.cast( filter ) ); + } + else + { + filters.add( filter ); + } + } + filters.addAll( simpleFilters ); if ( minimizeJar ) @@ -832,6 +917,44 @@ private List getFilters() return filters; } + private Set getMatchingJars( final Map artifacts, final ArtifactId pattern ) + { + final Set jars = new HashSet(); + + for ( final Map.Entry entry : artifacts.entrySet() ) + { + if ( entry.getValue().matches( pattern ) ) + { + final Artifact artifact = entry.getKey(); + + jars.add( artifact.getFile() ); + + if ( createSourcesJar ) + { + final File file = resolveArtifactSources( artifact ); + if ( file != null ) + { + jars.add( file ); + } + } + } + } + return jars; + } + + private Map getArtifactIds() + { + final Map artifacts = new HashMap(); + + artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) ); + + for ( final Artifact artifact : project.getArtifacts() ) + { + artifacts.put( artifact, new ArtifactId( artifact ) ); + } + return artifacts; + } + private File shadedArtifactFileWithClassifier() { Artifact artifact = project.getArtifact(); 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 208bac5f..57082671 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 @@ -29,6 +29,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -41,10 +42,13 @@ import org.apache.maven.plugins.shade.ShadeRequest; import org.apache.maven.plugins.shade.Shader; import org.apache.maven.plugins.shade.filter.Filter; +import org.apache.maven.plugins.shade.filter.SimpleFilter; import org.apache.maven.plugins.shade.relocation.Relocator; import org.apache.maven.plugins.shade.relocation.SimpleRelocator; import org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer; +import org.apache.maven.plugins.shade.resource.ManifestResourceTransformer; import org.apache.maven.plugins.shade.resource.ResourceTransformer; +import org.apache.maven.plugins.shade.resource.ServicesResourceTransformer; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate; @@ -60,6 +64,49 @@ public class ShadeMojoTest extends PlexusTestCase { + + public void testDefaultConfiguration() throws Exception + { + final ShadeMojo shadeMojo = new ShadeMojo(); + setProject(shadeMojo); + + // default transformers are present + final Method getResourceTransformers = ShadeMojo.class.getDeclaredMethod("getResourceTransformers"); + getResourceTransformers.setAccessible(true); + final List transformers = + List.class.cast(getResourceTransformers.invoke(shadeMojo)); + assertEquals(2, transformers.size()); + assertTrue(ServicesResourceTransformer.class.isInstance(transformers.get(0))); + assertTrue(ManifestResourceTransformer.class.isInstance(transformers.get(1))); + + // default exclusion is present + final Method getFilters = ShadeMojo.class.getDeclaredMethod("getFilters"); + getFilters.setAccessible(true); + final List filters = + List.class.cast(getFilters.invoke(shadeMojo)); + assertEquals(1, filters.size()); + + final Filter filter = filters.iterator().next(); + assertTrue(SimpleFilter.class.isInstance(filter)); + + final Field jars = filter.getClass().getDeclaredField("jars"); + jars.setAccessible(true); + assertEquals(1, Collection.class.cast(jars.get(filter)).size()); + + final Field excludes = filter.getClass().getDeclaredField("excludes"); + excludes.setAccessible(true); + final Collection excludesValues = Collection.class.cast(excludes.get(filter)); + assertEquals(3, excludesValues.size()); + for ( final String exclude : Arrays.asList( "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA" ) ) + { + assertTrue(exclude, excludesValues.contains(exclude) ); + } + + final Field includes = filter.getClass().getDeclaredField("includes"); + includes.setAccessible(true); + assertTrue(Collection.class.cast(includes.get(filter)).isEmpty()); + } + public void testShaderWithDefaultShadedPattern() throws Exception { @@ -124,11 +171,45 @@ public void testShadeWithFilter() createSourcesJar.setAccessible( true ); createSourcesJar.set( mojo, Boolean.TRUE ); + // setup a project + setProject(mojo); + + // create and configure the ArchiveFilter + ArchiveFilter archiveFilter = new ArchiveFilter(); + Field archiveFilterArtifact = ArchiveFilter.class.getDeclaredField( "artifact" ); + archiveFilterArtifact.setAccessible( true ); + archiveFilterArtifact.set( archiveFilter, "org.apache.myfaces.core:myfaces-impl" ); + + // add ArchiveFilter to mojo + Field filtersField = ShadeMojo.class.getDeclaredField( "filters" ); + filtersField.setAccessible( true ); + filtersField.set( mojo, new ArchiveFilter[]{ archiveFilter } ); + + Field sessionField = ShadeMojo.class.getDeclaredField( "session" ); + sessionField.setAccessible( true ); + sessionField.set( mojo, mock( MavenSession.class ) ); + + // invoke getFilters() + Method getFilters = ShadeMojo.class.getDeclaredMethod( "getFilters", new Class[0] ); + getFilters.setAccessible( true ); + List filters = (List) getFilters.invoke( mojo); + + // assertions - there must be one filter + assertEquals( 2, filters.size() ); + + // the filter must be able to filter the binary and the sources jar + Filter filter = filters.get( 1 ); // 0 is the built-in META-INF/* + assertTrue( filter.canFilter( new File( "myfaces-impl-2.0.1-SNAPSHOT.jar" ) ) ); // binary jar + assertTrue( filter.canFilter( new File( "myfaces-impl-2.0.1-SNAPSHOT-sources.jar" ) ) ); // sources jar + } + + private void setProject(final ShadeMojo mojo) throws Exception + { // configure artifactResolver (mocked) for mojo ArtifactResolver mockArtifactResolver = new ArtifactResolver() { @Override - public ArtifactResult resolveArtifact( ProjectBuildingRequest req, final Artifact art ) + public ArtifactResult resolveArtifact(ProjectBuildingRequest req, final Artifact art ) throws ArtifactResolverException { return new ArtifactResult() @@ -185,34 +266,6 @@ public Artifact getArtifact() Field projectField = ShadeMojo.class.getDeclaredField( "project" ); projectField.setAccessible( true ); projectField.set( mojo, project ); - - // create and configure the ArchiveFilter - ArchiveFilter archiveFilter = new ArchiveFilter(); - Field archiveFilterArtifact = ArchiveFilter.class.getDeclaredField( "artifact" ); - archiveFilterArtifact.setAccessible( true ); - archiveFilterArtifact.set( archiveFilter, "org.apache.myfaces.core:myfaces-impl" ); - - // add ArchiveFilter to mojo - Field filtersField = ShadeMojo.class.getDeclaredField( "filters" ); - filtersField.setAccessible( true ); - filtersField.set( mojo, new ArchiveFilter[]{ archiveFilter } ); - - Field sessionField = ShadeMojo.class.getDeclaredField( "session" ); - sessionField.setAccessible( true ); - sessionField.set( mojo, mock( MavenSession.class ) ); - - // invoke getFilters() - Method getFilters = ShadeMojo.class.getDeclaredMethod( "getFilters" ); - getFilters.setAccessible( true ); - List filters = (List) getFilters.invoke( mojo); - - // assertions - there must be one filter - assertEquals( 1, filters.size() ); - - // the filter must be able to filter the binary and the sources jar - Filter filter = filters.get( 0 ); - assertTrue( filter.canFilter( new File( "myfaces-impl-2.0.1-SNAPSHOT.jar" ) ) ); // binary jar - assertTrue( filter.canFilter( new File( "myfaces-impl-2.0.1-SNAPSHOT-sources.jar" ) ) ); // sources jar } public void shaderWithPattern( String shadedPattern, File jar )