You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2019/06/08 11:31:31 UTC
[maven-resolver] 01/01: [MRESOLVER-10] New
'TransitiveDependencyManager' supporting transitive dependency management
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a commit to branch MRESOLVER-10
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit a08cb20e53f206ca720cb850ff392544b73268fb
Author: Christian Schulte <cs...@schulte.it>
AuthorDate: Sat Mar 11 22:38:00 2017 +0100
[MRESOLVER-10] New 'TransitiveDependencyManager' supporting transitive dependency management
This closes #35
---
.../collect/DefaultDependencyCollectorTest.java | 49 ++++
.../managed/gid_direct_ver.ini | 5 +
.../artifact-descriptions/managed/gid_root_ver.ini | 5 +
.../managed/gid_transitive-1_managed-by-root.ini | 5 +
.../managed/gid_transitive-2_managed-by-direct.ini | 5 +
.../gid_transitive-3_managed-by-transitive-1.ini | 4 +
.../gid_transitive-4_managed-by-transitive-2.ini | 1 +
.../managed/management-tree.txt | 6 +
.../graph/manager/TransitiveDependencyManager.java | 307 +++++++++++++++++++++
9 files changed, 387 insertions(+)
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectorTest.java
index 0c10469..232cf9f 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectorTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectorTest.java
@@ -21,6 +21,7 @@ package org.eclipse.aether.internal.impl.collect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -47,6 +48,7 @@ import org.eclipse.aether.collection.DependencyCollectionContext;
import org.eclipse.aether.collection.DependencyCollectionException;
import org.eclipse.aether.collection.DependencyManagement;
import org.eclipse.aether.collection.DependencyManager;
+import org.eclipse.aether.graph.DefaultDependencyNode;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyCycle;
import org.eclipse.aether.graph.DependencyNode;
@@ -64,6 +66,7 @@ import org.eclipse.aether.resolution.ArtifactDescriptorResult;
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
+import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager;
import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
import org.eclipse.aether.util.graph.version.HighestVersionFilter;
import org.junit.Before;
@@ -481,6 +484,52 @@ public class DefaultDependencyCollectorTest
}
@Test
+ public void testDependencyManagement_TransitiveDependencyManager()
+ throws DependencyCollectionException, IOException
+ {
+ collector.setArtifactDescriptorReader( newReader( "managed/" ) );
+ parser = new DependencyGraphParser( "artifact-descriptions/managed/" );
+ session.setDependencyManager( new TransitiveDependencyManager() );
+ final Dependency root = newDep( "gid:root:ext:ver", "compile" );
+ CollectRequest request = new CollectRequest( root, Collections.singletonList( repository ) );
+ request.addManagedDependency( newDep( "gid:root:ext:must-retain-core-management" ) );
+ CollectResult result = collector.collectDependencies( session, request );
+
+ final DependencyNode expectedTree = parser.parseResource( "management-tree.txt" );
+ assertEqualSubtree( expectedTree, result.getRoot() );
+
+ // Same test for root artifact (POM) request.
+ final CollectRequest rootArtifactRequest = new CollectRequest();
+ rootArtifactRequest.setRepositories( Collections.singletonList( repository ) );
+ rootArtifactRequest.setRootArtifact( new DefaultArtifact( "gid:root:ext:ver" ) );
+ rootArtifactRequest.addDependency( newDep( "gid:direct:ext:ver", "compile" ) );
+ rootArtifactRequest.addManagedDependency( newDep( "gid:root:ext:must-retain-core-management" ) );
+ rootArtifactRequest.addManagedDependency( newDep( "gid:direct:ext:must-retain-core-management" ) );
+ rootArtifactRequest.addManagedDependency( newDep( "gid:transitive-1:ext:managed-by-root" ) );
+ session.setDependencyManager( new TransitiveDependencyManager() );
+ result = collector.collectDependencies( session, rootArtifactRequest );
+ assertEqualSubtree( expectedTree, toDependencyResult( result.getRoot(), "compile", null ) );
+ }
+
+ private DependencyNode toDependencyResult( final DependencyNode root, final String rootScope,
+ final Boolean optional )
+ {
+ // Make the root artifact resultion result a dependency resolution result for the subtree check.
+ assertNull( "Expected root artifact resolution result.", root.getDependency() );
+ final DefaultDependencyNode defaultNode =
+ new DefaultDependencyNode( new Dependency( root.getArtifact(), rootScope ) );
+
+ defaultNode.setChildren( root.getChildren() );
+
+ if ( optional != null )
+ {
+ defaultNode.setOptional( optional );
+ }
+
+ return defaultNode;
+ }
+
+ @Test
public void testVersionFilter()
throws Exception
{
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_direct_ver.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_direct_ver.ini
new file mode 100644
index 0000000..94ba9fb
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_direct_ver.ini
@@ -0,0 +1,5 @@
+[dependencies]
+gid:transitive-1:ext:ver
+[manageddependencies]
+gid:transitive-1:ext:must-retain-core-management
+gid:transitive-2:ext:managed-by-direct
\ No newline at end of file
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_root_ver.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_root_ver.ini
new file mode 100644
index 0000000..15db99e
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_root_ver.ini
@@ -0,0 +1,5 @@
+[dependencies]
+gid:direct:ext:ver
+[manageddependencies]
+gid:direct:ext:must-retain-core-management
+gid:transitive-1:ext:managed-by-root
\ No newline at end of file
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-1_managed-by-root.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-1_managed-by-root.ini
new file mode 100644
index 0000000..8fd9f0d
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-1_managed-by-root.ini
@@ -0,0 +1,5 @@
+[dependencies]
+gid:transitive-2:ext:ver
+[manageddependencies]
+gid:transitive-2:ext:must-retain-core-management
+gid:transitive-3:ext:managed-by-transitive-1
\ No newline at end of file
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-2_managed-by-direct.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-2_managed-by-direct.ini
new file mode 100644
index 0000000..96cc8f5
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-2_managed-by-direct.ini
@@ -0,0 +1,5 @@
+[dependencies]
+gid:transitive-3:ext:ver
+[manageddependencies]
+gid:transitive-3:ext:must-retain-core-management
+gid:transitive-4:ext:managed-by-transitive-2
\ No newline at end of file
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-3_managed-by-transitive-1.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-3_managed-by-transitive-1.ini
new file mode 100644
index 0000000..2b8f3cf
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-3_managed-by-transitive-1.ini
@@ -0,0 +1,4 @@
+[dependencies]
+gid:transitive-4:ext:ver
+[manageddependencies]
+gid:transitive-4:ext:must-retain-core-management
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-4_managed-by-transitive-2.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-4_managed-by-transitive-2.ini
new file mode 100644
index 0000000..61a252c
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_transitive-4_managed-by-transitive-2.ini
@@ -0,0 +1 @@
+[dependencies]
diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/management-tree.txt b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/management-tree.txt
new file mode 100644
index 0000000..1371426
--- /dev/null
+++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/management-tree.txt
@@ -0,0 +1,6 @@
+gid:root:ext:ver compile
++- gid:direct:ext:ver compile
+ +- gid:transitive-1:ext:managed-by-root compile
+ +- gid:transitive-2:ext:managed-by-direct compile
+ +- gid:transitive-3:ext:managed-by-transitive-1 compile
+ +- gid:transitive-4:ext:managed-by-transitive-2 compile
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java
new file mode 100644
index 0000000..3536e42
--- /dev/null
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/TransitiveDependencyManager.java
@@ -0,0 +1,307 @@
+package org.eclipse.aether.util.graph.manager;
+
+/*
+ * 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.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Objects;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.collection.DependencyCollectionContext;
+import org.eclipse.aether.collection.DependencyManagement;
+import org.eclipse.aether.collection.DependencyManager;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.Exclusion;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * A dependency manager managing transitive dependencies supporting transitive dependency management.
+ *
+ * @author Christian Schulte
+ * @since 1.4.0
+ */
+public final class TransitiveDependencyManager
+ implements DependencyManager
+{
+
+ private final Map<Object, String> managedVersions;
+
+ private final Map<Object, String> managedScopes;
+
+ private final Map<Object, Boolean> managedOptionals;
+
+ private final Map<Object, String> managedLocalPaths;
+
+ private final Map<Object, Collection<Exclusion>> managedExclusions;
+
+ private final int depth;
+
+ private int hashCode;
+
+ /**
+ * Creates a new dependency manager without any management information.
+ */
+ public TransitiveDependencyManager()
+ {
+ this( 0, Collections.<Object, String>emptyMap(), Collections.<Object, String>emptyMap(),
+ Collections.<Object, Boolean>emptyMap(), Collections.<Object, String>emptyMap(),
+ Collections.<Object, Collection<Exclusion>>emptyMap() );
+ }
+
+ private TransitiveDependencyManager( final int depth,
+ final Map<Object, String> managedVersions,
+ final Map<Object, String> managedScopes,
+ final Map<Object, Boolean> managedOptionals,
+ final Map<Object, String> managedLocalPaths,
+ final Map<Object, Collection<Exclusion>> managedExclusions )
+ {
+ super();
+ this.depth = depth;
+ this.managedVersions = managedVersions;
+ this.managedScopes = managedScopes;
+ this.managedOptionals = managedOptionals;
+ this.managedLocalPaths = managedLocalPaths;
+ this.managedExclusions = managedExclusions;
+ }
+
+ public DependencyManager deriveChildManager( final DependencyCollectionContext context )
+ {
+ Map<Object, String> versions = managedVersions;
+ Map<Object, String> scopes = managedScopes;
+ Map<Object, Boolean> optionals = managedOptionals;
+ Map<Object, String> localPaths = managedLocalPaths;
+ Map<Object, Collection<Exclusion>> exclusions = managedExclusions;
+
+ for ( Dependency managedDependency : context.getManagedDependencies() )
+ {
+ Artifact artifact = managedDependency.getArtifact();
+ Object key = getKey( artifact );
+
+ String version = artifact.getVersion();
+ if ( version.length() > 0 && !versions.containsKey( key ) )
+ {
+ if ( versions == managedVersions )
+ {
+ versions = new HashMap<>( managedVersions );
+ }
+ versions.put( key, version );
+ }
+
+ String scope = managedDependency.getScope();
+ if ( scope.length() > 0 && !scopes.containsKey( key ) )
+ {
+ if ( scopes == this.managedScopes )
+ {
+ scopes = new HashMap<>( this.managedScopes );
+ }
+ scopes.put( key, scope );
+ }
+
+ Boolean optional = managedDependency.getOptional();
+ if ( optional != null && !optionals.containsKey( key ) )
+ {
+ if ( optionals == managedOptionals )
+ {
+ optionals = new HashMap<>( managedOptionals );
+ }
+ optionals.put( key, optional );
+ }
+
+ String localPath = managedDependency.getArtifact().getProperty( ArtifactProperties.LOCAL_PATH, null );
+ if ( localPath != null && !localPaths.containsKey( key ) )
+ {
+ if ( localPaths == this.managedLocalPaths )
+ {
+ localPaths = new HashMap<>( managedLocalPaths );
+ }
+ localPaths.put( key, localPath );
+ }
+
+ if ( !managedDependency.getExclusions().isEmpty() )
+ {
+ if ( exclusions == managedExclusions )
+ {
+ exclusions = new HashMap<>( managedExclusions );
+ }
+ Collection<Exclusion> managed = exclusions.get( key );
+ if ( managed == null )
+ {
+ managed = new LinkedHashSet<>();
+ exclusions.put( key, managed );
+ }
+ managed.addAll( managedDependency.getExclusions() );
+ }
+ }
+
+ return new TransitiveDependencyManager( depth + 1, versions, scopes, optionals, localPaths,
+ exclusions );
+
+ }
+
+ public DependencyManagement manageDependency( Dependency dependency )
+ {
+ DependencyManagement management = null;
+
+ Object key = getKey( dependency.getArtifact() );
+
+ if ( depth >= 2 )
+ {
+ String version = managedVersions.get( key );
+ if ( version != null )
+ {
+ management = new DependencyManagement();
+ management.setVersion( version );
+ }
+
+ String scope = managedScopes.get( key );
+ if ( scope != null )
+ {
+ if ( management == null )
+ {
+ management = new DependencyManagement();
+ }
+ management.setScope( scope );
+
+ if ( !JavaScopes.SYSTEM.equals( scope ) && dependency.getArtifact().getProperty(
+ ArtifactProperties.LOCAL_PATH, null ) != null )
+ {
+ Map<String, String> properties = new HashMap<>( dependency.getArtifact().getProperties() );
+ properties.remove( ArtifactProperties.LOCAL_PATH );
+ management.setProperties( properties );
+ }
+ }
+
+ if ( ( JavaScopes.SYSTEM.equals( scope ) )
+ || ( scope == null && JavaScopes.SYSTEM.equals( dependency.getScope() ) ) )
+ {
+ String localPath = managedLocalPaths.get( key );
+ if ( localPath != null )
+ {
+ if ( management == null )
+ {
+ management = new DependencyManagement();
+ }
+ Map<String, String> properties = new HashMap<>( dependency.getArtifact().getProperties() );
+ properties.put( ArtifactProperties.LOCAL_PATH, localPath );
+ management.setProperties( properties );
+ }
+ }
+
+ Boolean optional = managedOptionals.get( key );
+ if ( optional != null )
+ {
+ if ( management == null )
+ {
+ management = new DependencyManagement();
+ }
+ management.setOptional( optional );
+ }
+ }
+
+ Collection<Exclusion> exclusions = managedExclusions.get( key );
+ if ( exclusions != null )
+ {
+ if ( management == null )
+ {
+ management = new DependencyManagement();
+ }
+ Collection<Exclusion> result = new LinkedHashSet<>( dependency.getExclusions() );
+ result.addAll( exclusions );
+ management.setExclusions( result );
+ }
+
+ return management;
+ }
+
+ private Object getKey( Artifact a )
+ {
+ return new Key( a );
+ }
+
+ @Override
+ public boolean equals( final Object obj )
+ {
+ boolean equal = obj instanceof TransitiveDependencyManager;
+
+ if ( equal )
+ {
+ final TransitiveDependencyManager that = (TransitiveDependencyManager) obj;
+ return depth == that.depth
+ && Objects.equals( managedVersions, that.managedVersions )
+ && Objects.equals( managedScopes, that.managedScopes )
+ && Objects.equals( managedOptionals, that.managedOptionals )
+ && Objects.equals( managedExclusions, that.managedExclusions );
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ if ( hashCode == 0 )
+ {
+ hashCode = Objects.hash( depth, managedVersions, managedScopes, managedOptionals, managedExclusions );
+ }
+ return hashCode;
+ }
+
+ static class Key
+ {
+ private final Artifact artifact;
+
+ private final int hashCode;
+
+ Key( final Artifact artifact )
+ {
+ this.artifact = artifact;
+ this.hashCode = Objects.hash( artifact.getGroupId(), artifact.getArtifactId() );
+ }
+
+ @Override
+ public boolean equals( final Object obj )
+ {
+ boolean equal = obj instanceof Key;
+
+ if ( equal )
+ {
+ final Key that = (Key) obj;
+ return Objects.equals( artifact.getArtifactId(), that.artifact.getArtifactId() )
+ && Objects.equals( artifact.getGroupId(), that.artifact.getGroupId() )
+ && Objects.equals( artifact.getExtension(), that.artifact.getExtension() )
+ && Objects.equals( artifact.getClassifier(), that.artifact.getClassifier() );
+ }
+
+ return equal;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return this.hashCode;
+ }
+
+ }
+
+}