PR: 9378 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272867 13f79535-47bb-0310-9956-ffa450edef68master
@@ -9,6 +9,8 @@ Other changes: | |||
* <echoproperties> has a new srcfile attribute that can make it read | |||
properties files and output them instead of Ant's properties. | |||
* <filterset> will now resolve filters recursively. | |||
Changes from Ant 1.4.1 to Ant 1.5 | |||
================================= | |||
@@ -19,6 +19,7 @@ children of | |||
<code>endtoken</code> attributes to define what to match.</p> | |||
<p>Filtersets are used for doing | |||
replacements in tasks such as <code><copy></code>, etc.</p> | |||
<p>Nested filters are possible and a message will be given in case a value in a filter chain is called for a second time and thus causing an infinite loop. The originating token will be passed back when an infinite loop occurs. | |||
<H2>Filterset</H2> | |||
@@ -75,6 +75,7 @@ import org.apache.tools.ant.Project; | |||
* A filter set may have begintoken and endtokens defined. | |||
* | |||
* @author <A href="mailto:gholam@xtra.co.nz"> Michael McCallum </A> | |||
* @author <A href="mailto:martin@mvdb.net"> Martin van den Bemt </A> | |||
*/ | |||
public class FilterSet extends DataType implements Cloneable { | |||
@@ -354,6 +355,10 @@ public class FilterSet extends DataType implements Cloneable { | |||
b.append(line.substring(i, index)); | |||
if (tokens.containsKey(token)) { | |||
value = (String) tokens.get(token); | |||
if (!value.equals(token)) { | |||
// we have another token, let's parse it. | |||
value = replaceTokens(value, token); | |||
} | |||
log("Replacing: " + beginToken + token + endToken | |||
+ " -> " + value, Project.MSG_VERBOSE); | |||
b.append(value); | |||
@@ -376,6 +381,54 @@ public class FilterSet extends DataType implements Cloneable { | |||
} | |||
} | |||
/** Contains a list of parsed tokens */ | |||
private Vector passedTokens; | |||
/** if a ducplicate token is found, this is set to true */ | |||
private boolean duplicateToken = false; | |||
/** | |||
* This parses tokens which point to tokens. | |||
* It also maintains a list of currently used tokens, so we cannot | |||
* get into an infinite loop | |||
* @param value the value / token to parse | |||
* @param parent the parant token (= the token it was parsed from) | |||
*/ | |||
private String replaceTokens(String line, String parent) | |||
throws BuildException | |||
{ | |||
if (passedTokens == null) { | |||
passedTokens = new Vector(); | |||
} | |||
if (passedTokens.contains(parent) && !duplicateToken) { | |||
duplicateToken = true; | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("Inifinite loop in tokens. Currently known tokens : "); | |||
sb.append(passedTokens); | |||
sb.append("\nProblem token : "+getBeginToken()+parent+getEndToken()); | |||
sb.append(" called from "+getBeginToken()+passedTokens.lastElement()); | |||
sb.append(getEndToken()); | |||
System.out.println(sb.toString()); | |||
return parent; | |||
} | |||
passedTokens.addElement(parent); | |||
String value = this.replaceTokens(line); | |||
if (value.indexOf(getBeginToken()) == -1 && !duplicateToken) { | |||
duplicateToken = false; | |||
passedTokens = null; | |||
} else if(duplicateToken) { | |||
// should always be the case... | |||
if (passedTokens.size() > 0) { | |||
value = (String) passedTokens.lastElement(); | |||
passedTokens.removeElementAt(passedTokens.size()-1); | |||
if (passedTokens.size() == 0) { | |||
value = getBeginToken()+value+getEndToken(); | |||
duplicateToken = false; | |||
} | |||
} | |||
} | |||
return value; | |||
} | |||
/** | |||
* Create a new filter | |||
* | |||
@@ -67,6 +67,7 @@ import java.io.*; | |||
* FilterSet testing | |||
* | |||
* @author Conor MacNeill | |||
* @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a> | |||
*/ | |||
public class FilterSetTest extends BuildFileTest { | |||
@@ -102,6 +103,42 @@ public class FilterSetTest extends BuildFileTest { | |||
"src/etc/testcases/types/dest3.txt")); | |||
} | |||
/** | |||
* This will test the recursive FilterSet. Which means that if | |||
* the filter value @test@ contains another filter value, it will | |||
* actually resolve. | |||
*/ | |||
public void testRecursive() { | |||
System.out.println("testRecursive"); | |||
String result = "it works line"; | |||
String line="@test@ line"; | |||
FilterSet fs = new FilterSet(); | |||
fs.addFilter("test", "@test1@"); | |||
fs.addFilter("test1","@test2@"); | |||
fs.addFilter("test2", "it works"); | |||
fs.setBeginToken("@"); | |||
fs.setEndToken("@"); | |||
assertEquals(result, fs.replaceTokens(line)); | |||
} | |||
/** | |||
* Test to see what happens when the resolving occurs in an | |||
* infinite loop. | |||
*/ | |||
public void testInfinite() { | |||
System.out.println("testInfinite"); | |||
String result = "@test@ line testvalue"; | |||
String line = "@test@ line @test3@"; | |||
FilterSet fs = new FilterSet(); | |||
fs.addFilter("test", "@test1@"); | |||
fs.addFilter("test1","@test2@"); | |||
fs.addFilter("test2", "@test@"); | |||
fs.addFilter("test3", "testvalue"); | |||
fs.setBeginToken("@"); | |||
fs.setEndToken("@"); | |||
assertEquals(result, fs.replaceTokens(line)); | |||
} | |||
private boolean compareFiles(String name1, String name2) { | |||
File file1 = new File(name1); | |||
File file2 = new File(name2); | |||