git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275731 13f79535-47bb-0310-9956-ffa450edef68master
@@ -817,10 +817,10 @@ | |||||
<macrodef name="optional-jar"> | <macrodef name="optional-jar"> | ||||
<attribute name="dep"/> | <attribute name="dep"/> | ||||
<sequential> | <sequential> | ||||
<jar destfile="${build.lib}/${optional.jars.prefix}-${dep}.jar" | |||||
<jar destfile="${build.lib}/${optional.jars.prefix}-@{dep}.jar" | |||||
basedir="${build.classes}" | basedir="${build.classes}" | ||||
manifest="${manifest.tmp}"> | manifest="${manifest.tmp}"> | ||||
<selector refid="needs.${dep}"/> | |||||
<selector refid="needs.@{dep}"/> | |||||
</jar> | </jar> | ||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
@@ -3,6 +3,11 @@ | |||||
<head> | <head> | ||||
<meta http-equiv="Content-Language" content="en-us"></meta> | <meta http-equiv="Content-Language" content="en-us"></meta> | ||||
<title>MacroDef Task</title> | <title>MacroDef Task</title> | ||||
<style type="text/css"> | |||||
<!-- | |||||
.code { background: #EFEFEF; margin-top: } | |||||
--> | |||||
</style> | |||||
</head> | </head> | ||||
<body> | <body> | ||||
@@ -49,8 +54,12 @@ | |||||
</p> | </p> | ||||
<p> | <p> | ||||
This attribute is placed in the body of the templated | This attribute is placed in the body of the templated | ||||
task using the ant property notation - ${attribute name}. | |||||
Note that is not an actual ant property. | |||||
task using a notation similar to the ant property notation | |||||
- @{attribute name}. (May be remembered as "put the substitution | |||||
AT this location"). | |||||
The escape sequence @@{x} is used to allow @{x} to be | |||||
placed in the text without substitution of x. | |||||
This corresponds to the $${x} escape sequence for properties | |||||
</p> | </p> | ||||
<h3>Parameters</h3> | <h3>Parameters</h3> | ||||
<table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
@@ -107,12 +116,12 @@ | |||||
runs it. | runs it. | ||||
</p> | </p> | ||||
<blockquote> | <blockquote> | ||||
<pre> | |||||
<pre class=code> | |||||
<macrodef name="testing"> | <macrodef name="testing"> | ||||
<attribute name="v" default="NOT SET"/> | <attribute name="v" default="NOT SET"/> | ||||
<element name="some-tasks" optional="yes"/> | <element name="some-tasks" optional="yes"/> | ||||
<sequential> | <sequential> | ||||
<echo>v is ${v}</echo> | |||||
<echo>v is @{v}</echo> | |||||
<some-tasks/> | <some-tasks/> | ||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
@@ -122,7 +131,7 @@ | |||||
<echo>this is a test</echo> | <echo>this is a test</echo> | ||||
</some-tasks> | </some-tasks> | ||||
</testing> | </testing> | ||||
</pre> | |||||
</pre> | |||||
</blockquote> | </blockquote> | ||||
<p> | <p> | ||||
The following fragment defines a task called <call-cc> which | The following fragment defines a task called <call-cc> which | ||||
@@ -132,29 +141,29 @@ | |||||
<a href="http://ant-contrib.sourceforge.net/">ant-contrib</a> project. | <a href="http://ant-contrib.sourceforge.net/">ant-contrib</a> project. | ||||
</p> | </p> | ||||
<blockquote> | <blockquote> | ||||
<pre> | |||||
<pre class="code"> | |||||
<macrodef name="call-cc"> | <macrodef name="call-cc"> | ||||
<attribute name="target"/> | <attribute name="target"/> | ||||
<attribute name="link"/> | <attribute name="link"/> | ||||
<attribute name="target.dir"/> | <attribute name="target.dir"/> | ||||
<element name="cc-elements"/> | <element name="cc-elements"/> | ||||
<sequential> | <sequential> | ||||
<mkdir dir="${obj.dir}/${target}"/> | |||||
<mkdir dir="${target.dir}"/> | |||||
<cc link="${link}" objdir="${obj.dir}/${target}" | |||||
outfile="${target.dir}/${target}"> | |||||
<mkdir dir="${obj.dir}/@{target}"/> | |||||
<mkdir dir="@{target.dir}"/> | |||||
<cc link="@{link}" objdir="${obj.dir}/@{target}" | |||||
outfile="@{target.dir}/@{target}"> | |||||
<compiler refid="compiler.options"/> | <compiler refid="compiler.options"/> | ||||
<cc-elements/> | <cc-elements/> | ||||
</cc> | </cc> | ||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
</pre> | |||||
</pre> | |||||
</blockquote> | </blockquote> | ||||
<p> | <p> | ||||
This then can be used as follows: | This then can be used as follows: | ||||
</p> | </p> | ||||
<blockquote> | <blockquote> | ||||
<pre> | |||||
<pre class="code"> | |||||
<call-cc target="unittests" link="executable" | <call-cc target="unittests" link="executable" | ||||
target.dir="${build.bin.dir}"> | target.dir="${build.bin.dir}"> | ||||
<cc-elements> | <cc-elements> | ||||
@@ -165,7 +174,7 @@ | |||||
<linker refid="linker-libs"/> | <linker refid="linker-libs"/> | ||||
</cc-elements> | </cc-elements> | ||||
</call-cc> | </call-cc> | ||||
</pre> | |||||
</pre> | |||||
</blockquote> | </blockquote> | ||||
<hr> | <hr> | ||||
<p align="center">Copyright © 2003 Apache Software | <p align="center">Copyright © 2003 Apache Software | ||||
@@ -89,7 +89,7 @@ | |||||
<attribute name="dir"/> | <attribute name="dir"/> | ||||
<sequential> | <sequential> | ||||
<antcontrib:shellscript shell="bash"> <!-- HERE --> | <antcontrib:shellscript shell="bash"> <!-- HERE --> | ||||
ls -Rl ${dir} | |||||
ls -Rl @{dir} | |||||
</antcontrib:shellscript> | </antcontrib:shellscript> | ||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
@@ -132,7 +132,7 @@ | |||||
<element name="do"/> | <element name="do"/> | ||||
<sequential> | <sequential> | ||||
<current:if> | <current:if> | ||||
<current:isallowed test="${action}"/> | |||||
<current:isallowed test="@{action}"/> | |||||
<current:then> | <current:then> | ||||
<current:do/> | <current:do/> | ||||
</current:then> | </current:then> | ||||
@@ -4,7 +4,7 @@ | |||||
<macrodef name="my.echo"> | <macrodef name="my.echo"> | ||||
<attribute name="text"/> | <attribute name="text"/> | ||||
<sequential> | <sequential> | ||||
<echo message="${text}"/> | |||||
<echo message="@{text}"/> | |||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
<my.echo text="Hello World"/> | <my.echo text="Hello World"/> | ||||
@@ -14,7 +14,7 @@ | |||||
<macrodef name="my.echo"> | <macrodef name="my.echo"> | ||||
<attribute name="text"/> | <attribute name="text"/> | ||||
<sequential> | <sequential> | ||||
<echo>${text}</echo> | |||||
<echo>@{text}</echo> | |||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
<my.echo text="Inner Text"/> | <my.echo text="Inner Text"/> | ||||
@@ -25,7 +25,7 @@ | |||||
<attribute name="text"/> | <attribute name="text"/> | ||||
<attribute name="text"/> | <attribute name="text"/> | ||||
<sequential> | <sequential> | ||||
<echo>${text}</echo> | |||||
<echo>@{text}</echo> | |||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
</target> | </target> | ||||
@@ -44,7 +44,7 @@ | |||||
<macrodef name="echo" uri="abc"> | <macrodef name="echo" uri="abc"> | ||||
<attribute name="text"/> | <attribute name="text"/> | ||||
<sequential> | <sequential> | ||||
<echo message="${text}"/> | |||||
<echo message="@{text}"/> | |||||
</sequential> | </sequential> | ||||
</macrodef> | </macrodef> | ||||
<x:echo xmlns:x="abc" text="Hello World"/> | <x:echo xmlns:x="abc" text="Hello World"/> | ||||
@@ -65,4 +65,14 @@ | |||||
</nested> | </nested> | ||||
</target> | </target> | ||||
<target name="double"> | |||||
<macrodef name="double"> | |||||
<attribute name="prop"/> | |||||
<sequential> | |||||
<echo>@@{prop} is '@{prop}', value of $${@{prop}} is '${@{prop}}'</echo> | |||||
</sequential> | |||||
</macrodef> | |||||
<property name="property" value="A property value"/> | |||||
<double prop="property"/> | |||||
</target> | |||||
</project> | </project> |
@@ -78,8 +78,8 @@ import org.apache.tools.ant.UnknownElement; | |||||
public class MacroDef extends AntlibDefinition { | public class MacroDef extends AntlibDefinition { | ||||
private NestedSequential nestedSequential; | private NestedSequential nestedSequential; | ||||
private String name; | private String name; | ||||
private Map attributes = new HashMap(); | |||||
private Map elements = new HashMap(); | |||||
private List attributes = new ArrayList(); | |||||
private Map elements = new HashMap(); | |||||
/** | /** | ||||
* Name of the definition | * Name of the definition | ||||
@@ -170,7 +170,7 @@ public class MacroDef extends AntlibDefinition { | |||||
/** | /** | ||||
* @return the nested Attributes | * @return the nested Attributes | ||||
*/ | */ | ||||
public Map getAttributes() { | |||||
public List getAttributes() { | |||||
return attributes; | return attributes; | ||||
} | } | ||||
@@ -221,12 +221,15 @@ public class MacroDef extends AntlibDefinition { | |||||
throw new BuildException( | throw new BuildException( | ||||
"the attribute nested element needed a \"name\" attribute"); | "the attribute nested element needed a \"name\" attribute"); | ||||
} | } | ||||
if (attributes.get(attribute.getName()) != null) { | |||||
throw new BuildException( | |||||
"the attribute " + attribute.getName() | |||||
+ " has already been specified"); | |||||
for (int i = 0; i < attributes.size(); ++i) { | |||||
if (((Attribute) attributes.get(i)).getName().equals( | |||||
attribute.getName())) { | |||||
throw new BuildException( | |||||
"the attribute " + attribute.getName() | |||||
+ " has already been specified"); | |||||
} | |||||
} | } | ||||
attributes.put(attribute.getName(), attribute); | |||||
attributes.add(attribute); | |||||
} | } | ||||
/** | /** | ||||
@@ -347,6 +350,13 @@ public class MacroDef extends AntlibDefinition { | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | |||||
* @return a hash code value for this object. | |||||
*/ | |||||
public int hashCode() { | |||||
return objectHashCode(defaultValue) + objectHashCode(name); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -416,6 +426,13 @@ public class MacroDef extends AntlibDefinition { | |||||
} | } | ||||
return optional == other.optional; | return optional == other.optional; | ||||
} | } | ||||
/** | |||||
* @return a hash code value for this object. | |||||
*/ | |||||
public int hashCode() { | |||||
return objectHashCode(name) + (optional ? 1 : 0); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -463,6 +480,17 @@ public class MacroDef extends AntlibDefinition { | |||||
return true; | return true; | ||||
} | } | ||||
/** | |||||
* @return a hash code value for this object. | |||||
*/ | |||||
public int hashCode() { | |||||
return objectHashCode(name) | |||||
+ objectHashCode(getURI()) | |||||
+ objectHashCode(nestedSequential) | |||||
+ objectHashCode(attributes) | |||||
+ objectHashCode(elements); | |||||
} | |||||
/** | /** | ||||
* extends AntTypeDefinition, on create | * extends AntTypeDefinition, on create | ||||
* of the object, the template macro definition | * of the object, the template macro definition | ||||
@@ -526,4 +554,12 @@ public class MacroDef extends AntlibDefinition { | |||||
return macroDef.equals(otherDef.macroDef); | return macroDef.equals(otherDef.macroDef); | ||||
} | } | ||||
} | } | ||||
private static int objectHashCode(Object o) { | |||||
if (o == null) { | |||||
return 0; | |||||
} else { | |||||
return o.hashCode(); | |||||
} | |||||
} | |||||
} | } |
@@ -87,7 +87,6 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
private Map nsElements = null; | private Map nsElements = null; | ||||
private Map presentElements = new HashMap(); | private Map presentElements = new HashMap(); | ||||
private Hashtable localProperties = new Hashtable(); | private Hashtable localProperties = new Hashtable(); | ||||
/** | /** | ||||
* Called from MacroDef.MyAntTypeDefinition#create() | * Called from MacroDef.MyAntTypeDefinition#create() | ||||
@@ -142,7 +141,7 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
} | } | ||||
return nsElements; | return nsElements; | ||||
} | } | ||||
/** | /** | ||||
* Embedded element in macro instance | * Embedded element in macro instance | ||||
*/ | */ | ||||
@@ -166,11 +165,15 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
} | } | ||||
} | } | ||||
private static final int STATE_NORMAL = 0; | |||||
private static final int STATE_NORMAL = 0; | |||||
private static final int STATE_EXPECT_BRACKET = 1; | private static final int STATE_EXPECT_BRACKET = 1; | ||||
private static final int STATE_EXPECT_NAME = 2; | |||||
private static final int STATE_EXPECT_NAME = 2; | |||||
private static final int STATE_EXPECT_EXCAPE = 3; | |||||
private String macroSubs(String s, Map macroMapping) { | private String macroSubs(String s, Map macroMapping) { | ||||
if (s == null) { | |||||
return null; | |||||
} | |||||
StringBuffer ret = new StringBuffer(); | StringBuffer ret = new StringBuffer(); | ||||
StringBuffer macroName = null; | StringBuffer macroName = null; | ||||
boolean inMacro = false; | boolean inMacro = false; | ||||
@@ -179,48 +182,67 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
char ch = s.charAt(i); | char ch = s.charAt(i); | ||||
switch (state) { | switch (state) { | ||||
case STATE_NORMAL: | case STATE_NORMAL: | ||||
if (ch == '$') { | |||||
state = 1; | |||||
if (ch == '@') { | |||||
state = STATE_EXPECT_BRACKET; | |||||
} else { | } else { | ||||
ret.append(ch); | ret.append(ch); | ||||
} | |||||
} | |||||
break; | break; | ||||
case STATE_EXPECT_BRACKET: | case STATE_EXPECT_BRACKET: | ||||
if (ch == '{') { | if (ch == '{') { | ||||
state = 2; | |||||
state = STATE_EXPECT_NAME; | |||||
macroName = new StringBuffer(); | macroName = new StringBuffer(); | ||||
} else if (ch == '@') { | |||||
state = STATE_EXPECT_EXCAPE; | |||||
} else { | } else { | ||||
state = 0; | |||||
ret.append('$'); | |||||
state = STATE_NORMAL; | |||||
ret.append('@'); | |||||
ret.append(ch); | ret.append(ch); | ||||
} | } | ||||
break; | break; | ||||
case STATE_EXPECT_NAME: | case STATE_EXPECT_NAME: | ||||
if (ch == '}') { | if (ch == '}') { | ||||
state = 0; | |||||
state = STATE_NORMAL; | |||||
String name = macroName.toString(); | String name = macroName.toString(); | ||||
String value = (String) macroMapping.get(name); | String value = (String) macroMapping.get(name); | ||||
if (value == null) { | if (value == null) { | ||||
ret.append("${" + name + "}"); | |||||
ret.append("@{" + name + "}"); | |||||
} else { | } else { | ||||
ret.append(value); | ret.append(value); | ||||
} | } | ||||
macroName = null; | macroName = null; | ||||
} else { | } else { | ||||
macroName.append(s.charAt(i)); | |||||
macroName.append(ch); | |||||
} | |||||
break; | |||||
case STATE_EXPECT_EXCAPE: | |||||
state = STATE_NORMAL; | |||||
if (ch == '{') { | |||||
ret.append("@"); | |||||
} else { | |||||
ret.append("@@"); | |||||
} | } | ||||
ret.append(ch); | |||||
break; | |||||
default: | |||||
break; | |||||
} | } | ||||
} | } | ||||
switch (state) { | switch (state) { | ||||
case STATE_NORMAL: | case STATE_NORMAL: | ||||
break; | break; | ||||
case STATE_EXPECT_BRACKET: | case STATE_EXPECT_BRACKET: | ||||
ret.append('$'); | |||||
ret.append('@'); | |||||
break; | break; | ||||
case STATE_EXPECT_NAME: | case STATE_EXPECT_NAME: | ||||
ret.append("${"); | |||||
ret.append("@{"); | |||||
ret.append(macroName.toString()); | ret.append(macroName.toString()); | ||||
break; | break; | ||||
case STATE_EXPECT_EXCAPE: | |||||
ret.append("@@"); | |||||
break; | |||||
default: | |||||
break; | |||||
} | } | ||||
return ret.toString(); | return ret.toString(); | ||||
@@ -294,12 +316,12 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
public void execute() { | public void execute() { | ||||
localProperties = new Hashtable(); | localProperties = new Hashtable(); | ||||
Set copyKeys = new HashSet(map.keySet()); | Set copyKeys = new HashSet(map.keySet()); | ||||
for (Iterator i = macroDef.getAttributes().values().iterator(); | |||||
i.hasNext();) { | |||||
for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) { | |||||
MacroDef.Attribute attribute = (MacroDef.Attribute) i.next(); | MacroDef.Attribute attribute = (MacroDef.Attribute) i.next(); | ||||
String value = (String) map.get(attribute.getName()); | String value = (String) map.get(attribute.getName()); | ||||
if (value == null) { | if (value == null) { | ||||
value = attribute.getDefault(); | value = attribute.getDefault(); | ||||
value = macroSubs(value, localProperties); | |||||
} | } | ||||
if (value == null) { | if (value == null) { | ||||
throw new BuildException( | throw new BuildException( | ||||
@@ -98,5 +98,10 @@ public class MacroDefTest extends BuildFileTest { | |||||
expectLog("nested", "A nested element"); | expectLog("nested", "A nested element"); | ||||
} | } | ||||
public void testDouble() { | |||||
expectLog( | |||||
"double", | |||||
"@{prop} is 'property', value of ${property} is 'A property value'"); | |||||
} | |||||
} | } | ||||