You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by hi...@apache.org on 2017/06/01 12:11:20 UTC

[1/3] ant-ivy git commit: IVY-1540 Fix infinite loop in dependencytree, caused to due circular dependencies (coming in via Maven module descriptors)

Repository: ant-ivy
Updated Branches:
  refs/heads/master 0dbae4197 -> 4d1551a5d


IVY-1540 Fix infinite loop in dependencytree, caused to due circular dependencies (coming in via Maven module descriptors)


Project: http://git-wip-us.apache.org/repos/asf/ant-ivy/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant-ivy/commit/2f757454
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/2f757454
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/2f757454

Branch: refs/heads/master
Commit: 2f757454dc41f4d130234aea68b348da4f12a0fa
Parents: 5601c44
Author: Jaikiran Pai <ja...@gmail.com>
Authored: Tue May 23 13:45:39 2017 +0530
Committer: Jaikiran Pai <ja...@gmail.com>
Committed: Tue May 30 09:48:48 2017 +0530

----------------------------------------------------------------------
 .../org/apache/ivy/ant/IvyDependencyTree.java   | 73 ++++++++++++--------
 .../apache/ivy/ant/IvyDependencyTreeTest.java   | 30 +++++++-
 .../1/org/foo-bar/ivys/ivy-1.2.3.xml            | 28 ++++++++
 .../1/org/foo-bar/jars/foo-bar-1.2.3.jar        |  0
 test/repositories/1/org/mod1/ivys/ivy-2.0.xml   | 27 ++++++++
 test/repositories/1/org/mod1/jars/mod1-2.0.jar  |  0
 .../m2/org/circular/module1/1.0/module1-1.0.jar |  1 +
 .../m2/org/circular/module1/1.0/module1-1.0.pom | 35 ++++++++++
 .../m2/org/circular/module2/2.0/module2-2.0.jar |  1 +
 .../m2/org/circular/module2/2.0/module2-2.0.pom | 35 ++++++++++
 10 files changed, 201 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/src/java/org/apache/ivy/ant/IvyDependencyTree.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/ant/IvyDependencyTree.java b/src/java/org/apache/ivy/ant/IvyDependencyTree.java
index b95aa91..5df9548 100644
--- a/src/java/org/apache/ivy/ant/IvyDependencyTree.java
+++ b/src/java/org/apache/ivy/ant/IvyDependencyTree.java
@@ -17,12 +17,6 @@
  */
 package org.apache.ivy.ant;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.ResolveReport;
 import org.apache.ivy.core.resolve.IvyNode;
