diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java index b250937e8c..2bee63ba1c 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java @@ -150,4 +150,6 @@ public interface Artifact List getAvailableVersions(); void setAvailableVersions( List versions ); + + boolean isOptional(); } \ No newline at end of file diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java index 4bee7a332f..176ee07a89 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java @@ -80,8 +80,16 @@ public class DefaultArtifact private Map metadataMap; + private boolean optional; + public DefaultArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, String type, String classifier, ArtifactHandler artifactHandler ) + { + this( groupId, artifactId, versionRange, scope, type, classifier, artifactHandler, false ); + } + + public DefaultArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, String type, + String classifier, ArtifactHandler artifactHandler, boolean optional ) { this.groupId = groupId; @@ -102,6 +110,8 @@ public class DefaultArtifact this.classifier = classifier; + this.optional = optional; + validateIdentity(); } @@ -504,4 +514,9 @@ public class DefaultArtifact { this.availableVersions = availableVersions; } + + public boolean isOptional() + { + return optional; + } } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java b/maven-artifact/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java index d0ac270135..136549847b 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java @@ -47,6 +47,9 @@ public interface ArtifactFactory Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type, String classifier, String scope, String inheritedScope ); + Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type, + String classifier, String scope, String inheritedScope, boolean optional ); + Artifact createBuildArtifact( String groupId, String artifactId, String version, String packaging ); Artifact createProjectArtifact( String groupId, String artifactId, String version ); diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java b/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java index f62f88d65a..403b8ccdb3 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java @@ -52,13 +52,19 @@ public class DefaultArtifactFactory public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type, String classifier, String scope ) { - return createArtifact( groupId, artifactId, versionRange, null, type, classifier, null ); + return createArtifact( groupId, artifactId, versionRange, type, classifier, null, null ); } public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type, String classifier, String scope, String inheritedScope ) { - return createArtifact( groupId, artifactId, versionRange, scope, type, classifier, inheritedScope ); + return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope ); + } + + public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type, + String classifier, String scope, String inheritedScope, boolean optional ) + { + return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, optional ); } public Artifact createBuildArtifact( String groupId, String artifactId, String version, String packaging ) @@ -78,7 +84,7 @@ public class DefaultArtifactFactory public Artifact createPluginArtifact( String groupId, String artifactId, VersionRange versionRange ) { - return createArtifact( groupId, artifactId, versionRange, Artifact.SCOPE_RUNTIME, "maven-plugin", null, null ); + return createArtifact( groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null ); } public Artifact createProjectArtifact( String groupId, String artifactId, String version, String scope ) @@ -88,7 +94,7 @@ public class DefaultArtifactFactory public Artifact createExtensionArtifact( String groupId, String artifactId, VersionRange versionRange ) { - return createArtifact( groupId, artifactId, versionRange, Artifact.SCOPE_RUNTIME, "jar", null, null ); + return createArtifact( groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null ); } public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type, @@ -105,11 +111,17 @@ public class DefaultArtifactFactory { versionRange = VersionRange.createFromVersion( version ); } - return createArtifact( groupId, artifactId, versionRange, scope, type, classifier, inheritedScope ); + return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope ); } - private Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, - String type, String classifier, String inheritedScope ) + private Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String type, + String classifier, String scope, String inheritedScope ) + { + return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false ); + } + + private Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String type, + String classifier, String scope, String inheritedScope, boolean optional ) { // TODO: can refactor - inherited scope calculation belongs in the collector, use scope handler @@ -140,6 +152,7 @@ public class DefaultArtifactFactory ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( type ); - return new DefaultArtifact( groupId, artifactId, versionRange, desiredScope, type, classifier, handler ); + return new DefaultArtifact( groupId, artifactId, versionRange, desiredScope, type, classifier, handler, + optional ); } } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java index 4c65f02b55..a9795ca461 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java @@ -77,9 +77,13 @@ public class DefaultArtifactCollector { Artifact artifact = node.getArtifact(); - artifact.setDependencyTrail( node.getDependencyTrail() ); + // If it was optional, we don't add it or its children, just allow the update of the version and scope + if ( !node.getArtifact().isOptional() ) + { + artifact.setDependencyTrail( node.getDependencyTrail() ); - set.add( node ); + set.add( node ); + } } } @@ -169,7 +173,8 @@ public class DefaultArtifactCollector for ( Iterator i = node.getChildrenIterator(); i.hasNext(); ) { ResolutionNode child = (ResolutionNode) i.next(); - if ( !child.isResolved() ) + // We leave in optional ones, but don't pick up its dependencies + if ( !child.isResolved() && !child.getArtifact().isOptional() ) { Artifact artifact = child.getArtifact(); try diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java index 5b0179f2b7..342e323d28 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java @@ -75,24 +75,31 @@ public class ResolutionNode public void addDependencies( Set artifacts, List remoteRepositories, ArtifactFilter filter ) throws CyclicDependencyException, OverConstrainedVersionException { - children = new ArrayList( artifacts.size() ); - - for ( Iterator i = artifacts.iterator(); i.hasNext(); ) + if ( !artifacts.isEmpty() ) { - Artifact a = (Artifact) i.next(); + children = new ArrayList( artifacts.size() ); - if ( filter == null || filter.include( a ) ) + for ( Iterator i = artifacts.iterator(); i.hasNext(); ) { - if ( parents.contains( a.getDependencyConflictId() ) ) + Artifact a = (Artifact) i.next(); + + if ( filter == null || filter.include( a ) ) { - a.setDependencyTrail( getDependencyTrail() ); + if ( parents.contains( a.getDependencyConflictId() ) ) + { + a.setDependencyTrail( getDependencyTrail() ); - throw new CyclicDependencyException( "A dependency has introduced a cycle", a ); + throw new CyclicDependencyException( "A dependency has introduced a cycle", a ); + } + + children.add( new ResolutionNode( a, remoteRepositories, this ) ); } - - children.add( new ResolutionNode( a, remoteRepositories, this ) ); } } + else + { + children = Collections.EMPTY_LIST; + } } public List getDependencyTrail() diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactCollectorTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactCollectorTest.java index b23837e03f..bd3a037a00 100644 --- a/maven-artifact/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactCollectorTest.java +++ b/maven-artifact/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactCollectorTest.java @@ -70,11 +70,11 @@ public class DefaultArtifactCollectorTest // works, but we don't fail on cycles presently public void disabledtestCircularDependencyNotIncludingCurrentProject() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); - b.addDependency( a ); + b.addDependency( "a", "1.0" ); try { collect( a ); @@ -88,7 +88,7 @@ public class DefaultArtifactCollectorTest // works, but we don't fail on cycles presently public void disabledtestCircularDependencyIncludingCurrentProject() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -105,7 +105,7 @@ public class DefaultArtifactCollectorTest } public void testResolveWithFilter() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -124,7 +124,7 @@ public class DefaultArtifactCollectorTest } public void testResolveNearestNewestIsNearest() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -139,7 +139,7 @@ public class DefaultArtifactCollectorTest } public void testResolveNearestOldestIsNearest() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -154,7 +154,7 @@ public class DefaultArtifactCollectorTest } public void testResolveNearestWithRanges() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -169,7 +169,7 @@ public class DefaultArtifactCollectorTest } public void testCompatibleRanges() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -185,7 +185,7 @@ public class DefaultArtifactCollectorTest } public void testIncompatibleRanges() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -204,7 +204,7 @@ public class DefaultArtifactCollectorTest } public void testUnboundedRange() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec b = a.addDependency( "b", "1.0" ); @@ -220,7 +220,7 @@ public class DefaultArtifactCollectorTest } public void testResolveManagedVersion() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); a.addDependency( "b", "3.0", Artifact.SCOPE_RUNTIME ); @@ -233,7 +233,7 @@ public class DefaultArtifactCollectorTest } public void testResolveCompileScopeOverTestScope() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec c = createArtifact( "c", "3.0", Artifact.SCOPE_TEST ); @@ -249,7 +249,7 @@ public class DefaultArtifactCollectorTest } public void testResolveRuntimeScopeOverTestScope() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec c = createArtifact( "c", "3.0", Artifact.SCOPE_TEST ); @@ -265,7 +265,7 @@ public class DefaultArtifactCollectorTest } public void testResolveCompileScopeOverRuntimeScope() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec c = createArtifact( "c", "3.0", Artifact.SCOPE_RUNTIME ); @@ -281,7 +281,7 @@ public class DefaultArtifactCollectorTest } public void testResolveCompileScopeOverProvidedScope() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec c = createArtifact( "c", "3.0", Artifact.SCOPE_PROVIDED ); @@ -297,7 +297,7 @@ public class DefaultArtifactCollectorTest } public void testResolveRuntimeScopeOverProvidedScope() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0" ); ArtifactSpec c = createArtifact( "c", "3.0", Artifact.SCOPE_PROVIDED ); @@ -313,7 +313,7 @@ public class DefaultArtifactCollectorTest } public void testProvidedScopeNotTransitive() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0", Artifact.SCOPE_PROVIDED ); ArtifactSpec b = createArtifact( "b", "1.0" ); @@ -323,8 +323,51 @@ public class DefaultArtifactCollectorTest assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact} ), res.getArtifacts() ); } + public void testOptionalNotTransitive() + throws ArtifactResolutionException, InvalidVersionSpecificationException + { + ArtifactSpec a = createArtifact( "a", "1.0" ); + ArtifactSpec b = createArtifact( "b", "1.0" ); + b.addDependency( "c", "3.0", true ); + + ArtifactResolutionResult res = collect( createSet( new Object[]{a.artifact, b.artifact} ) ); + assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact} ), res.getArtifacts() ); + } + + public void testOptionalIncludedAtRoot() + throws ArtifactResolutionException, InvalidVersionSpecificationException + { + ArtifactSpec a = createArtifact( "a", "1.0" ); + createArtifact( "b", "1.0", true ); + + ArtifactSpec b = createArtifact( "b", "1.0" ); + + ArtifactResolutionResult res = collect( createSet( new Object[]{a.artifact, b.artifact} ) ); + assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact} ), res.getArtifacts() ); + } + + public void disabledtestOptionalNotTransitiveButVersionIsInfluential() + throws ArtifactResolutionException, InvalidVersionSpecificationException + { + ArtifactSpec a = createArtifact( "a", "1.0" ); + ArtifactSpec b = createArtifact( "b", "1.0" ); + b.addDependency( "c", "3.0", true ); + ArtifactSpec d = a.addDependency( "d", "1.0" ); + ArtifactSpec e = d.addDependency( "e", "1.0" ); + e.addDependency( "c", "2.0" ); + + ArtifactSpec c = createArtifact( "c", "3.0" ); + + ArtifactResolutionResult res = collect( createSet( new Object[]{a.artifact, b.artifact} ) ); + assertEquals( "Check artifact list", + createSet( new Object[]{a.artifact, b.artifact, c.artifact, d.artifact, e.artifact} ), + res.getArtifacts() ); + Artifact artifact = getArtifact( "c", res.getArtifacts() ); + assertEquals( "Check version", "3.0", artifact.getVersion() ); + } + public void testTestScopeNotTransitive() - throws ArtifactResolutionException + throws ArtifactResolutionException, InvalidVersionSpecificationException { ArtifactSpec a = createArtifact( "a", "1.0", Artifact.SCOPE_TEST ); ArtifactSpec b = createArtifact( "b", "1.0" ); @@ -377,16 +420,37 @@ public class DefaultArtifactCollectorTest } private ArtifactSpec createArtifact( String id, String version ) + throws InvalidVersionSpecificationException { return createArtifact( id, version, Artifact.SCOPE_COMPILE ); } - private ArtifactSpec createArtifact( String id, String version, String scope ) + private ArtifactSpec createArtifact( String id, String version, boolean optional ) + throws InvalidVersionSpecificationException { - ArtifactSpec spec = new ArtifactSpec(); - Artifact artifact = artifactFactory.createArtifact( GROUP_ID, id, version, scope, "jar" ); - spec.artifact = artifact; - source.artifacts.put( source.getKey( artifact ), spec ); + return createArtifact( id, version, Artifact.SCOPE_COMPILE, null, optional ); + } + + private ArtifactSpec createArtifact( String id, String version, String scope ) + throws InvalidVersionSpecificationException + { + return createArtifact( id, version, scope, null, false ); + } + + private ArtifactSpec createArtifact( String id, String version, String scope, String inheritedScope, + boolean optional ) + throws InvalidVersionSpecificationException + { + VersionRange versionRange = VersionRange.createFromVersionSpec( version ); + Artifact artifact = artifactFactory.createDependencyArtifact( GROUP_ID, id, versionRange, "jar", null, scope, + inheritedScope, optional ); + ArtifactSpec spec = null; + if ( artifact != null ) + { + spec = new ArtifactSpec(); + spec.artifact = artifact; + source.artifacts.put( source.getKey( artifact ), spec ); + } return spec; } @@ -402,20 +466,32 @@ public class DefaultArtifactCollectorTest private Set dependencies = new HashSet(); public ArtifactSpec addDependency( String id, String version ) + throws InvalidVersionSpecificationException { return addDependency( id, version, null ); } public ArtifactSpec addDependency( String id, String version, String scope ) + throws InvalidVersionSpecificationException { - ArtifactSpec dep = createArtifact( id, version, scope ); - addDependency( dep ); + return addDependency( id, version, scope, false ); + } + + private ArtifactSpec addDependency( String id, String version, String scope, boolean optional ) + throws InvalidVersionSpecificationException + { + ArtifactSpec dep = createArtifact( id, version, scope, this.artifact.getScope(), optional ); + if ( dep != null ) + { + dependencies.add( dep.artifact ); + } return dep; } - public void addDependency( ArtifactSpec dep ) + public ArtifactSpec addDependency( String id, String version, boolean optional ) + throws InvalidVersionSpecificationException { - dependencies.add( dep.artifact ); + return addDependency( id, version, Artifact.SCOPE_COMPILE, optional ); } } @@ -459,11 +535,19 @@ public class DefaultArtifactCollectorTest { Artifact d = (Artifact) i.next(); - VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); + VersionRange versionRange; + if ( d.getVersionRange() != null ) + { + versionRange = d.getVersionRange(); + } + else + { + versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); + } Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(), d.getClassifier(), d.getScope(), - inheritedScope ); + inheritedScope, d.isOptional() ); if ( artifact != null && ( dependencyFilter == null || dependencyFilter.include( artifact ) ) ) { diff --git a/maven-model/maven.mdo b/maven-model/maven.mdo index 90efff520c..e7b5602a57 100644 --- a/maven-model/maven.mdo +++ b/maven-model/maven.mdo @@ -1303,6 +1303,7 @@ String @@ -1325,6 +1326,17 @@ * + + optional + 4.0.0 + + Indicates the dependency is optional for use of this library. While the version of the dependency will be + taken into account for dependency calculation if the library is used elsewhere, it will not be passed on + transitively. + + boolean + false + diff --git a/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java b/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java index 36b1b91761..6ad8cbe735 100644 --- a/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java +++ b/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java @@ -76,7 +76,7 @@ public class MavenMetadataSource private ArtifactFactory artifactFactory; private RepositoryMetadataManager repositoryMetadataManager; - + // lazily instantiated and cached. private MavenProject superProject; @@ -190,8 +190,9 @@ public class MavenMetadataSource Set artifacts = project.createArtifacts( artifactFactory, artifact.getScope(), artifact.getDependencyFilter() ); - List repositories = aggregateRepositoryLists( remoteRepositories, project.getRemoteArtifactRepositories() ); - + List repositories = aggregateRepositoryLists( remoteRepositories, + project.getRemoteArtifactRepositories() ); + result = new ResolutionGroup( pomArtifact, artifacts, repositories ); } @@ -275,7 +276,7 @@ public class MavenMetadataSource VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(), d.getClassifier(), - scope, inheritedScope ); + scope, inheritedScope, d.isOptional() ); if ( Artifact.SCOPE_SYSTEM.equals( scope ) ) {