Bug 424586 - Report cycles in dependency graph
Considered root artifact of dependency graph when looking out for cycles
diff --git a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java
index a972a2e..1cb0ceb 100644
--- a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java
+++ b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * Copyright (c) 2010, 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
@@ -429,15 +429,19 @@
int cycleEntry = args.nodes.find( d.getArtifact() );
if ( cycleEntry >= 0 )
{
- DependencyNode cycleNode = args.nodes.get( cycleEntry );
- DefaultDependencyNode child =
- createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult,
- cycleNode );
-
- node.getChildren().add( child );
results.addCycle( args.nodes, cycleEntry, d );
+ DependencyNode cycleNode = args.nodes.get( cycleEntry );
+ if ( cycleNode.getDependency() != null )
+ {
+ DefaultDependencyNode child =
+ createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult,
+ cycleNode );
+ node.getChildren().add( child );
+ continue;
+ }
}
- else if ( !descriptorResult.getRelocations().isEmpty() )
+
+ if ( !descriptorResult.getRelocations().isEmpty() )
{
boolean disableVersionManagementSubsequently =
originalArtifact.getGroupId().equals( d.getArtifact().getGroupId() )
diff --git a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java
index 6f31f88..94cd344 100644
--- a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java
+++ b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCycle.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 Sonatype, Inc.
+ * Copyright (c) 2013, 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
@@ -16,6 +16,7 @@
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyCycle;
+import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
/**
@@ -31,11 +32,18 @@
public DefaultDependencyCycle( NodeStack nodes, int cycleEntry, Dependency dependency )
{
- int offset = ( nodes.get( 0 ).getDependency() == null ) ? 1 : 0;
+ // skip root node unless it actually has a dependency or is considered the cycle entry (due to its label)
+ int offset = ( cycleEntry > 0 && nodes.get( 0 ).getDependency() == null ) ? 1 : 0;
Dependency[] dependencies = new Dependency[nodes.size() - offset + 1];
for ( int i = 0, n = dependencies.length - 1; i < n; i++ )
{
- dependencies[i] = nodes.get( i + offset ).getDependency();
+ DependencyNode node = nodes.get( i + offset );
+ dependencies[i] = node.getDependency();
+ // when cycle starts at root artifact as opposed to root dependency, synthesize a dependency
+ if ( dependencies[i] == null )
+ {
+ dependencies[i] = new Dependency( node.getArtifact(), null );
+ }
}
dependencies[dependencies.length - 1] = dependency;
this.dependencies = Collections.unmodifiableList( Arrays.asList( dependencies ) );
diff --git a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java
index 658364b..a61bfb4 100644
--- a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java
+++ b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/NodeStack.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * Copyright (c) 2010, 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
@@ -13,7 +13,6 @@
import java.util.Arrays;
import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyNode;
/**
@@ -61,13 +60,12 @@
{
DependencyNode node = nodes[i];
- Dependency dependency = node.getDependency();
- if ( dependency == null )
+ Artifact a = node.getArtifact();
+ if ( a == null )
{
break;
}
- Artifact a = dependency.getArtifact();
if ( !a.getArtifactId().equals( artifact.getArtifactId() ) )
{
continue;
diff --git a/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java b/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java
index a714d5b..b79e990 100644
--- a/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java
+++ b/aether-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDependencyCollectorTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * Copyright (c) 2010, 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
@@ -294,6 +294,29 @@
}
@Test
+ public void testCyclicProjects_ConsiderLabelOfRootlessGraph()
+ throws Exception
+ {
+ Dependency dep = newDep( "gid:aid:ver", "compile" );
+ CollectRequest request =
+ new CollectRequest().addDependency( dep ).addRepository( repository ).setRootArtifact( dep.getArtifact() );
+ CollectResult result = collector.collectDependencies( session, request );
+ DependencyNode root = result.getRoot();
+ DependencyNode a1 = root.getChildren().get( 0 );
+ assertEquals( "aid", a1.getArtifact().getArtifactId() );
+ assertEquals( "ver", a1.getArtifact().getVersion() );
+ DependencyNode a2 = a1.getChildren().get( 0 );
+ assertEquals( "aid2", a2.getArtifact().getArtifactId() );
+ assertEquals( "ver", a2.getArtifact().getVersion() );
+
+ assertEquals( 1, result.getCycles().size() );
+ DependencyCycle cycle = result.getCycles().get( 0 );
+ assertEquals( Arrays.asList(), cycle.getPrecedingDependencies() );
+ assertEquals( Arrays.asList( new Dependency( dep.getArtifact(), null ), a1.getDependency() ),
+ cycle.getCyclicDependencies() );
+ }
+
+ @Test
public void testPartialResultOnError()
throws IOException
{