You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sc...@apache.org on 2016/07/02 16:09:53 UTC

[2/2] maven-aether git commit: Feature: Updated class 'JavaDependencyMediator' to become a very simple but complete replacement for the 'ConflictResolver'. In addition to the nearest node wins strategy, this implementation supports scop

Feature: Updated class 'JavaDependencyMediator' to become a very simple but
         complete replacement for the 'ConflictResolver'. In addition to the
         nearest node wins strategy, this implementation supports scope
         priorities. Currently the priorities are hard-coded to (from highest
         to lowest): system, compile, runtime, test, provided. This may be
         changed in the future to allow for different priorities based on the
         target classpath to transform the graph to. So that when transforming
         to a test classpath the test scope gets higher priority than the
         compile scope. See MNG-5988.


Project: http://git-wip-us.apache.org/repos/asf/maven-aether/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-aether/commit/5b69d98e
Tree: http://git-wip-us.apache.org/repos/asf/maven-aether/tree/5b69d98e
Diff: http://git-wip-us.apache.org/repos/asf/maven-aether/diff/5b69d98e

Branch: refs/heads/master
Commit: 5b69d98e7bce7e49e1af031db59990f22d91526b
Parents: 0a82c39
Author: Christian Schulte <sc...@apache.org>
Authored: Sat Jul 2 17:14:33 2016 +0200
Committer: Christian Schulte <sc...@apache.org>
Committed: Sat Jul 2 17:23:50 2016 +0200

----------------------------------------------------------------------
 .../transformer/JavaDependencyMediator.java     | 132 +++++++++++++++++--
 1 file changed, 118 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-aether/blob/5b69d98e/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyMediator.java
----------------------------------------------------------------------
diff --git a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyMediator.java b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyMediator.java
index ae385e6..626fc5d 100644
--- a/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyMediator.java
+++ b/aether-util/src/main/java/org/eclipse/aether/util/graph/transformer/JavaDependencyMediator.java
@@ -19,7 +19,10 @@ package org.eclipse.aether.util.graph.transformer;
  * under the License.
  */
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.eclipse.aether.RepositoryException;
 import org.eclipse.aether.collection.DependencyGraphTransformationContext;
@@ -43,10 +46,14 @@ public final class JavaDependencyMediator
                                           final DependencyGraphTransformationContext context )
         throws RepositoryException
     {
-        return this.recurse( node );
+        DependencyNode result = node;
+        result = this.removeNonTransitiveNodes( result );
+        result = this.updateTransitiveScopes( result );
+        result = this.removeDuplicateNodes( result, new HashMap<ConflictMarker.Key, DependencyNode>( 1024 ) );
+        return result;
     }
 
-    private DependencyNode recurse( final DependencyNode parent )
+    private DependencyNode removeNonTransitiveNodes( final DependencyNode parent )
     {
         final String parentScope = parent.getDependency() != null
                                        ? parent.getDependency().getScope() != null
@@ -58,8 +65,45 @@ public final class JavaDependencyMediator
         for ( final Iterator<DependencyNode> it = parent.getChildren().iterator(); it.hasNext(); )
         {
             final DependencyNode child = it.next();
-            boolean removed = false;
 
+            recurse:
+            {
+                if ( parentScope != null )
+                {
+                    String childScope = child.getDependency().getScope() != null
+                                            && child.getDependency().getScope().length() >= 0
+                                            ? child.getDependency().getScope()
+                                            : JavaScopes.COMPILE;
+
+                    // Provided and test scopes are non-transitive.
+                    // Optional dependencies are non-transitive.
+                    if ( JavaScopes.PROVIDED.equals( childScope )
+                             || JavaScopes.TEST.equals( childScope )
+                             || child.getDependency().isOptional() )
+                    {
+                        it.remove();
+                        break recurse;
+                    }
+                }
+
+                this.removeNonTransitiveNodes( child );
+            }
+        }
+
+        return parent;
+    }
+
+    private DependencyNode updateTransitiveScopes( final DependencyNode parent )
+    {
+        final String parentScope = parent.getDependency() != null
+                                       ? parent.getDependency().getScope() != null
+                                             && parent.getDependency().getScope().length() >= 0
+                                             ? parent.getDependency().getScope()
+                                             : JavaScopes.COMPILE
+                                       : null;
+
+        for ( final DependencyNode child : parent.getChildren() )
+        {
             if ( parentScope != null )
             {
                 String childScope = child.getDependency().getScope() != null
@@ -79,7 +123,7 @@ public final class JavaDependencyMediator
                                  || JavaScopes.RUNTIME.equals( childScope ) )
                         {
                             childScope = JavaScopes.PROVIDED;
-                            child.getDependency().setScope( childScope );
+                            child.setScope( childScope );
                         }
                     }
                     else if ( JavaScopes.RUNTIME.equals( parentScope ) )
@@ -88,7 +132,7 @@ public final class JavaDependencyMediator
                         if ( JavaScopes.COMPILE.equals( childScope ) )
                         {
                             childScope = JavaScopes.RUNTIME;
-                            child.getDependency().setScope( childScope );
+                            child.setScope( childScope );
                         }
                     }
                     else if ( JavaScopes.TEST.equals( parentScope ) )
