diff --git a/CHANGES.txt b/CHANGES.txt index 1f4b4715..1985a176 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,4 @@ +- FIX: raise a clean error when a cyclic variable definition is found (IVY-75) - FIX: reinitiliase ant project instance at each new task to avoid using a bad ant project instance in some ide (like netbeans) (IVY-87) - FIX: ivy is now able to use simple ivy files in cache (doesn't need resolver info, use default one if no resolver is given) (IVY-86) - FIX: private conf not accessible from other modules (IVY-76) diff --git a/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java b/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java index 8d6a85c1..63008d2e 100644 --- a/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java +++ b/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java @@ -5,8 +5,11 @@ */ package fr.jayasoft.ivy.util; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -83,11 +86,15 @@ public class IvyPatternHelper { } public static String substituteVariables(String pattern, Map variables) { - // if you supply null, null is what you get - if (pattern == null) { - return null; - } - + return substituteVariables(pattern, variables, new Stack()); + } + + private static String substituteVariables(String pattern, Map variables, Stack substituting) { + // if you supply null, null is what you get + if (pattern == null) { + return null; + } + Matcher m = VAR_PATTERN.matcher(pattern); StringBuffer sb = new StringBuffer(); @@ -95,7 +102,15 @@ public class IvyPatternHelper { String var = m.group(1); String val = (String)variables.get(var); if (val != null) { - val = substituteVariables(val, variables); + int index; + if ((index = substituting.indexOf(var)) != -1) { + List cycle = new ArrayList(substituting.subList(index, substituting.size())); + cycle.add(var); + throw new IllegalArgumentException("cyclic variable definition: cycle = "+cycle); + } + substituting.push(var); + val = substituteVariables(val, variables, substituting); + substituting.pop(); } else { val = m.group(); } diff --git a/test/java/fr/jayasoft/ivy/util/IvyPatternHelperTest.java b/test/java/fr/jayasoft/ivy/util/IvyPatternHelperTest.java index 2196b801..4b2f1291 100644 --- a/test/java/fr/jayasoft/ivy/util/IvyPatternHelperTest.java +++ b/test/java/fr/jayasoft/ivy/util/IvyPatternHelperTest.java @@ -6,6 +6,9 @@ */ package fr.jayasoft.ivy.util; +import java.util.HashMap; +import java.util.Map; + import junit.framework.TestCase; public class IvyPatternHelperTest extends TestCase { @@ -16,6 +19,21 @@ public class IvyPatternHelperTest extends TestCase { IvyPatternHelper.substitute(pattern, "jayasoft", "Test", "1.0", "test", "jar", "jar")); } + public void testCyclicSubstitute() { + String pattern = "${var}"; + Map variables = new HashMap(); + variables.put("var", "${othervar}"); + variables.put("othervar", "${var}"); + try { + IvyPatternHelper.substituteVariables(pattern, variables); + fail("cyclic var should raise an exception"); + } catch (Exception ex) { + // ok + } catch (Error er) { + fail("cyclic var shouldn't raise an error: "+er); + } + } + public void testOrganization() { String pattern = "[organization]/[module]/build/archives/[type]s/[artifact]-[revision].[ext]"; assertEquals(