Bug in ant macrodef - ant

I have a bug in the following ant macrodef definition:
<macrodef name="xxx" description="does xxx">
<attribute name="attr1" default=""/>
<sequential>
<echo message="doing yyy"/>
<echo message="#{attr1}" file="${builddir}/zzz.xml"/>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>
<xmltask report="true" source="${builddir}/zzz.xml">
<call path="spuds" target="process-spuds">
<param name="spud-kicker" path="#count"/>
</call>
</xmltask>
</sequential>
</macrodef>
When it tries to call the target of the call inside the xmltask, i get a null pointer exception.
What am I doing wrong?
The file zzz.xml contains (supposedly) well formed xml. It contains a top level tag called "spuds" with an attribute named count. I want to invoke the spud-kicker ant target on the spuds tag and pass the value of the count attribute to that task.

Related

Ant - String contains within an array of String

I am basically trying to do the following thing in Ant (v1.9.4):
I have a list of fixed string like {a,b,c,d} --> First how should I declare this in Ant?
Then I have an input parameter such as ${mystring} and I want to check if the variable value is in my list. Which means in this example, if the variable value is equals to a or b or c or d.
If so return true else false (or 0 and 1 something like that).
Is there a simple way to do that?
Thanks,
Thiago
Use ant property task to declare your stringlist.
Use ant contains condition to check whether list contains a specific item.
Something like :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- fail if 'foobaz' is missing -->
<fail message="foobaz not in List => [${csvprop}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</project>
Or wrap it in a macrodef for resuse :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<fail message="#{item} not in List => [#{list}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
-- EDIT --
From ant manual condition :
If the condition holds true, the property value is set to true by default; otherwise, the property is not set. You can set the value to something other than the default by specifying the value attribute.
So simply use a condition to create a property that is either true or not set, f.e. combined with the new if/unless feature introduced with Ant 1.9.1 :
<project
xmlns:if="ant:if"
xmlns:unless="ant:unless"
>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<condition property="itemfound">
<contains string="${csvprop}" substring="foobaz"/>
</condition>
<!-- echo as example only instead of
your real stuff -->
<echo if:true="${itemfound}">Item #{item} found => OK !!</echo>
<echo unless:true="${itemfound}">Warning => Item #{item} not found !!</echo>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
output :
[echo] Warning => Item foobaz not found !!
Note that you need the namespace declarations to activate the if/unless feature.

Macrodef in Ant : passing a value outside the definition

I have the following macro definition in Ant and I would like to pass the "cmdStatus" value outside this macro def:
<macrodef name="execEtlBinScript">
<attribute name="script" />
<sequential>
<exec executable="#{script}" resultproperty="cmdStatus"/>
</sequential>
</macrodef>
Do you have any idea if it is possible or not ?
Thank you for any help.
Kind regards,
foxrafi
In your exemple, the property cmdStatus is set and is then available outside the macrodef. But I guess that your issue is that if your call several times your macro, you don't get the next status values as properties in Ant are immutable.
The way to handle it properly is to make the result property an attribute of the macro:
<macrodef name="execEtlBinScript">
<attribute name="script" />
<attribute name="resultproperty" />
<sequential>
<exec executable="#{script}" resultproperty="#{resultproperty}"/>
</sequential>
</macrodef>
Then each call to the macrodef will get its value via a different property:
<execEtlBinScript script="somescript" resultproperty="status1" />
<echo message="Result of the first call: ${status1}" />
<execEtlBinScript script="somescript" resultproperty="status2" />
<echo message="Result of the second call: ${status2}" />

How to pass paramters by refrence in ant

