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 | * <echoproperties> has a new srcfile attribute that can make it read | ||||
| properties files and output them instead of Ant's properties. | 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 | 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> | <code>endtoken</code> attributes to define what to match.</p> | ||||
| <p>Filtersets are used for doing | <p>Filtersets are used for doing | ||||
| replacements in tasks such as <code><copy></code>, etc.</p> | 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> | <H2>Filterset</H2> | ||||
| @@ -75,6 +75,7 @@ import org.apache.tools.ant.Project; | |||||
| * A filter set may have begintoken and endtokens defined. | * A filter set may have begintoken and endtokens defined. | ||||
| * | * | ||||
| * @author <A href="mailto:gholam@xtra.co.nz"> Michael McCallum </A> | * @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 { | public class FilterSet extends DataType implements Cloneable { | ||||
| @@ -354,6 +355,10 @@ public class FilterSet extends DataType implements Cloneable { | |||||
| b.append(line.substring(i, index)); | b.append(line.substring(i, index)); | ||||
| if (tokens.containsKey(token)) { | if (tokens.containsKey(token)) { | ||||
| value = (String) tokens.get(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 | log("Replacing: " + beginToken + token + endToken | ||||
| + " -> " + value, Project.MSG_VERBOSE); | + " -> " + value, Project.MSG_VERBOSE); | ||||
| b.append(value); | 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 | * Create a new filter | ||||
| * | * | ||||
| @@ -67,6 +67,7 @@ import java.io.*; | |||||
| * FilterSet testing | * FilterSet testing | ||||
| * | * | ||||
| * @author Conor MacNeill | * @author Conor MacNeill | ||||
| * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a> | |||||
| */ | */ | ||||
| public class FilterSetTest extends BuildFileTest { | public class FilterSetTest extends BuildFileTest { | ||||
| @@ -102,6 +103,42 @@ public class FilterSetTest extends BuildFileTest { | |||||
| "src/etc/testcases/types/dest3.txt")); | "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) { | private boolean compareFiles(String name1, String name2) { | ||||
| File file1 = new File(name1); | File file1 = new File(name1); | ||||
| File file2 = new File(name2); | File file2 = new File(name2); | ||||