This is an automated email from the ASF dual-hosted git repository. rmannibucau pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven-shade-plugin.git
The following commit(s) were added to refs/heads/master by this push: new 72cf77e [MSHADE-373] allow to configure the manifest per shaded artifact. (#59) 72cf77e is described below commit 72cf77e445b502b606b36724e1c4794a7587c05c Author: Rafael Winterhalter <rafael....@gmail.com> AuthorDate: Sat Jul 4 12:11:44 2020 +0200 [MSHADE-373] allow to configure the manifest per shaded artifact. (#59) * MSHADE-373: allow to specify optional target for resource transformers. * enrich MSHADE-373 it test with multiple artifact deliveries and null/manifest-removal test + handle the case multiple manifest transformers are used for the same build Co-authored-by: Romain Manni-Bucau <rmannibu...@gmail.com> --- README.md | 16 +++ pom.xml | 1 + src/it/projects/MSHADE-183/verify.bsh | 4 +- src/it/projects/MSHADE-373/pom.xml | 117 +++++++++++++++++++++ src/it/projects/MSHADE-373/verify.bsh | 62 +++++++++++ .../apache/maven/plugins/shade/mojo/ShadeMojo.java | 60 +++++++++-- .../resource/ManifestResourceTransformer.java | 31 +++++- .../maven/plugins/shade/mojo/ShadeMojoTest.java | 51 ++++++++- 8 files changed, 328 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6655702..c10dec7 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,22 @@ For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in JIRA. In this case, it is appropriate to start the first line of a commit with '(doc)' instead of a ticket number. +Developer Tips +-------------- + +If you machine is big enough and you want to parallelise the IT execution to validate the build +before a PR you can set the concurrency in MAVEN_OPTS: + +```` +MAVEN_OPTS=-Dinvoker.parallelThreads=2 mvn verify -Prun-its +```` + +You can also run a single IT test using: + +```` +mvn verify -Prun-its -Dinvoker.test=myitproject +```` + Additional Resources -------------------- diff --git a/pom.xml b/pom.xml index 25ec427..b56c028 100644 --- a/pom.xml +++ b/pom.xml @@ -286,6 +286,7 @@ <goals> <goal>package</goal> </goals> + <showErrors>true</showErrors> <projectsDirectory>src/it/projects</projectsDirectory> <settingsFile>src/it/mrm/settings.xml</settingsFile> <extraArtifacts> diff --git a/src/it/projects/MSHADE-183/verify.bsh b/src/it/projects/MSHADE-183/verify.bsh index 8511b12..52e8ab8 100644 --- a/src/it/projects/MSHADE-183/verify.bsh +++ b/src/it/projects/MSHADE-183/verify.bsh @@ -43,7 +43,7 @@ if ( !"org.apache.maven.Shade".equals( mf.getMainAttributes().getValue( "Main-Cl { throw new IllegalStateException( "META-INF/MANIFEST.MF is incomplete" ); } -if ( !"null".equals( mf.getMainAttributes().getValue( "Implementation-Build" ) ) ) +if ( null != mf.getMainAttributes().getValue( "Implementation-Build" ) ) { - throw new IllegalStateException( "META-INF/MANIFEST.MF Implementation-Build content is not null as expected." ); + throw new IllegalStateException( "META-INF/MANIFEST.MF Implementation-Build content is not null as expected. (" + mf.getMainAttributes().entrySet() + ")" ); } diff --git a/src/it/projects/MSHADE-373/pom.xml b/src/it/projects/MSHADE-373/pom.xml new file mode 100644 index 0000000..19a1e17 --- /dev/null +++ b/src/it/projects/MSHADE-373/pom.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +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. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.its.shade.mt</groupId> + <artifactId>test</artifactId> + <version>1.0</version> + <packaging>jar</packaging> + + <name>MSHADE-373</name> + <description> + Test that reproduces the issue described in MSHADE-373. + </description> + + <dependencies> + <dependency> + <!-- dummy dependency to test interaction of multiple manifests --> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>@project.version@</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>2.0.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <version>2.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.2</version> + <configuration> + <archive> + <manifest> + <mainClass>org.apache.maven.Main</mainClass> + </manifest> + <manifestEntries> + <Test-Entry>PASSED</Test-Entry> + <Original-Entry>PASSED</Original-Entry> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>2.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>@project.version@</version> + <executions> + <execution> + <id>attach-shade</id> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <createSourcesJar>true</createSourcesJar> + <shadeTestJar>true</shadeTestJar> + <shadedArtifactAttached>false</shadedArtifactAttached> + <transformers> + <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <manifestEntries> + <Custom-Entry>SET</Custom-Entry> <!-- not using original manifest but using transformer directly --> + </manifestEntries> + </transformer> + <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <forShade>sources-jar</forShade> + <manifestEntries> + <Test-Entry>FAILED</Test-Entry> + <Archiver-Version /> + </manifestEntries> + </transformer> + </transformers> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.3.1</version> + </plugin> + </plugins> + </build> +</project> diff --git a/src/it/projects/MSHADE-373/verify.bsh b/src/it/projects/MSHADE-373/verify.bsh new file mode 100644 index 0000000..cc23df3 --- /dev/null +++ b/src/it/projects/MSHADE-373/verify.bsh @@ -0,0 +1,62 @@ +/* + * 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.*; +import java.util.jar.*; + +// NOTE: We deliberately use JarInputStream and not JarFile here! +Manifest extractManifest(name) { + file = new File( basedir, "target/" + name ); + if ( !file.exists() ) + { + throw new IllegalStateException( "No file '" + file + "'" ); + } + JarInputStream jarStream = new JarInputStream( new FileInputStream( file ) ); + Manifest mf = jarStream.getManifest(); + jarStream.close(); + return mf; +} + +void assertsEntries( name, expectedTestEntry, expectedOriginalEntry, expectedCustomEntry, shouldHaveArchiverVersion ) { + attributes = extractManifest( name ).getMainAttributes(); + + if ( !Objects.equals( expectedTestEntry, attributes.getValue( "Test-Entry" ) ) ) + { + throw new IllegalStateException( "Test-Entry should have been '" + expectedTestEntry + "' in " + name + ": " + attributes.entrySet() ); + } + + if ( !Objects.equals( expectedOriginalEntry, attributes.getValue( "Original-Entry" ) ) ) + { + throw new IllegalStateException( "Original-Entry should have been '" + expectedOriginalEntry + "' in " + name + ": " + attributes.entrySet() ); + } + + if ( !Objects.equals( expectedCustomEntry, attributes.getValue( "Custom-Entry" ) ) ) + { + throw new IllegalStateException( "Custom-Entry should have been '" + expectedCustomEntry + "' in " + name + ": " + attributes.entrySet() ); + } + + if ( shouldHaveArchiverVersion && attributes.getValue( "Archiver-Version" ) == null || + !shouldHaveArchiverVersion && attributes.getValue( "Archiver-Version" ) != null ) + { + throw new IllegalStateException( "META-INF/MANIFEST.mf Archiver-Version entry is invalid in " + name + ": " + attributes.entrySet() ); + } +} + +assertsEntries( "test-1.0.jar", "PASSED", "PASSED", "SET", true ); +assertsEntries( "test-1.0-sources.jar", "FAILED", null, null, false ); // specific config +assertsEntries( "test-1.0-tests.jar", "PASSED", "PASSED", "SET", true ); // inherits from the default transformer 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 cf7cddf..a6e84d9 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,6 +40,7 @@ import org.apache.maven.plugins.shade.filter.SimpleFilter; 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.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; @@ -458,14 +459,16 @@ public class ShadeMojo List<ResourceTransformer> resourceTransformers = getResourceTransformers(); - ShadeRequest shadeRequest = shadeRequest( artifacts, outputJar, filters, relocators, resourceTransformers ); + ShadeRequest shadeRequest = shadeRequest( "jar", artifacts, outputJar, filters, relocators, + resourceTransformers ); shader.shade( shadeRequest ); if ( createSourcesJar ) { ShadeRequest shadeSourcesRequest = - createShadeSourcesRequest( sourceArtifacts, sourcesJar, filters, relocators, resourceTransformers ); + createShadeSourcesRequest( "sources-jar", sourceArtifacts, sourcesJar, filters, relocators, + resourceTransformers ); shader.shade( shadeSourcesRequest ); } @@ -473,7 +476,7 @@ public class ShadeMojo if ( shadeTestJar ) { ShadeRequest shadeTestRequest = - shadeRequest( testArtifacts, testJar, filters, relocators, resourceTransformers ); + shadeRequest( "test-jar", testArtifacts, testJar, filters, relocators, resourceTransformers ); shader.shade( shadeTestRequest ); } @@ -481,8 +484,8 @@ public class ShadeMojo if ( createTestSourcesJar ) { ShadeRequest shadeTestSourcesRequest = - createShadeSourcesRequest( testSourceArtifacts, testSourcesJar, filters, relocators, - resourceTransformers ); + createShadeSourcesRequest( "test-sources-jar", testSourceArtifacts, testSourcesJar, filters, + relocators, resourceTransformers ); shader.shade( shadeTestSourcesRequest ); } @@ -621,7 +624,7 @@ public class ShadeMojo getLog().error( "- You removed the configuration of the maven-jar-plugin that produces the main artifact." ); } - private ShadeRequest shadeRequest( Set<File> artifacts, File outputJar, List<Filter> filters, + private ShadeRequest shadeRequest( String shade, Set<File> artifacts, File outputJar, List<Filter> filters, List<Relocator> relocators, List<ResourceTransformer> resourceTransformers ) { ShadeRequest shadeRequest = new ShadeRequest(); @@ -629,16 +632,16 @@ public class ShadeMojo shadeRequest.setUberJar( outputJar ); shadeRequest.setFilters( filters ); shadeRequest.setRelocators( relocators ); - shadeRequest.setResourceTransformers( resourceTransformers ); + shadeRequest.setResourceTransformers( toResourceTransformers( shade, resourceTransformers ) ); return shadeRequest; } - private ShadeRequest createShadeSourcesRequest( Set<File> testArtifacts, File testJar, List<Filter> filters, - List<Relocator> relocators, + private ShadeRequest createShadeSourcesRequest( String shade, Set<File> testArtifacts, File testJar, + List<Filter> filters, List<Relocator> relocators, List<ResourceTransformer> resourceTransformers ) { ShadeRequest shadeSourcesRequest = - shadeRequest( testArtifacts, testJar, filters, relocators, resourceTransformers ); + shadeRequest( shade, testArtifacts, testJar, filters, relocators, resourceTransformers ); shadeSourcesRequest.setShadeSourcesContent( shadeSourcesContent ); return shadeSourcesRequest; } @@ -1314,4 +1317,41 @@ public class ShadeMojo session.getProjectBuildingRequest().setProject( original ); } } + + private List<ResourceTransformer> toResourceTransformers( + String shade, List<ResourceTransformer> resourceTransformers ) + { + List<ResourceTransformer> forShade = new ArrayList<ResourceTransformer>(); + ManifestResourceTransformer lastMt = null; + for ( ResourceTransformer transformer : resourceTransformers ) + { + if ( !( transformer instanceof ManifestResourceTransformer ) ) + { + forShade.add( transformer ); + } + else if ( ( ( ManifestResourceTransformer ) transformer ) .isForShade( shade ) ) + { + final ManifestResourceTransformer mt = (ManifestResourceTransformer) transformer; + if ( mt.isUsedForDefaultShading() && lastMt != null && !lastMt.isUsedForDefaultShading() ) + { + continue; // skip, we already have a specific transformer + } + if ( !mt.isUsedForDefaultShading() && lastMt != null && lastMt.isUsedForDefaultShading() ) + { + forShade.remove( lastMt ); + } + else if ( !mt.isUsedForDefaultShading() && lastMt != null ) + { + getLog().warn( "Ambiguous manifest transformer definition for '" + shade + "': " + + mt + " / " + lastMt ); + } + if ( lastMt == null || !mt.isUsedForDefaultShading() ) + { + lastMt = mt; + } + forShade.add( transformer ); + } + } + return forShade; + } } diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java index b66c73a..fe38979 100644 --- a/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java +++ b/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java @@ -62,6 +62,8 @@ public class ManifestResourceTransformer private long time = Long.MIN_VALUE; + private String shade; + public void setMainClass( String mainClass ) { this.mainClass = mainClass; @@ -163,7 +165,14 @@ public class ManifestResourceTransformer { for ( Map.Entry<String, Object> entry : manifestEntries.entrySet() ) { - attributes.put( new Attributes.Name( entry.getKey() ), entry.getValue() ); + if ( entry.getValue() == null ) + { + attributes.remove( new Attributes.Name( entry.getKey() ) ); + } + else + { + attributes.put( new Attributes.Name( entry.getKey() ), entry.getValue() ); + } } } @@ -188,4 +197,24 @@ public class ManifestResourceTransformer } return newValue; } + + /** + * The shades to apply this transformer to or no shades if no filter is applied. + * + * @param shade {@code null}, {@code jar}, {@code test-jar}, {@code sources-jar} or {@code test-sources-jar}. + */ + public void setForShade( String shade ) + { + this.shade = shade; + } + + public boolean isForShade( String shade ) + { + return isUsedForDefaultShading() || this.shade.equalsIgnoreCase( shade ); + } + + public boolean isUsedForDefaultShading() + { + return this.shade == null || this.shade.isEmpty(); + } } 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 6458fb0..181287c 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 @@ -19,6 +19,8 @@ package org.apache.maven.plugins.shade.mojo; * under the License. */ +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,12 +46,12 @@ import org.apache.maven.plugins.shade.filter.Filter; 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.project.MavenProject; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate; import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver; -import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException; import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult; import org.codehaus.plexus.PlexusTestCase; @@ -60,6 +62,53 @@ import org.codehaus.plexus.PlexusTestCase; public class ShadeMojoTest extends PlexusTestCase { + public void testManifestTransformerSelection() throws Exception + { + final ShadeMojo mojo = new ShadeMojo(); + final Method m = ShadeMojo.class.getDeclaredMethod("toResourceTransformers", String.class, List.class); + m.setAccessible(true); + + final ManifestResourceTransformer defaultTfr = new ManifestResourceTransformer() + { + @Override + public String toString() // when test fails junit does a toString so easier to read errors this way + { + return "default"; + } + }; + final ManifestResourceTransformer testsTfr1 = new ManifestResourceTransformer() + { + @Override + public String toString() + { + return "t1"; + } + }; + testsTfr1.setForShade("tests"); + final ManifestResourceTransformer testsTfr2 = new ManifestResourceTransformer() + { + @Override + public String toString() + { + return "t2"; + } + }; + testsTfr2.setForShade("tests"); + + assertEquals( + singletonList( defaultTfr ), + m.invoke( mojo, "jar", asList( defaultTfr, testsTfr1, testsTfr2 ) )); + assertEquals( + asList( testsTfr1, testsTfr2 ), + m.invoke( mojo, "tests", asList( defaultTfr, testsTfr1, testsTfr2 ) )); + assertEquals( + asList( testsTfr1, testsTfr2 ), + m.invoke( mojo, "tests", asList( testsTfr1, defaultTfr, testsTfr2 ) )); + assertEquals( + asList( testsTfr1, testsTfr2 ), + m.invoke( mojo, "tests", asList( testsTfr1, testsTfr2, defaultTfr ) )); + } + public void testShaderWithDefaultShadedPattern() throws Exception {