Hi all this is my code for target calling.
<target name="abc">
<var name="x" value="10"/>
<antcall target="def"/>
<!--Again Access The value of x here and also change it here-->
</target>
<target name="def">
<!--Access The value of x here and also change it here-->
</target>
and also i want to access this X in other build file,is there any way
This is not possible with ant. In an properties are immutable and cannot be reset. The var task from ant contrib can be used to override values, but should be used sparingly.
You could use a temporary file to achieve what you want. But probably you are trying something weird, which can be solved in a different way.
This would also work across buildfiles if they have access to the property file.
<target name="abc">
<var name="x" value="10"/>
<antcall target="def"/>
<!--Again Access The value of x here and also change it here-->
<var unset="true" file="myproperty.properties" /> <!-- read variable from property file-->
</target>
<target name="def">
<echo file="myproperty.properties" append="false">x=12</echo> <!-- create a new propertyfile-->
</target>
For the sake of justice, there is a hack that allows to alter ant's immutable properties without any additional libs (since java 6):
<scriptdef name="propertyreset" language="javascript"
description="Allows to assing #{property} new value">
<attribute name="name"/>
<attribute name="value"/>
project.setProperty(attributes.get("name"), attributes.get("value"));
</scriptdef>
Usage:
<target name="abc">
<property name="x" value="10"/>
<antcall target="def"/>
</target>
<target name="def">
<propertyreset name="x" value="11"/>
</target>
As #oers mentioned, this should be used with care after all canonical approaches proved not to fit.
It is difficult to suggest further without knowing the goal behind the question.

Macrodef and "local properties"

I am trying to move a file (specified by a pattern) to a given location in an Ant macrodef:
<macrodef name="extract">
<attribute name="package"/>
<sequential>
<!-- the path will contain the unique file in extracted regardless of the name -->
<path id="source_refid">
<dirset dir="${dep}/lib/#{package}/extracted/">
<include name="#{package}-*"/>
</dirset>
</path>
<!-- this is not working: properties are immutable -->
<property name="source_name" refid="source_refid"/>
<move
file="${source_name}"
tofile="${dep}/#{package}/"
overwrite="true"
/>
</sequential>
</macrodef>
This will work just once as ${source_name} is immutable.
An option would be to use the variable task but I didn't find a way to assign a refid to a var.
Is there a way to have something similar to local variable in a macrodef? Or (XY problem) is there a better way to solve my problem?
Since Ant 1.8 you can use the local task for this. For example:
<local name="source_name"/>
<property name="source_name" refid="source_refid"/>
Your example is just the sort of thing local is for!

Default element for Ant's macrodef?

I would like to create a macro as such:
<macrodef name="testing">
<element name="test" implicit="yes"/>
<sequential>
<test/>
</sequential>
</macrodef>
And then use it:
<testing>
<echo message="hello world"/>
</testing>
However, I would like to specify a default for the implicit element... something like:
<macrodef name="testing">
<element name="test" implicit="yes">
<echo message="hello world"/>
</element>
<sequential>
<test/>
</sequential>
</macrodef>
So I can then use it as such:
<testing/>
Except where I want to change the default element.
Is this possible without defining a task via a Java class? So far, I don't see any documentation that indicates how to do it, if so.
Update
I ended up resolving my particular issue by using refid for filesets (which is what I actually was trying to pull into an element). Using the refid, it was simple to just use a macrodef attribute, which CAN have a default value.
Another alternative would be to create a new base macro which uses the element, and then I could have kept my existing macro as using that one... but still, there is no real default mechanism for an element (which would be nice).
So, Simon gets the answer since he's correct! Thanks!
This is not possible based on the nested element element documentation for the macrodef task.
There is a Bugzilla issue open for exactly the functionality you describe, unfortunately it has been open since 2004.
if you define your macrodef as:
<macrodef name="testing">
<element name="additional" optional="true"/>
<sequential>
<echo message="hello"/>
<additional/>
</sequential>
</macrodef>
the following invocation:
<target name="testing-call">
<mylib:testing/>
<mylib:testing>
<additional>
<echo message="world!"/>
</additional>
</mylib:testing>
</target>
will output:
[echo] hello
[echo] hello
[echo] world!

Resources