You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ja...@apache.org on 2018/02/09 03:50:06 UTC

ant-ivy git commit: IVY-1545: Added tracking for a cycle in parent-POM ancestry, throw a CircularDependencyException if found. Added tests for cycles in parent ancestry and references-self as parent.

Repository: ant-ivy
Updated Branches:
  refs/heads/master 55e6b039a -> 537e13241


IVY-1545: Added tracking for a cycle in parent-POM ancestry, throw a CircularDependencyException if found.
Added tests for cycles in parent ancestry and references-self as parent.

This closes #66 pull request at github/apache/ant-ivy repo


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

Branch: refs/heads/master
Commit: 537e13241a7ffd99e5a3676e574e3cd9ea9aae03
Parents: 55e6b03
Author: Brett Randall <ja...@gmail.com>
Authored: Fri Mar 25 20:55:15 2016 +1100
Committer: Jaikiran Pai <ja...@apache.org>
Committed: Fri Feb 9 09:17:56 2018 +0530

----------------------------------------------------------------------
 asciidoc/release-notes.adoc                     |  1 +
 .../circular/CircularDependencyException.java   | 12 +++++-
 .../parser/m2/PomModuleDescriptorParser.java    | 40 +++++++++++++++---
 .../apache/ivy/core/resolve/ResolveTest.java    | 43 ++++++++++++++++++++
 .../org/apache/dm/parent4/1.0/parent4-1.0.pom   | 36 ++++++++++++++++
 .../org/apache/dm/parent5/1.0/parent5-1.0.pom   | 36 ++++++++++++++++
 .../org/apache/dm/test6/1.0/test6-1.0.jar       |  1 +
 .../org/apache/dm/test6/1.0/test6-1.0.pom       | 37 +++++++++++++++++
 .../org/apache/dm/test7/1.0/test7-1.0.jar       |  1 +
 .../org/apache/dm/test7/1.0/test7-1.0.pom       | 37 +++++++++++++++++
 10 files changed, 237 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/asciidoc/release-notes.adoc
----------------------------------------------------------------------
diff --git a/asciidoc/release-notes.adoc b/asciidoc/release-notes.adoc
index 38ca44b..986b153 100644
--- a/asciidoc/release-notes.adoc
+++ b/asciidoc/release-notes.adoc
@@ -74,6 +74,7 @@ For details about the following changes, check our JIRA install at link:https://
 - FIX: ApacheURLLister skips versions with URL encoded characters [jira:IVY-1442[]] [jira:IVY-1573[]]
 - FIX: Configuration lists are sensitive to whitespace; multiple split/merge methods [jira:IVY-309[]] [jira:IVY-1282[]]
 - FIX: Warnings about illegal reflection access due to lack of methods to retrieve default authenticator in Java 5 to 8 [jira:IVY-1569[]]