@@ -30,18 +24,26 @@ import org.apache.ivy.core.resolve.IvyNodeCallers.Caller;
 import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData;
 import org.apache.tools.ant.BuildException;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 public class IvyDependencyTree extends IvyPostResolveTask {
 
-    private Map/* <ModuleRevisionId, List<IvyNode>> */dependencies = new HashMap/*
-                                                                                 * <ModuleRevisionId,
-                                                                                 * List<IvyNode>>
-                                                                                 */();
+    private final Map<ModuleRevisionId, List<IvyNode>> dependencies = new HashMap<ModuleRevisionId, List<IvyNode>>();
 
     private boolean showEvicted = false;
 
     public void doExecute() throws BuildException {
         prepareAndCheck();
         ResolveReport report = getResolvedReport();
+        if (report == null) {
+            throw new BuildException("No resolution report was available to run the post-resolve task. Make sure resolve was done before this task");
+        }
         log("Dependency tree for " + report.getResolveId());
         ModuleRevisionId mrid = report.getModuleDescriptor().getModuleRevisionId();
         // make dependency tree easier to fetch information
@@ -49,20 +51,26 @@ public class IvyDependencyTree extends IvyPostResolveTask {
             IvyNode dependency = (IvyNode) iterator.next();
             populateDependencyTree(dependency, mrid, report);
         }
-        List dependencyList = (List) dependencies.get(mrid);
+        final List<IvyNode> dependencyList = dependencies.get(mrid);
         if (dependencyList != null) {
-            printDependencies(dependencyList, 0);
+            printDependencies(mrid, dependencyList, 0, new HashSet<ModuleRevisionId>());
         }
     }
 
-    private void printDependencies(List/* <IvyNode> */dependencyList, int indent) {
-        for (Iterator iterator = dependencyList.iterator(); iterator.hasNext();) {
-            IvyNode dependency = (IvyNode) iterator.next();
-            boolean evicted = dependency.isEvicted(getConf());
+    private void printDependencies(final ModuleRevisionId mrid, final List<IvyNode> dependencyList, final int indent,
+                                   final Set<ModuleRevisionId> ancestors) {
+        for (final Iterator iterator = dependencyList.iterator(); iterator.hasNext();) {
+            final Set<ModuleRevisionId> ancestorsForCurrentDep = new HashSet<ModuleRevisionId>(ancestors);
+            // previous ancestors plus the module to whom these dependencies belong to
+            ancestorsForCurrentDep.add(mrid);
+            final IvyNode dependency = (IvyNode) iterator.next();
+            final ModuleRevisionId dependencyMrid = dependency.getId();
+            final boolean circular = ancestorsForCurrentDep.contains(dependencyMrid);
+            final boolean evicted = dependency.isEvicted(getConf());
+            final StringBuilder sb = new StringBuilder();
             if (evicted && !showEvicted) {
                 continue;
             }
-            StringBuffer sb = new StringBuffer();
             if (indent > 0) {
                 for (int i = 0; i < indent; i++) {
                     if (i == indent - 1 && !iterator.hasNext() && !hasDependencies(dependency)) {
@@ -78,7 +86,15 @@ public class IvyDependencyTree extends IvyPostResolveTask {
             } else {
                 sb.append("\\- ");
             }
-            sb.append(dependency.getId().toString());
+            if (!evicted && circular) {
+                // log and skip processing the (transitive) dependencies of this dependency
+                sb.append("(circularly depends on) ").append(dependencyMrid);
+                log(sb.toString());
+                continue;
+
+            } else {
+                sb.append(dependencyMrid.toString());
+            }
             if (evicted && showEvicted) {
                 EvictionData evictedData = dependency.getEvictedData(getConf());
                 if (evictedData.isTransitivelyEvicted()) {
@@ -94,13 +110,16 @@ public class IvyDependencyTree extends IvyPostResolveTask {
             }
             log(sb.toString());
 
-            printDependencies((List) dependencies.get(dependency.getId()), indent + 1);
+            printDependencies(dependencyMrid, dependencies.get(dependencyMrid), indent + 1, ancestorsForCurrentDep);
         }
     }
 
-    private boolean hasDependencies(IvyNode dependency) {
-        List dependencyList = (List) dependencies.get(dependency.getId());
-        return dependencyList.size() > 0;
+    private boolean hasDependencies(final IvyNode module) {
+        if (module == null) {
+            return false;
+        }
+        final List<IvyNode> dependenciesForModule = dependencies.get(module.getId());
+        return dependenciesForModule != null && !dependenciesForModule.isEmpty();
     }
 
     private void populateDependencyTree(IvyNode dependency, ModuleRevisionId currentMrid,
@@ -112,16 +131,16 @@ public class IvyDependencyTree extends IvyPostResolveTask {
         }
     }
 
-    private void registerNodeIfNecessary(ModuleRevisionId moduleRevisionId) {
+    private void registerNodeIfNecessary(final ModuleRevisionId moduleRevisionId) {
         if (!dependencies.containsKey(moduleRevisionId)) {
-            dependencies.put(moduleRevisionId, new ArrayList/* <IvyNode> */());
+            dependencies.put(moduleRevisionId, new ArrayList<IvyNode>());
         }
     }
 
-    private void addDependency(ModuleRevisionId moduleRevisionId, IvyNode dependency) {
+    private void addDependency(final ModuleRevisionId moduleRevisionId, final IvyNode dependency) {
         registerNodeIfNecessary(moduleRevisionId);
-        List/* <IvyNode> */list = (List) dependencies.get(moduleRevisionId);
-        list.add(dependency);
+        final List<IvyNode> dependencyList = dependencies.get(moduleRevisionId);
+        dependencyList.add(dependency);
     }
 
     public boolean isShowEvicted() {

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/java/org/apache/ivy/ant/IvyDependencyTreeTest.java
----------------------------------------------------------------------
diff --git a/test/java/org/apache/ivy/ant/IvyDependencyTreeTest.java b/test/java/org/apache/ivy/ant/IvyDependencyTreeTest.java
index 23c1ed4..14437e9 100644
--- a/test/java/org/apache/ivy/ant/IvyDependencyTreeTest.java
+++ b/test/java/org/apache/ivy/ant/IvyDependencyTreeTest.java
@@ -17,8 +17,6 @@
  */
 package org.apache.ivy.ant;
 
-import java.io.File;
-
 import org.apache.ivy.TestHelper;
 import org.apache.ivy.ant.testutil.AntTaskTestCase;
 import org.apache.tools.ant.BuildException;
@@ -27,6 +25,9 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.File;
+
+
 public class IvyDependencyTreeTest extends AntTaskTestCase {
 
     private IvyDependencyTree dependencyTree;
@@ -117,4 +118,29 @@ public class IvyDependencyTreeTest extends AntTaskTestCase {
         assertLogContaining("\\- org1#mod1.2;2.2");
     }
 
+
+    /**
+     * Tests that dependency tree task doesn't run into an infinite loop due to circular dependencies
+     *
+     * @throws Exception
+     * @see <a href="https://issues.apache.org/jira/browse/IVY-1540">IVY-1540</a> for more details
+     */
+    @Test
+    public void testCircularDep() throws Exception {
+        final String resolveId = "circular-dep-tree";
+        // resolve
+        final IvyResolve ivyResolve = new IvyResolve();
+        ivyResolve.setProject(project);
+        ivyResolve.setResolveId(resolveId);
+        ivyResolve.setFile(new File("test/repositories/1/org/foo-bar/ivys/ivy-1.2.3.xml"));
+        ivyResolve.execute();
+        // use the resolveid to fetch the dependency tree from that previous resolution
+        dependencyTree.setResolveId(resolveId);
+        dependencyTree.execute();
+        // check the logged message
+        assertLogContaining("Dependency tree for " + resolveId);
+        assertLogContaining("(circularly depends on) " + "org.circular#module1;1.0");
+        assertLogNotContaining("(circularly depends on) " + "org.circular#module2;2.0");
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/1/org/foo-bar/ivys/ivy-1.2.3.xml
----------------------------------------------------------------------
diff --git a/test/repositories/1/org/foo-bar/ivys/ivy-1.2.3.xml b/test/repositories/1/org/foo-bar/ivys/ivy-1.2.3.xml
new file mode 100644
index 0000000..ab09e3e
--- /dev/null
+++ b/test/repositories/1/org/foo-bar/ivys/ivy-1.2.3.xml
@@ -0,0 +1,28 @@
+<!--
+   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.
+-->
+<ivy-module version="1.0">
+    <info organisation="org"
+          module="foo-bar"
+          revision="1.2.3"
+    />
+    <dependencies>
+        <dependency org="org.circular" name="module1" rev="1.0"/>
+        <dependency org="org" name="mod1" rev="2.0" />
+    </dependencies>
+</ivy-module>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/1/org/foo-bar/jars/foo-bar-1.2.3.jar
----------------------------------------------------------------------
diff --git a/test/repositories/1/org/foo-bar/jars/foo-bar-1.2.3.jar b/test/repositories/1/org/foo-bar/jars/foo-bar-1.2.3.jar
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/1/org/mod1/ivys/ivy-2.0.xml
----------------------------------------------------------------------
diff --git a/test/repositories/1/org/mod1/ivys/ivy-2.0.xml b/test/repositories/1/org/mod1/ivys/ivy-2.0.xml
new file mode 100644
index 0000000..27a8cb4
--- /dev/null
+++ b/test/repositories/1/org/mod1/ivys/ivy-2.0.xml
@@ -0,0 +1,27 @@
+<!--
+   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.
+-->
+<ivy-module version="1.0">
+    <info organisation="org"
+          module="mod1"
+          revision="2.0"
+    />
+    <dependencies>
+        <dependency org="org" name="foo-bar" rev="1.2.3" />
+    </dependencies>
+</ivy-module>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/1/org/mod1/jars/mod1-2.0.jar
----------------------------------------------------------------------
diff --git a/test/repositories/1/org/mod1/jars/mod1-2.0.jar b/test/repositories/1/org/mod1/jars/mod1-2.0.jar
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/m2/org/circular/module1/1.0/module1-1.0.jar
----------------------------------------------------------------------
diff --git a/test/repositories/m2/org/circular/module1/1.0/module1-1.0.jar b/test/repositories/m2/org/circular/module1/1.0/module1-1.0.jar
new file mode 100644
index 0000000..56f3b36
--- /dev/null
+++ b/test/repositories/m2/org/circular/module1/1.0/module1-1.0.jar
@@ -0,0 +1 @@
+ 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/m2/org/circular/module1/1.0/module1-1.0.pom
----------------------------------------------------------------------
diff --git a/test/repositories/m2/org/circular/module1/1.0/module1-1.0.pom b/test/repositories/m2/org/circular/module1/1.0/module1-1.0.pom
new file mode 100644
index 0000000..4d7c8ff
--- /dev/null
+++ b/test/repositories/m2/org/circular/module1/1.0/module1-1.0.pom
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+   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.    
+-->
+<project>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.circular</groupId>
+    <artifactId>module1</artifactId>
+    <name>Test Module for Ivy tests</name>
+    <version>1.0</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.circular</groupId>
+            <artifactId>module2</artifactId>
+            <version>2.0</version>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/m2/org/circular/module2/2.0/module2-2.0.jar
----------------------------------------------------------------------
diff --git a/test/repositories/m2/org/circular/module2/2.0/module2-2.0.jar b/test/repositories/m2/org/circular/module2/2.0/module2-2.0.jar
new file mode 100644
index 0000000..56f3b36
--- /dev/null
+++ b/test/repositories/m2/org/circular/module2/2.0/module2-2.0.jar
@@ -0,0 +1 @@
+ 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/2f757454/test/repositories/m2/org/circular/module2/2.0/module2-2.0.pom
----------------------------------------------------------------------
diff --git a/test/repositories/m2/org/circular/module2/2.0/module2-2.0.pom b/test/repositories/m2/org/circular/module2/2.0/module2-2.0.pom
new file mode 100644
index 0000000..fd751b6
--- /dev/null
+++ b/test/repositories/m2/org/circular/module2/2.0/module2-2.0.pom
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+   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.    
+-->
+<project>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.circular</groupId>
+    <artifactId>module2</artifactId>
+    <name>Test Module for Ivy tests</name>
+    <version>2.0</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.circular</groupId>
+            <artifactId>module1</artifactId>
+            <version>1.0</version>
+        </dependency>
+    </dependencies>
+
+</project>


[2/3] ant-ivy git commit: This closes #27

Posted by hi...@apache.org.
This closes #27


Project: http://git-wip-us.apache.org/repos/asf/ant-ivy/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant-ivy/commit/fdeb6b86
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/fdeb6b86
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/fdeb6b86

Branch: refs/heads/master
Commit: fdeb6b86219d13a370d325ee49c694631b7e9ff3
Parents: 0dbae41 2f75745
Author: Nicolas Lalevée <ni...@hibnet.org>
Authored: Thu Jun 1 14:02:06 2017 +0200
Committer: Nicolas Lalevée <ni...@hibnet.org>
Committed: Thu Jun 1 14:09:44 2017 +0200

----------------------------------------------------------------------
 .../org/apache/ivy/ant/IvyDependencyTree.java   | 68 ++++++++++++--------
 .../apache/ivy/ant/IvyDependencyTreeTest.java   | 25 +++++++
 .../1/org/foo-bar/ivys/ivy-1.2.3.xml            | 28 ++++++++
 .../1/org/foo-bar/jars/foo-bar-1.2.3.jar        |  0
 test/repositories/1/org/mod1/ivys/ivy-2.0.xml   | 27 ++++++++
 test/repositories/1/org/mod1/jars/mod1-2.0.jar  |  0
 .../m2/org/circular/module1/1.0/module1-1.0.jar |  1 +
 .../m2/org/circular/module1/1.0/module1-1.0.pom | 35 ++++++++++
 .../m2/org/circular/module2/2.0/module2-2.0.jar |  1 +
 .../m2/org/circular/module2/2.0/module2-2.0.pom | 35 ++++++++++
 10 files changed, 194 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/fdeb6b86/src/java/org/apache/ivy/ant/IvyDependencyTree.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/ivy/ant/IvyDependencyTree.java
index b95aa91,5df9548..e2e5978
--- a/src/java/org/apache/ivy/ant/IvyDependencyTree.java
+++ b/src/java/org/apache/ivy/ant/IvyDependencyTree.java
@@@ -17,25 -17,24 +17,24 @@@
   */
  package org.apache.ivy.ant;
  
 -import org.apache.ivy.core.module.id.ModuleRevisionId;
 -import org.apache.ivy.core.report.ResolveReport;
 -import org.apache.ivy.core.resolve.IvyNode;
 -import org.apache.ivy.core.resolve.IvyNodeCallers.Caller;
 -import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData;
 -import org.apache.tools.ant.BuildException;
 -
  import java.util.ArrayList;
  import java.util.HashMap;
+ import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
+ import java.util.Set;
  
 +import org.apache.ivy.core.module.id.ModuleRevisionId;
 +import org.apache.ivy.core.report.ResolveReport;
 +import org.apache.ivy.core.resolve.IvyNode;
 +import org.apache.ivy.core.resolve.IvyNodeCallers.Caller;
 +import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData;
 +import org.apache.tools.ant.BuildException;
 +
  public class IvyDependencyTree extends IvyPostResolveTask {
  
-     private Map/* <ModuleRevisionId, List<IvyNode>> */dependencies = new HashMap/*
-                                                                                  * <ModuleRevisionId,
-                                                                                  * List<IvyNode>>
-                                                                                  */();
 -    private final Map<ModuleRevisionId, List<IvyNode>> dependencies = new HashMap<ModuleRevisionId, List<IvyNode>>();
++    private final Map<ModuleRevisionId, List<IvyNode>> dependencies = new HashMap<>();
  
      private boolean showEvicted = false;
  
@@@ -45,24 -47,30 +47,29 @@@
          log("Dependency tree for " + report.getResolveId());
          ModuleRevisionId mrid = report.getModuleDescriptor().getModuleRevisionId();
          // make dependency tree easier to fetch information
--        for (Iterator iterator = report.getDependencies().iterator(); iterator.hasNext();) {
--            IvyNode dependency = (IvyNode) iterator.next();
--            populateDependencyTree(dependency, mrid, report);
++        for (IvyNode dependency : report.getDependencies()) {
++            populateDependencyTree(dependency);
          }
-         List dependencyList = (List) dependencies.get(mrid);
+         final List<IvyNode> dependencyList = dependencies.get(mrid);
          if (dependencyList != null) {
-             printDependencies(dependencyList, 0);
+             printDependencies(mrid, dependencyList, 0, new HashSet<ModuleRevisionId>());
          }
      }
  
-     private void printDependencies(List/* <IvyNode> */dependencyList, int indent) {
-         for (Iterator iterator = dependencyList.iterator(); iterator.hasNext();) {
-             IvyNode dependency = (IvyNode) iterator.next();
-             boolean evicted = dependency.isEvicted(getConf());
+     private void printDependencies(final ModuleRevisionId mrid, final List<IvyNode> dependencyList, final int indent,
+                                    final Set<ModuleRevisionId> ancestors) {
+         for (final Iterator iterator = dependencyList.iterator(); iterator.hasNext();) {
 -            final Set<ModuleRevisionId> ancestorsForCurrentDep = new HashSet<ModuleRevisionId>(ancestors);
++            final Set<ModuleRevisionId> ancestorsForCurrentDep = new HashSet<>(ancestors);
+             // previous ancestors plus the module to whom these dependencies belong to
+             ancestorsForCurrentDep.add(mrid);
+             final IvyNode dependency = (IvyNode) iterator.next();
 -            final ModuleRevisionId dependencyMrid = dependency.getId();
 -            final boolean circular = ancestorsForCurrentDep.contains(dependencyMrid);
+             final boolean evicted = dependency.isEvicted(getConf());
 -            final StringBuilder sb = new StringBuilder();
              if (evicted && !showEvicted) {
                  continue;
              }
-             StringBuffer sb = new StringBuffer();
++            final StringBuilder sb = new StringBuilder();
++            final ModuleRevisionId dependencyMrid = dependency.getId();
++            final boolean circular = ancestorsForCurrentDep.contains(dependencyMrid);
              if (indent > 0) {
                  for (int i = 0; i < indent; i++) {
                      if (i == indent - 1 && !iterator.hasNext() && !hasDependencies(dependency)) {
@@@ -78,7 -86,15 +85,14 @@@
              } else {
                  sb.append("\\- ");
              }
-             sb.append(dependency.getId().toString());
+             if (!evicted && circular) {
+                 // log and skip processing the (transitive) dependencies of this dependency
+                 sb.append("(circularly depends on) ").append(dependencyMrid);
+                 log(sb.toString());
+                 continue;
 -
+             } else {
+                 sb.append(dependencyMrid.toString());
+             }
              if (evicted && showEvicted) {
                  EvictionData evictedData = dependency.getEvictedData(getConf());
                  if (evictedData.isTransitivelyEvicted()) {
@@@ -98,13 -114,16 +112,15 @@@
          }
      }
  
-     private boolean hasDependencies(IvyNode dependency) {
-         List dependencyList = (List) dependencies.get(dependency.getId());
-         return dependencyList.size() > 0;
+     private boolean hasDependencies(final IvyNode module) {
+         if (module == null) {
+             return false;
+         }
+         final List<IvyNode> dependenciesForModule = dependencies.get(module.getId());
+         return dependenciesForModule != null && !dependenciesForModule.isEmpty();
      }
  
--    private void populateDependencyTree(IvyNode dependency, ModuleRevisionId currentMrid,
--            ResolveReport report) {
++    private void populateDependencyTree(IvyNode dependency) {
          registerNodeIfNecessary(dependency.getId());
          for (int i = 0; i < dependency.getAllCallers().length; i++) {
              Caller caller = dependency.getAllCallers()[i];

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/fdeb6b86/test/java/org/apache/ivy/ant/IvyDependencyTreeTest.java
----------------------------------------------------------------------


[3/3] ant-ivy git commit: release notes for IVY-1540

Posted by hi...@apache.org.
release notes for IVY-1540


Project: http://git-wip-us.apache.org/repos/asf/ant-ivy/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant-ivy/commit/4d1551a5
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/4d1551a5
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/4d1551a5

Branch: refs/heads/master
Commit: 4d1551a5d6b516987fbc6a987e93b964fab40fe6
Parents: fdeb6b8
Author: Nicolas Lalevée <ni...@hibnet.org>
Authored: Thu Jun 1 14:11:14 2017 +0200
Committer: Nicolas Lalevée <ni...@hibnet.org>
Committed: Thu Jun 1 14:11:14 2017 +0200

----------------------------------------------------------------------
 doc/release-notes.html | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/4d1551a5/doc/release-notes.html
----------------------------------------------------------------------
diff --git a/doc/release-notes.html b/doc/release-notes.html
index 3462ef1..95a3e61 100644
--- a/doc/release-notes.html
+++ b/doc/release-notes.html
@@ -75,6 +75,7 @@ List of changes since Ivy 2.4.0:
 - FIX: Delay the processing of configured cache ttls, until the IvySettings object is usable (IVY-1495) (Thanks to Jaikiran Pai)
 - FIX: Including optional ivysettings of type 'file' doesn't work when file doesn't exist (IVY-1555) (Thanks to Jaikiran Pai)
 - FIX: Makepom ignores dependency classifiers (IVY-1528) (Thanks to Jaikiran Pai)
+- FIX: Infinite loop in dependencytree (IVY-1540) (Thanks to Jaikiran Pai)
 
 - IMPROVEMENT: Throw an IllegalStateException when retrieving the resolutionCacheRoot on the DefaultResolutionCacheManager if the basedir (or IvySettings) is not set (IVY-1482)
 - IMPROVEMENT: Optimization: limit the revision numbers scanned if revision prefix is specified (Thanks to Ernestas Vaiciukevi&#269;ius)