This is an automated email from the ASF dual-hosted git repository. michaelo pushed a commit to branch MRESOLVER-33 in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 57d550092709a8662b88332a3cfbf061321d6297 Author: Christian Schulte <c...@schulte.it> AuthorDate: Sun Oct 22 05:34:58 2017 +0200 [MRESOLVER-33] New class 'DefaultDependencyManager' managing dependencies on all levels supporting transitive dependency management. --- .../collect/DefaultDependencyCollectorTest.java | 30 ++ .../managed/default-management-tree.txt | 6 + .../gid_direct_managed-by-dominant-request.ini | 5 + .../artifact-descriptions/managed/gid_root_ver.ini | 2 +- .../graph/manager/DefaultDependencyManager.java | 320 +++++++++++++++++++++ 5 files changed, 362 insertions(+), 1 deletion(-) 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 232cf9f..88ced9f 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 @@ -65,6 +65,7 @@ import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 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.DefaultDependencyManager; import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; import org.eclipse.aether.util.graph.selector.ScopeDependencySelector; @@ -511,6 +512,35 @@ public class DefaultDependencyCollectorTest assertEqualSubtree( expectedTree, toDependencyResult( result.getRoot(), "compile", null ) ); } + @Test + public void testDependencyManagement_DefaultDependencyManager() + throws DependencyCollectionException, IOException + { + collector.setArtifactDescriptorReader( newReader( "managed/" ) ); + parser = new DependencyGraphParser( "artifact-descriptions/managed/" ); + session.setDependencyManager( new DefaultDependencyManager() ); + final Dependency root = newDep( "gid:root:ext:ver", "compile" ); + CollectRequest request = new CollectRequest( root, Arrays.asList( repository ) ); + request.addManagedDependency( newDep( "gid:root:ext:must-not-manage-root" ) ); + request.addManagedDependency( newDep( "gid:direct:ext:managed-by-dominant-request" ) ); + CollectResult result = collector.collectDependencies( session, request ); + + final DependencyNode expectedTree = parser.parseResource( "default-management-tree.txt" ); + assertEqualSubtree( expectedTree, result.getRoot() ); + + // Same test for root artifact (POM) request. + final CollectRequest rootArtifactRequest = new CollectRequest(); + rootArtifactRequest.setRepositories( Arrays.asList( repository ) ); + rootArtifactRequest.setRootArtifact( new DefaultArtifact( "gid:root:ext:ver" ) ); + rootArtifactRequest.addDependency( newDep( "gid:direct:ext:ver", "compile" ) ); + rootArtifactRequest.addManagedDependency( newDep( "gid:root:ext:must-not-manage-root" ) ); + rootArtifactRequest.addManagedDependency( newDep( "gid:direct:ext:managed-by-dominant-request" ) ); + rootArtifactRequest.addManagedDependency( newDep( "gid:transitive-1:ext:managed-by-root" ) ); + session.setDependencyManager( new DefaultDependencyManager() ); + result = collector.collectDependencies( session, rootArtifactRequest ); + assertEqualSubtree( expectedTree, toDependencyResult( result.getRoot(), "compile", null ) ); + } + private DependencyNode toDependencyResult( final DependencyNode root, final String rootScope, final Boolean optional ) { diff --git a/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/default-management-tree.txt b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/default-management-tree.txt new file mode 100644 index 0000000..d0a1946 --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/default-management-tree.txt @@ -0,0 +1,6 @@ +gid:root:ext:ver compile ++- gid:direct:ext:managed-by-dominant-request 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-impl/src/test/resources/artifact-descriptions/managed/gid_direct_managed-by-dominant-request.ini b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_direct_managed-by-dominant-request.ini new file mode 100644 index 0000000..94ba9fb --- /dev/null +++ b/maven-resolver-impl/src/test/resources/artifact-descriptions/managed/gid_direct_managed-by-dominant-request.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 index 15db99e..5ac544a 100644 --- 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 @@ -1,5 +1,5 @@ [dependencies] gid:direct:ext:ver [manageddependencies] -gid:direct:ext:must-retain-core-management +gid:direct:ext:must-be-ignored-for-maven-2-and-3-compat gid:transitive-1:ext:managed-by-root \ No newline at end of file diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java new file mode 100644 index 0000000..99995fd --- /dev/null +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/manager/DefaultDependencyManager.java @@ -0,0 +1,320 @@ +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 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 dependencies on all levels supporting transitive dependency management. + * <p> + * <b>Note:</b>Unlike the {@code ClassicDependencyManager} and the {@code TransitiveDependencyManager} this + * implementation applies management also on the first level. This is considered the resolver's default behaviour. + * It ignores all management overrides supported by the {@code MavenModelBuilder}. + * </p> + * + * @author Christian Schulte + * @since 1.4.0 + */ +public final class DefaultDependencyManager + 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 int hashCode; + + /** + * Creates a new dependency manager without any management information. + */ + public DefaultDependencyManager() + { + this( Collections.<Object, String>emptyMap(), Collections.<Object, String>emptyMap(), + Collections.<Object, Boolean>emptyMap(), Collections.<Object, String>emptyMap(), + Collections.<Object, Collection<Exclusion>>emptyMap() ); + } + + private DefaultDependencyManager( 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.managedVersions = managedVersions; + this.managedScopes = managedScopes; + this.managedOptionals = managedOptionals; + this.managedLocalPaths = managedLocalPaths; + this.managedExclusions = managedExclusions; + } + + public DependencyManager deriveChildManager( final DependencyCollectionContext context ) + { + Map<Object, String> versions = this.managedVersions; + Map<Object, String> scopes = this.managedScopes; + Map<Object, Boolean> optionals = this.managedOptionals; + Map<Object, String> localPaths = this.managedLocalPaths; + Map<Object, Collection<Exclusion>> exclusions = this.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 == this.managedVersions ) + { + versions = new HashMap<Object, String>( this.managedVersions ); + } + versions.put( key, version ); + } + + String scope = managedDependency.getScope(); + if ( scope.length() > 0 && !scopes.containsKey( key ) ) + { + if ( scopes == this.managedScopes ) + { + scopes = new HashMap<Object, String>( this.managedScopes ); + } + scopes.put( key, scope ); + } + + Boolean optional = managedDependency.getOptional(); + if ( optional != null && !optionals.containsKey( key ) ) + { + if ( optionals == this.managedOptionals ) + { + optionals = new HashMap<Object, Boolean>( this.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<Object, String>( this.managedLocalPaths ); + } + localPaths.put( key, localPath ); + } + + if ( !managedDependency.getExclusions().isEmpty() ) + { + if ( exclusions == this.managedExclusions ) + { + exclusions = new HashMap<Object, Collection<Exclusion>>( this.managedExclusions ); + } + Collection<Exclusion> managed = exclusions.get( key ); + if ( managed == null ) + { + managed = new LinkedHashSet<Exclusion>(); + exclusions.put( key, managed ); + } + managed.addAll( managedDependency.getExclusions() ); + } + } + + return new DefaultDependencyManager( versions, scopes, optionals, localPaths, exclusions ); + } + + public DependencyManagement manageDependency( Dependency dependency ) + { + DependencyManagement management = null; + + Object key = getKey( dependency.getArtifact() ); + + String version = managedVersions.get( key ); + if ( version != null ) + { + if ( management == 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<String, String>( dependency.getArtifact().getProperties() ); + + properties.remove( ArtifactProperties.LOCAL_PATH ); + management.setProperties( properties ); + } + } + + if ( ( scope != null && 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<String, String>( 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<Exclusion>( 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 DefaultDependencyManager; + + if ( equal ) + { + final DefaultDependencyManager that = (DefaultDependencyManager) obj; + equal = this.managedVersions.equals( that.managedVersions ) + && this.managedScopes.equals( that.managedScopes ) + && this.managedOptionals.equals( that.managedOptionals ) + && this.managedExclusions.equals( that.managedExclusions ); + + } + + return equal; + } + + @Override + public int hashCode() + { + if ( this.hashCode == 0 ) + { + int hash = 17; + hash = hash * 31 + this.managedVersions.hashCode(); + hash = hash * 31 + this.managedScopes.hashCode(); + hash = hash * 31 + this.managedOptionals.hashCode(); + hash = hash * 31 + this.managedExclusions.hashCode(); + this.hashCode = hash; + } + return this.hashCode; + } + + static class Key + { + + private final Artifact artifact; + + private final int hashCode; + + public Key( final Artifact artifact ) + { + this.artifact = artifact; + + int hash = 17; + hash = hash * 31 + artifact.getGroupId().hashCode(); + hash = hash * 31 + artifact.getArtifactId().hashCode(); + this.hashCode = hash; + } + + @Override + public boolean equals( final Object obj ) + { + boolean equal = obj instanceof Key; + + if ( equal ) + { + final Key that = (Key) obj; + return this.artifact.getArtifactId().equals( that.artifact.getArtifactId() ) + && this.artifact.getGroupId().equals( that.artifact.getGroupId() ) + && this.artifact.getExtension().equals( that.artifact.getExtension() ) + && this.artifact.getClassifier().equals( that.artifact.getClassifier() ); + + } + + return equal; + } + + @Override + public int hashCode() + { + return this.hashCode; + } + + } + +}