+- FIX: Cycle in parent POM ancestry yields StackOverflowError in PomModuleDescriptorParser [jira:IVY-1545] (Thanks to Brett Randall)
 
 - IMPROVEMENT: Throw an IllegalStateException when retrieving the resolutionCacheRoot on the DefaultResolutionCacheManager if the basedir (or IvySettings) is not set (jira:IVY-1482[])
 - IMPROVEMENT: Optimization: limit the revision numbers scanned if revision prefix is specified (Thanks to Ernestas Vaiciukevi&#269;ius)

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/src/java/org/apache/ivy/plugins/circular/CircularDependencyException.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/plugins/circular/CircularDependencyException.java b/src/java/org/apache/ivy/plugins/circular/CircularDependencyException.java
index 438c572..788b994 100644
--- a/src/java/org/apache/ivy/plugins/circular/CircularDependencyException.java
+++ b/src/java/org/apache/ivy/plugins/circular/CircularDependencyException.java
@@ -17,15 +17,21 @@
  */
 package org.apache.ivy.plugins.circular;
 
+import java.util.Collection;
+
 import org.apache.ivy.core.module.id.ModuleRevisionId;
 
 /**
  * Unchecked exception thrown when a circular dependency exists between projects.
  */
 
-@SuppressWarnings("serial")
 public class CircularDependencyException extends RuntimeException {
 
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 670272039106237360L;
+
     private ModuleRevisionId[] mrids;
 
     /**
@@ -37,6 +43,10 @@ public class CircularDependencyException extends RuntimeException {
         this.mrids = mrids;
     }
 
+    public CircularDependencyException(final Collection<ModuleRevisionId> mrids) {
+        this(mrids.toArray(new ModuleRevisionId[mrids.size()]));
+    }
+
     public ModuleRevisionId[] getPath() {
         return this.mrids;
     }

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java b/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java
index 01b3509..b1c0b7f 100644
--- a/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java
+++ b/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java
@@ -23,8 +23,11 @@ import java.io.InputStream;
 import java.net.URL;
 import java.text.ParseException;
 import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Map;
 
+import org.apache.ivy.core.IvyContext;
 import org.apache.ivy.core.cache.ArtifactOrigin;
 import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.Configuration;
@@ -38,6 +41,7 @@ import org.apache.ivy.core.resolve.ResolveData;
 import org.apache.ivy.core.resolve.ResolveEngine;
 import org.apache.ivy.core.resolve.ResolveOptions;
 import org.apache.ivy.core.resolve.ResolvedModuleRevision;
+import org.apache.ivy.plugins.circular.CircularDependencyException;
 import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
 import org.apache.ivy.plugins.parser.ParserSettings;
 import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder.PomDependencyDescriptor;
@@ -52,7 +56,6 @@ import org.apache.ivy.plugins.resolver.DependencyResolver;
 import org.apache.ivy.util.Message;
 import org.xml.sax.SAXException;
 
-import static org.apache.ivy.core.IvyContext.getContext;
 import static org.apache.ivy.core.module.descriptor.Configuration.Visibility.PUBLIC;
 import static org.apache.ivy.plugins.namespace.NameSpaceHelper.toSystem;
 import static org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder.MAVEN2_CONFIGURATIONS;
@@ -63,9 +66,9 @@ import static org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder.getPlu
 /**
  * A parser for Maven 2 POM.
  * <p>
- * The configurations used in the generated module descriptor mimics the behavior defined by
- * Maven 2 scopes, as documented
- * <a href="http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">here</a>.
+ * The configurations used in the generated module descriptor mimics the behavior defined by Maven 2
+ * scopes, as documented <a href=
+ * "http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">here</a>.
  * The PomModuleDescriptorParser use a PomDomReader to read the pom, and the
  * PomModuleDescriptorBuilder to write the ivy module descriptor using the info read by the
  * PomDomReader.
@@ -75,6 +78,8 @@ public final class PomModuleDescriptorParser implements ModuleDescriptorParser {
 
     private static final PomModuleDescriptorParser INSTANCE = new PomModuleDescriptorParser();
 
+    private static final String PARENT_MAP_KEY = PomModuleDescriptorParser.class.getName() + ".parentMap";
+    
     public static PomModuleDescriptorParser getInstance() {
         return INSTANCE;
     }
@@ -123,12 +128,25 @@ public final class PomModuleDescriptorParser implements ModuleDescriptorParser {
                 ivySettings);
 
         try {
+            final IvyContext ivyContext = IvyContext.pushNewCopyContext();
+            @SuppressWarnings("unchecked")
+            HashSet<ModuleRevisionId> parents = (HashSet<ModuleRevisionId>) ivyContext
+                    .get(PARENT_MAP_KEY);
+            if (parents == null) {
+                parents = new LinkedHashSet<ModuleRevisionId>();
+                ivyContext.set(PARENT_MAP_KEY, parents);
+            }
+
             PomReader domReader = new PomReader(descriptorURL, res);
             domReader.setProperty("parent.version", domReader.getParentVersion());
             domReader.setProperty("parent.groupId", domReader.getParentGroupId());
             domReader.setProperty("project.parent.version", domReader.getParentVersion());
             domReader.setProperty("project.parent.groupId", domReader.getParentGroupId());
 
+            Message.debug("parent.groupId: " + domReader.getParentGroupId());
+            Message.debug("parent.artifactId: " + domReader.getParentArtifactId());
+            Message.debug("parent.version: " + domReader.getParentVersion());
+
             for (Map.Entry<String, String> prop : domReader.getPomProperties().entrySet()) {
                 domReader.setProperty(prop.getKey(), prop.getValue());
                 mdBuilder.addProperty(prop.getKey(), prop.getValue());
@@ -141,6 +159,14 @@ public final class PomModuleDescriptorParser implements ModuleDescriptorParser {
                 ModuleRevisionId parentModRevID = ModuleRevisionId.newInstance(
                     domReader.getParentGroupId(), domReader.getParentArtifactId(),
                     domReader.getParentVersion());
+
+                // check for cycles
+                if (parents.contains(parentModRevID)) {
+                    throw new CircularDependencyException(parents);
+                } else {
+                    parents.add(parentModRevID);
+                }
+
                 ResolvedModuleRevision parentModule = parseOtherPom(ivySettings, parentModRevID);
                 if (parentModule == null) {
                     throw new IOException("Impossible to load parent for " + res.getName()
@@ -282,6 +308,8 @@ public final class PomModuleDescriptorParser implements ModuleDescriptorParser {
             }
         } catch (SAXException e) {
             throw newParserException(e);
+        } finally {
+            IvyContext.popContext();
         }
 
         return mdBuilder.getModuleDescriptor();
@@ -383,9 +411,9 @@ public final class PomModuleDescriptorParser implements ModuleDescriptorParser {
     private ResolvedModuleRevision parseOtherPom(ParserSettings ivySettings,
             ModuleRevisionId parentModRevID) throws ParseException {
         DependencyDescriptor dd = new DefaultDependencyDescriptor(parentModRevID, true);
-        ResolveData data = getContext().getResolveData();
+        ResolveData data = IvyContext.getContext().getResolveData();
         if (data == null) {
-            ResolveEngine engine = getContext().getIvy().getResolveEngine();
+            ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine();
             ResolveOptions options = new ResolveOptions();
             options.setDownload(false);
             data = new ResolveData(engine, options);

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/java/org/apache/ivy/core/resolve/ResolveTest.java
----------------------------------------------------------------------
diff --git a/test/java/org/apache/ivy/core/resolve/ResolveTest.java b/test/java/org/apache/ivy/core/resolve/ResolveTest.java
index a41f91f..c3fe21a 100644
--- a/test/java/org/apache/ivy/core/resolve/ResolveTest.java
+++ b/test/java/org/apache/ivy/core/resolve/ResolveTest.java
@@ -79,6 +79,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  *
@@ -4921,6 +4922,48 @@ public class ResolveTest {
             "jar").exists());
     }
 
+    @Test
+    public void testErrorResolveMaven2ParentPomWithCycle() throws Exception {
+        // IVY-1545
+        // test6 has parent parent4, parent4 parent is parent5, parent5 parent is parent4, a cycle.
+        Ivy ivy = new Ivy();
+        ivy.configure(new File("test/repositories/parentPom/ivysettings.xml"));
+        ivy.getSettings().setDefaultResolver("parentChain");
+
+        try {
+            ivy.resolve(
+                new File("test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.pom"),
+                getResolveOptions(new String[] {"*"}));
+
+            // don't expect to get here, should suffer StackOverflowError if cycle is not detected
+            fail("Expected CircularDependencyException from parent cycle detection");
+        } catch (CircularDependencyException e) {
+            // ok
+            assertEquals("org.apache.dm#parent4;1.0->org.apache.dm#parent5;1.0", e.getMessage());
+        }
+    }
+
+    @Test
+    public void testErrorResolveMaven2SelfAsParent() throws Exception {
+        // IVY-1545
+        // test7 has parent == self
+        Ivy ivy = new Ivy();
+        ivy.configure(new File("test/repositories/parentPom/ivysettings.xml"));
+        ivy.getSettings().setDefaultResolver("parentChain");
+
+        try {
+            ivy.resolve(
+                new File("test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.pom"),
+                getResolveOptions(new String[] {"*"}));
+
+            // don't expect to get here, should suffer StackOverflowError if cycle is not detected
+            fail("Expected CircularDependencyException from parent cycle detection");
+        } catch (CircularDependencyException e) {
+            // ok
+            assertEquals("org.apache.dm#test7;1.0", e.getMessage());
+        }
+    }
+
     /**
      * Test case for IVY-1186.
      *

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/repositories/parentPom/org/apache/dm/parent4/1.0/parent4-1.0.pom
----------------------------------------------------------------------
diff --git a/test/repositories/parentPom/org/apache/dm/parent4/1.0/parent4-1.0.pom b/test/repositories/parentPom/org/apache/dm/parent4/1.0/parent4-1.0.pom
new file mode 100644
index 0000000..82a69f5
--- /dev/null
+++ b/test/repositories/parentPom/org/apache/dm/parent4/1.0/parent4-1.0.pom
@@ -0,0 +1,36 @@
+<?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>
+  <parent>
+    <artifactId>parent5</artifactId>
+    <groupId>org.apache.dm</groupId>
+    <version>1.0</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.dm</groupId>
+  <artifactId>parent4</artifactId>
+  <name>Test Module for Ivy M2 parsing - detects circular parent references</name>
+  <version>1.0</version>
+  <url>http://ivy.jayasoft.org/</url>
+  <organization>
+    <name>Jayasoft</name>
+    <url>http://www.jayasoft.org/</url>
+  </organization>
+</project>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/repositories/parentPom/org/apache/dm/parent5/1.0/parent5-1.0.pom
----------------------------------------------------------------------
diff --git a/test/repositories/parentPom/org/apache/dm/parent5/1.0/parent5-1.0.pom b/test/repositories/parentPom/org/apache/dm/parent5/1.0/parent5-1.0.pom
new file mode 100644
index 0000000..596a8f1
--- /dev/null
+++ b/test/repositories/parentPom/org/apache/dm/parent5/1.0/parent5-1.0.pom
@@ -0,0 +1,36 @@
+<?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>
+  <parent>
+    <artifactId>parent4</artifactId>
+    <groupId>org.apache.dm</groupId>
+    <version>1.0</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.dm</groupId>
+  <artifactId>parent5</artifactId>
+  <name>Test Module for Ivy M2 parsing - detects circular parent references</name>
+  <version>1.0</version>
+  <url>http://ivy.jayasoft.org/</url>
+  <organization>
+    <name>Jayasoft</name>
+    <url>http://www.jayasoft.org/</url>
+  </organization>
+</project>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.jar
----------------------------------------------------------------------
diff --git a/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.jar b/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.jar
new file mode 100644
index 0000000..56f3b36
--- /dev/null
+++ b/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.jar
@@ -0,0 +1 @@
+ 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.pom
----------------------------------------------------------------------
diff --git a/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.pom b/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.pom
new file mode 100644
index 0000000..35e1a3c
--- /dev/null
+++ b/test/repositories/parentPom/org/apache/dm/test6/1.0/test6-1.0.pom
@@ -0,0 +1,37 @@
+<?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>
+  <!-- has parent cycle parent4 -> parent5 -> parent4 ... -->
+  <parent>
+    <artifactId>parent4</artifactId>
+    <groupId>org.apache.dm</groupId>
+    <version>1.0</version>
+   </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.dm</groupId>
+  <artifactId>test6</artifactId>
+  <name>Test safe-failure of parent with dependency cycle</name>
+  <version>1.0</version>
+  <url>http://ivy.jayasoft.org/</url>
+  <organization>
+    <name>Jayasoft</name>
+    <url>http://www.jayasoft.org/</url>
+  </organization>
+</project>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.jar
----------------------------------------------------------------------
diff --git a/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.jar b/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.jar
new file mode 100644
index 0000000..56f3b36
--- /dev/null
+++ b/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.jar
@@ -0,0 +1 @@
+ 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/537e1324/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.pom
----------------------------------------------------------------------
diff --git a/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.pom b/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.pom
new file mode 100644
index 0000000..be74ee2
--- /dev/null
+++ b/test/repositories/parentPom/org/apache/dm/test7/1.0/test7-1.0.pom
@@ -0,0 +1,37 @@
+<?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>
+  <!-- illegal, references itself as parent -->
+  <parent>
+    <artifactId>test7</artifactId>
+    <groupId>org.apache.dm</groupId>
+    <version>1.0</version>
+   </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.dm</groupId>
+  <artifactId>test7</artifactId>
+  <name>Test safe-failure of references self as parent</name>
+  <version>1.0</version>
+  <url>http://ivy.jayasoft.org/</url>
+  <organization>
+    <name>Jayasoft</name>
+    <url>http://www.jayasoft.org/</url>
+  </organization>
+</project>