@@ -98,27 +142,87 @@ public final class JavaDependencyMediator
                                  || JavaScopes.RUNTIME.equals( childScope ) )
                         {
                             childScope = JavaScopes.TEST;
-                            child.getDependency().setScope( childScope );
+                            child.setScope( childScope );
                         }
                     }
                 }
+            }
+
+            this.updateTransitiveScopes( child );
+        }
 
-                // Provided and test scopes are non-transitive.
-                if ( JavaScopes.PROVIDED.equals( childScope )
-                         || JavaScopes.TEST.equals( childScope ) )
+        return parent;
+    }
+
+    private DependencyNode removeDuplicateNodes( final DependencyNode candidate,
+                                                 final Map<ConflictMarker.Key, DependencyNode> nodes )
+    {
+        recurse:
+        {
+            if ( candidate.getDependency() != null )
+            {
+                final ConflictMarker.Key candidateKey = new ConflictMarker.Key( candidate.getArtifact() );
+                final DependencyNode existing = nodes.get( candidateKey );
+
+                if ( existing == null )
                 {
-                    it.remove();
-                    removed = true;
+                    // Candidate is selected.
+                    nodes.put( candidateKey, candidate );
+                }
+                else if ( this.isPreferredNode( existing, candidate ) )
+                {
+                    // Candidate is selected.
+                    nodes.put( candidateKey, candidate );
+                    existing.getParent().getChildren().remove( existing );
+                }
+                else
+                {
+                    // Candidate is not selected.
+                    candidate.getParent().getChildren().remove( candidate );
+                    // No need to inspect children.
+                    break recurse;
                 }
             }
 
-            if ( !removed )
+            for ( final DependencyNode child : new ArrayList<DependencyNode>( candidate.getChildren() ) )
             {
-                this.recurse( child );
+                this.removeDuplicateNodes( child, nodes );
             }
         }
 
-        return parent;
+        return candidate;
+    }
+
+    private boolean isPreferredNode( final DependencyNode existing, final DependencyNode candidate )
+    {
+        boolean preferred = false;
+        final Integer p1 = SCOPE_PRIORITIES.get( existing.getDependency().getScope() );
+        final Integer p2 = SCOPE_PRIORITIES.get( candidate.getDependency().getScope() );
+        final boolean candidateScopePrioritized = p1 != null && p2 != null ? p2 > p1 : false;
+        final boolean equalPriority = existing.getDependency().getScope().
+            equals( candidate.getDependency().getScope() );
+
+        if ( candidate.getDepth() < existing.getDepth() )
+        {
+            preferred = equalPriority || candidateScopePrioritized;
+        }
+        else if ( candidate.getDepth() == existing.getDepth() )
+        {
+            preferred = !equalPriority && candidateScopePrioritized;
+        }
+
+        return preferred;
+    }
+
+    private static final Map<String, Integer> SCOPE_PRIORITIES = new HashMap<String, Integer>();
+
+    static
+    {
+        SCOPE_PRIORITIES.put( JavaScopes.PROVIDED, 0 );
+        SCOPE_PRIORITIES.put( JavaScopes.TEST, 0 );
+        SCOPE_PRIORITIES.put( JavaScopes.RUNTIME, 1 );
+        SCOPE_PRIORITIES.put( JavaScopes.COMPILE, 2 );
+        SCOPE_PRIORITIES.put( JavaScopes.SYSTEM, 3 );
     }
 
 }