Bug 433102 - Allow nested <dependencies> groups
Made <dependencies> element accept other <dependencies> elements as children
diff --git a/README.md b/README.md
index afc62e5..e5ffb9c 100644
--- a/README.md
+++ b/README.md
@@ -132,7 +132,7 @@
the `<resolve>`-task, which collects the artifacts belonging to the dependencies
transitively.
- <dependency coords="g:a:v"/>
+ <dependency coords="g:a:v:scope"/>
<dependency groupId="g" artifactId="a" version="v" classifier="c" type="jar" scope="runtime">
<exclusion coords="g:a"/>
@@ -145,6 +145,11 @@
<exclusion coords="g:a"/> <!-- global exclusion for all dependencies of this group -->
</dependencies>
+ <dependencies>
+ <dependency coords="test:artifact:1.0:runtime"/>
+ <dependencies refid="deps"/> <!-- nested dependency collection merged into this one -->
+ </dependencies>
+
<dependencies id="depsFromPom" pomRef="pom"/>
<dependencies id="depsFromPlainTextFile" file="dependencies.txt"/>
diff --git a/src/main/java/org/eclipse/aether/ant/AntRepoSys.java b/src/main/java/org/eclipse/aether/ant/AntRepoSys.java
index cf81357..364173f 100644
--- a/src/main/java/org/eclipse/aether/ant/AntRepoSys.java
+++ b/src/main/java/org/eclipse/aether/ant/AntRepoSys.java
@@ -61,6 +61,7 @@
import org.eclipse.aether.ant.types.Authentication;
import org.eclipse.aether.ant.types.Dependencies;
import org.eclipse.aether.ant.types.Dependency;
+import org.eclipse.aether.ant.types.DependencyContainer;
import org.eclipse.aether.ant.types.Exclusion;
import org.eclipse.aether.ant.types.LocalRepository;
import org.eclipse.aether.ant.types.Mirror;
@@ -617,64 +618,7 @@
if ( dependencies != null )
{
- List<Exclusion> globalExclusions = dependencies.getExclusions();
- Collection<String> ids = new HashSet<String>();
-
- for ( Dependency dep : dependencies.getDependencies() )
- {
- ids.add( dep.getVersionlessKey() );
- collectRequest.addDependency( ConverterUtils.toDependency( dep, globalExclusions, session ) );
- }
-
- if ( dependencies.getPom() != null )
- {
- Model model = dependencies.getPom().getModel( task );
- for ( org.apache.maven.model.Dependency dep : model.getDependencies() )
- {
- Dependency dependency = new Dependency();
- dependency.setArtifactId( dep.getArtifactId() );
- dependency.setClassifier( dep.getClassifier() );
- dependency.setGroupId( dep.getGroupId() );
- dependency.setScope( dep.getScope() );
- dependency.setType( dep.getType() );
- dependency.setVersion( dep.getVersion() );
- if ( ids.contains( dependency.getVersionlessKey() ) )
- {
- project.log( "Ignoring dependency " + dependency.getVersionlessKey() + " from " + model.getId()
- + ", already declared locally", Project.MSG_VERBOSE );
- continue;
- }
- if ( dep.getSystemPath() != null && dep.getSystemPath().length() > 0 )
- {
- dependency.setSystemPath( task.getProject().resolveFile( dep.getSystemPath() ) );
- }
- for ( org.apache.maven.model.Exclusion exc : dep.getExclusions() )
- {
- Exclusion exclusion = new Exclusion();
- exclusion.setGroupId( exc.getGroupId() );
- exclusion.setArtifactId( exc.getArtifactId() );
- exclusion.setClassifier( "*" );
- exclusion.setExtension( "*" );
- dependency.addExclusion( exclusion );
- }
- collectRequest.addDependency( ConverterUtils.toDependency( dependency, globalExclusions, session ) );
- }
- }
-
- if ( dependencies.getFile() != null )
- {
- List<Dependency> deps = readDependencies( dependencies.getFile() );
- for ( Dependency dependency : deps )
- {
- if ( ids.contains( dependency.getVersionlessKey() ) )
- {
- project.log( "Ignoring dependency " + dependency.getVersionlessKey() + " from "
- + dependencies.getFile() + ", already declared locally", Project.MSG_VERBOSE );
- continue;
- }
- collectRequest.addDependency( ConverterUtils.toDependency( dependency, globalExclusions, session ) );
- }
- }
+ populateCollectRequest( collectRequest, task, session, dependencies, Collections.<Exclusion> emptyList() );
}
task.getProject().log( "Collecting dependencies", Project.MSG_VERBOSE );
@@ -692,6 +636,83 @@
return result;
}
+ private void populateCollectRequest( CollectRequest collectRequest, Task task, RepositorySystemSession session,
+ Dependencies dependencies, List<Exclusion> exclusions )
+ {
+ List<Exclusion> globalExclusions = exclusions;
+ if ( !dependencies.getExclusions().isEmpty() )
+ {
+ globalExclusions = new ArrayList<Exclusion>( exclusions );
+ globalExclusions.addAll( dependencies.getExclusions() );
+ }
+
+ Collection<String> ids = new HashSet<String>();
+
+ for ( DependencyContainer container : dependencies.getDependencyContainers() )
+ {
+ if ( container instanceof Dependency )
+ {
+ Dependency dep = (Dependency) container;
+ ids.add( dep.getVersionlessKey() );
+ collectRequest.addDependency( ConverterUtils.toDependency( dep, globalExclusions, session ) );
+ }
+ else
+ {
+ populateCollectRequest( collectRequest, task, session, (Dependencies) container, globalExclusions );
+ }
+ }
+
+ if ( dependencies.getPom() != null )
+ {
+ Model model = dependencies.getPom().getModel( task );
+ for ( org.apache.maven.model.Dependency dep : model.getDependencies() )
+ {
+ Dependency dependency = new Dependency();
+ dependency.setArtifactId( dep.getArtifactId() );
+ dependency.setClassifier( dep.getClassifier() );
+ dependency.setGroupId( dep.getGroupId() );
+ dependency.setScope( dep.getScope() );
+ dependency.setType( dep.getType() );
+ dependency.setVersion( dep.getVersion() );
+ if ( ids.contains( dependency.getVersionlessKey() ) )
+ {
+ project.log( "Ignoring dependency " + dependency.getVersionlessKey() + " from " + model.getId()
+ + ", already declared locally", Project.MSG_VERBOSE );
+ continue;
+ }
+ if ( dep.getSystemPath() != null && dep.getSystemPath().length() > 0 )
+ {
+ dependency.setSystemPath( task.getProject().resolveFile( dep.getSystemPath() ) );
+ }
+ for ( org.apache.maven.model.Exclusion exc : dep.getExclusions() )
+ {
+ Exclusion exclusion = new Exclusion();
+ exclusion.setGroupId( exc.getGroupId() );
+ exclusion.setArtifactId( exc.getArtifactId() );
+ exclusion.setClassifier( "*" );
+ exclusion.setExtension( "*" );
+ dependency.addExclusion( exclusion );
+ }
+ collectRequest.addDependency( ConverterUtils.toDependency( dependency, globalExclusions, session ) );
+ }
+ }
+
+ if ( dependencies.getFile() != null )
+ {
+ List<Dependency> deps = readDependencies( dependencies.getFile() );
+ for ( Dependency dependency : deps )
+ {
+ if ( ids.contains( dependency.getVersionlessKey() ) )
+ {
+ project.log( "Ignoring dependency " + dependency.getVersionlessKey() + " from "
+ + dependencies.getFile() + ", already declared locally", Project.MSG_VERBOSE );
+ continue;
+ }
+ collectRequest.addDependency( ConverterUtils.toDependency( dependency, globalExclusions, session ) );
+ }
+ }
+ }
+
private List<Dependency> readDependencies( File file )
{
List<Dependency> dependencies = new ArrayList<Dependency>();
diff --git a/src/main/java/org/eclipse/aether/ant/types/Dependencies.java b/src/main/java/org/eclipse/aether/ant/types/Dependencies.java
index d26627d..35702ca 100644
--- a/src/main/java/org/eclipse/aether/ant/types/Dependencies.java
+++ b/src/main/java/org/eclipse/aether/ant/types/Dependencies.java
@@ -25,16 +25,19 @@
*/
public class Dependencies
extends DataType
+ implements DependencyContainer
{
private File file;
private Pom pom;
- private List<Dependency> dependencies = new ArrayList<Dependency>();
+ private List<DependencyContainer> containers = new ArrayList<DependencyContainer>();
private List<Exclusion> exclusions = new ArrayList<Exclusion>();
+ private boolean nestedDependencies;
+
protected Dependencies getRef()
{
return (Dependencies) getCheckedRef();
@@ -53,16 +56,20 @@
throw new BuildException( "A <pom> used for dependency resolution has to be backed by a pom.xml file" );
}
Map<String, String> ids = new HashMap<String, String>();
- for ( Dependency dependency : dependencies )
+ for ( DependencyContainer container : containers )
{
- dependency.validate( task );
- String id = dependency.getVersionlessKey();
- String collision = ids.put( id, dependency.getVersion() );
- if ( collision != null )
+ container.validate( task );
+ if ( container instanceof Dependency )
{
- throw new BuildException( "You must not declare multiple <dependency> elements"
- + " with the same coordinates but got " + id + " -> " + collision + " vs "
- + dependency.getVersion() );
+ Dependency dependency = (Dependency) container;
+ String id = dependency.getVersionlessKey();
+ String collision = ids.put( id, dependency.getVersion() );
+ if ( collision != null )
+ {
+ throw new BuildException( "You must not declare multiple <dependency> elements"
+ + " with the same coordinates but got " + id + " -> " + collision + " vs "
+ + dependency.getVersion() );
+ }
}
}
}
@@ -70,7 +77,7 @@
public void setRefid( Reference ref )
{
- if ( pom != null || !exclusions.isEmpty() || !dependencies.isEmpty() )
+ if ( pom != null || !exclusions.isEmpty() || !containers.isEmpty() )
{
throw noChildrenAllowed();
}
@@ -130,21 +137,37 @@
{
throw new BuildException( "You must not specify both a text file and a POM to list dependencies" );
}
+ if ( ( file != null || pom != null ) && nestedDependencies )
+ {
+ throw new BuildException( "You must not specify both a file/POM and nested dependency collections" );
+ }
}
public void addDependency( Dependency dependency )
{
checkChildrenAllowed();
- this.dependencies.add( dependency );
+ containers.add( dependency );
}
- public List<Dependency> getDependencies()
+ public void addDependencies( Dependencies dependencies )
+ {
+ checkChildrenAllowed();
+ if ( dependencies == this )
+ {
+ throw circularReference();
+ }
+ containers.add( dependencies );
+ nestedDependencies = true;
+ checkExternalSources();
+ }
+
+ public List<DependencyContainer> getDependencyContainers()
{
if ( isReference() )
{
- return getRef().getDependencies();
+ return getRef().getDependencyContainers();
}
- return dependencies;
+ return containers;
}
public void addExclusion( Exclusion exclusion )
diff --git a/src/main/java/org/eclipse/aether/ant/types/Dependency.java b/src/main/java/org/eclipse/aether/ant/types/Dependency.java
index 4343a4a..9ca40bd 100644
--- a/src/main/java/org/eclipse/aether/ant/types/Dependency.java
+++ b/src/main/java/org/eclipse/aether/ant/types/Dependency.java
@@ -26,6 +26,7 @@
*/
public class Dependency
extends DataType
+ implements DependencyContainer
{
private String groupId;
diff --git a/src/main/java/org/eclipse/aether/ant/types/DependencyContainer.java b/src/main/java/org/eclipse/aether/ant/types/DependencyContainer.java
new file mode 100644
index 0000000..b05b3e5
--- /dev/null
+++ b/src/main/java/org/eclipse/aether/ant/types/DependencyContainer.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.ant.types;
+
+import org.apache.tools.ant.Task;
+
+/**
+ */
+public interface DependencyContainer
+{
+
+ void validate( Task task );
+
+}
diff --git a/src/test/java/org/eclipse/aether/ant/ResolveTest.java b/src/test/java/org/eclipse/aether/ant/ResolveTest.java
index 921f80d..cf3d545 100644
--- a/src/test/java/org/eclipse/aether/ant/ResolveTest.java
+++ b/src/test/java/org/eclipse/aether/ant/ResolveTest.java
@@ -108,4 +108,16 @@
assertThat( "aether-api was resolved as a property", prop, nullValue() );
}
+ public void testResolveNestedDependencyCollections()
+ {
+ executeTarget( "testResolveNestedDependencyCollections" );
+
+ String prop = getProject().getProperty( "test.resolve.path.org.eclipse.aether:aether-spi:jar" );
+ assertThat( "aether-spi was not resolved as a property", prop, notNullValue() );
+ prop = getProject().getProperty( "test.resolve.path.org.eclipse.aether:aether-util:jar" );
+ assertThat( "aether-util was not resolved as a property", prop, notNullValue() );
+ prop = getProject().getProperty( "test.resolve.path.org.eclipse.aether:aether-api:jar" );
+ assertThat( "aether-api was resolved as a property", prop, nullValue() );
+ }
+
}
diff --git a/src/test/resources/ant/Resolve/ant.xml b/src/test/resources/ant/Resolve/ant.xml
index e7c4890..4ff378f 100644
--- a/src/test/resources/ant/Resolve/ant.xml
+++ b/src/test/resources/ant/Resolve/ant.xml
@@ -63,7 +63,7 @@
<target name="testResolveAttachments">
<repo:resolve>
<dependencies>
- <dependency groupid="org.eclipse.aether" artifactid="aether-impl" version="0.9.0.M3" />
+ <dependency groupid="org.eclipse.aether" artifactid="aether-impl" version="0.9.0.v20140226" />
</dependencies>
<files dir="${build.dir}/resolve-attachments/" layout="javadoc/{groupId}-{artifactId}-{classifier}.{extension}" attachments="javadoc"/>
<files dir="${build.dir}/resolve-attachments/" layout="sources/{groupId}-{artifactId}-{classifier}.{extension}" attachments="sources"/>
@@ -87,4 +87,19 @@
</repo:resolve>
</target>
+ <target name="testResolveNestedDependencyCollections">
+ <repo:resolve>
+ <dependencies>
+ <dependencies>
+ <dependency groupid="org.eclipse.aether" artifactid="aether-spi" version="0.9.0.v20140226" />
+ </dependencies>
+ <dependencies>
+ <dependency groupid="org.eclipse.aether" artifactid="aether-util" version="0.9.0.v20140226" />
+ </dependencies>
+ <exclusion coords="org.eclipse.aether:aether-api"/>
+ </dependencies>
+ <properties prefix="test.resolve.path" classpath="runtime"/>
+ </repo:resolve>
+ </target>
+
</project>