diff --git a/src/it/projects/MSHADE-413-parallel/invoker.properties b/src/it/projects/MSHADE-413-parallel/invoker.properties
new file mode 100644
index 00000000..7eb2f06c
--- /dev/null
+++ b/src/it/projects/MSHADE-413-parallel/invoker.properties
@@ -0,0 +1,19 @@
+# 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.
+
+invoker.timeoutInSeconds=60
+invoker.goals = clean install -T2 -pl p1/ -pl p2/
diff --git a/src/it/projects/MSHADE-413-parallel/p1/pom.xml b/src/it/projects/MSHADE-413-parallel/p1/pom.xml
new file mode 100644
index 00000000..cab97d13
--- /dev/null
+++ b/src/it/projects/MSHADE-413-parallel/p1/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.apache.maven.its.shade.parallel
+ mshade413-parent
+ 1.0
+
+
+ mshade413-p1
+ 1.0
+
+ MSHADE-413-p1
+
+
+
+ org.projectnessie
+ nessie-spark-extensions-base
+ 0.22.0
+
+
+ org.projectnessie
+ nessie-spark-extensions-base
+ 0.22.0
+ tests
+ test
+
+
+ org.apache.iceberg
+ iceberg-spark3-runtime
+ 0.13.1
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.8.2
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ @project.version@
+
+
+
+ org.projectnessie
+
+
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
diff --git a/src/it/projects/MSHADE-413-parallel/p2/pom.xml b/src/it/projects/MSHADE-413-parallel/p2/pom.xml
new file mode 100644
index 00000000..f598df6b
--- /dev/null
+++ b/src/it/projects/MSHADE-413-parallel/p2/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.apache.maven.its.shade.parallel
+ mshade413-parent
+ 1.0
+
+
+ mshade413-p2
+ 1.0
+
+ MSHADE-413-p2
+
+
+
+ org.projectnessie
+ nessie-spark-extensions-base
+ 0.22.0
+
+
+ org.projectnessie
+ nessie-spark-extensions-base
+ 0.22.0
+ tests
+ test
+
+
+ org.apache.iceberg
+ iceberg-spark3-runtime
+ 0.13.1
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.8.2
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ @project.version@
+
+
+
+ org.projectnessie
+
+
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
diff --git a/src/it/projects/MSHADE-413-parallel/pom.xml b/src/it/projects/MSHADE-413-parallel/pom.xml
new file mode 100644
index 00000000..7089c0a9
--- /dev/null
+++ b/src/it/projects/MSHADE-413-parallel/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.shade.parallel
+ mshade413-parent
+ 1.0
+ pom
+
+ MSHADE-413
+
+ Test that shade works in two parallel project builds.
+
+
+
+ p1
+ p2
+
+
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 d717253f..10b1be24 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
@@ -1061,10 +1061,6 @@ private File shadedTestArtifactFile()
private void createDependencyReducedPom( Set artifactsToRemove )
throws IOException, DependencyGraphBuilderException, ProjectBuildingException
{
- List dependencies = new ArrayList<>();
-
- boolean modified = false;
-
List transitiveDeps = new ArrayList<>();
// NOTE: By using the getArtifacts() we get the completely evaluated artifacts
@@ -1083,39 +1079,48 @@ private void createDependencyReducedPom( Set artifactsToRemove )
// we'll figure out the exclusions in a bit.
transitiveDeps.add( dep );
}
- List origDeps = project.getDependencies();
- if ( promoteTransitiveDependencies )
+ Model model = project.getOriginalModel();
+
+ // MSHADE-413: Must not use objects (for example `Model` or `Dependency`) that are "owned
+ // by Maven" and being used by other projects/plugins. Modifying those will break the
+ // correctness of the build - or cause an endless loop.
+ List origDeps = new ArrayList<>();
+ List source = promoteTransitiveDependencies ? transitiveDeps : project.getDependencies();
+ for ( Dependency d : source )
{
- origDeps = transitiveDeps;
+ origDeps.add( d.clone() );
}
+ model = model.clone();
- Model model = project.getOriginalModel();
// MSHADE-185: We will remove all system scoped dependencies which usually
// have some kind of property usage. At this time the properties within
// such things are already evaluated.
List originalDependencies = model.getDependencies();
removeSystemScopedDependencies( artifactsToRemove, originalDependencies );
+ List dependencies = new ArrayList<>();
+ boolean modified = false;
for ( Dependency d : origDeps )
{
- dependencies.add( d );
-
- String id = getId( d );
-
- if ( artifactsToRemove.contains( id ) )
+ if ( artifactsToRemove.contains( getId( d ) ) )
{
- modified = true;
-
if ( keepDependenciesWithProvidedScope )
{
- d.setScope( "provided" );
+ if ( !"provided".equals( d.getScope() ) )
+ {
+ modified = true;
+ d.setScope( "provided" );
+ }
}
else
{
- dependencies.remove( d );
+ modified = true;
+ continue;
}
}
+
+ dependencies.add( d );
}
// MSHADE-155
@@ -1299,8 +1304,13 @@ public boolean updateExcludesInDeps( MavenProject project, List depe
boolean modified = false;
for ( DependencyNode n2 : node.getChildren() )
{
+ String artifactId2 = getId( n2.getArtifact() );
+
for ( DependencyNode n3 : n2.getChildren() )
{
+ Artifact artifact3 = n3.getArtifact();
+ String artifactId3 = getId( artifact3 );
+
// check if it really isn't in the list of original dependencies. Maven
// prior to 2.0.8 may grab versions from transients instead of
// from the direct deps in which case they would be marked included
@@ -1310,7 +1320,7 @@ public boolean updateExcludesInDeps( MavenProject project, List depe
boolean found = false;
for ( Dependency dep : transitiveDeps )
{
- if ( getId( dep ).equals( getId( n3.getArtifact() ) ) )
+ if ( getId( dep ).equals( artifactId3 ) )
{
found = true;
break;
@@ -1321,18 +1331,31 @@ public boolean updateExcludesInDeps( MavenProject project, List depe
// note: MSHADE-31 introduced the exclusion logic for promoteTransitiveDependencies=true,
// but as of 3.2.1 promoteTransitiveDependencies has no effect for provided deps,
// which makes this fix even possible (see also MSHADE-181)
- if ( !found && !"provided".equals( n3.getArtifact().getScope() ) )
+ if ( !found && !"provided".equals( artifact3.getScope() ) )
{
+ getLog().debug( String.format( "dependency %s (scope %s) not found in transitive dependencies",
+ artifactId3, artifact3.getScope() ) );
for ( Dependency dep : dependencies )
{
- if ( getId( dep ).equals( getId( n2.getArtifact() ) ) )
+ if ( getId( dep ).equals( artifactId2 ) )
{
- Exclusion exclusion = new Exclusion();
- exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
- exclusion.setGroupId( n3.getArtifact().getGroupId() );
- dep.addExclusion( exclusion );
- modified = true;
- break;
+ // MSHADE-413: First check whether the exclusion has already been added,
+ // because it's meaningless to add it more than once. Certain cases
+ // can end up adding the exclusion "forever" and cause an endless loop
+ // rewriting the whole dependency-reduced-pom.xml file.
+ if ( !dependencyHasExclusion( dep, artifact3 ) )
+ {
+ getLog().debug( String.format( "Adding exclusion for dependency %s (scope %s) "
+ + "to %s (scope %s)",
+ artifactId3, artifact3.getScope(),
+ getId( dep ), dep.getScope() ) );
+ Exclusion exclusion = new Exclusion();
+ exclusion.setArtifactId( artifact3.getArtifactId() );
+ exclusion.setGroupId( artifact3.getGroupId() );
+ dep.addExclusion( exclusion );
+ modified = true;
+ break;
+ }
}
}
}
@@ -1347,6 +1370,21 @@ public boolean updateExcludesInDeps( MavenProject project, List depe
}
}
+ private boolean dependencyHasExclusion( Dependency dep, Artifact exclusionToCheck )
+ {
+ boolean containsExclusion = false;
+ for ( Exclusion existingExclusion : dep.getExclusions() )
+ {
+ if ( existingExclusion.getGroupId().equals( exclusionToCheck.getGroupId() )
+ && existingExclusion.getArtifactId().equals( exclusionToCheck.getArtifactId() ) )
+ {
+ containsExclusion = true;
+ break;
+ }
+ }
+ return containsExclusion;
+ }
+
private List toResourceTransformers(
String shade, List resourceTransformers )
{