Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 788A8200CA3 for ; Thu, 1 Jun 2017 14:11:22 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 77787160BC4; Thu, 1 Jun 2017 12:11:22 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 73511160BB5 for ; Thu, 1 Jun 2017 14:11:21 +0200 (CEST) Received: (qmail 83130 invoked by uid 500); 1 Jun 2017 12:11:20 -0000 Mailing-List: contact notifications-help@ant.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ant.apache.org Delivered-To: mailing list notifications@ant.apache.org Received: (qmail 83121 invoked by uid 99); 1 Jun 2017 12:11:20 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Jun 2017 12:11:20 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 76C4EDFAF5; Thu, 1 Jun 2017 12:11:20 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: hibou@apache.org To: notifications@ant.apache.org Date: Thu, 01 Jun 2017 12:11:20 -0000 Message-Id: <4afa9c4e8bd543fd82b873ad61c1dbf6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [1/3] ant-ivy git commit: IVY-1540 Fix infinite loop in dependencytree, caused to due circular dependencies (coming in via Maven module descriptors) archived-at: Thu, 01 Jun 2017 12:11:22 -0000 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 Authored: Tue May 23 13:45:39 2017 +0530 Committer: Jaikiran Pai 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/* > */dependencies = new HashMap/* - * > - */(); + private final Map> dependencies = new HashMap>(); 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 dependencyList = dependencies.get(mrid); if (dependencyList != null) { - printDependencies(dependencyList, 0); + printDependencies(mrid, dependencyList, 0, new HashSet()); } } - private void printDependencies(List/* */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 dependencyList, final int indent, + final Set ancestors) { + for (final Iterator iterator = dependencyList.iterator(); iterator.hasNext();) { + final Set 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(); 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 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/* */()); + dependencies.put(moduleRevisionId, new ArrayList()); } } - private void addDependency(ModuleRevisionId moduleRevisionId, IvyNode dependency) { + private void addDependency(final ModuleRevisionId moduleRevisionId, final IvyNode dependency) { registerNodeIfNecessary(moduleRevisionId); - List/* */list = (List) dependencies.get(moduleRevisionId); - list.add(dependency); + final List 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 IVY-1540 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 @@ + + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + 4.0.0 + org.circular + module1 + Test Module for Ivy tests + 1.0 + + + + org.circular + module2 + 2.0 + + + + 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 @@ + + + + 4.0.0 + org.circular + module2 + Test Module for Ivy tests + 2.0 + + + + org.circular + module1 + 1.0 + + + +