I'm writing a velocity macro within which I have some ant tasks. Within a #foreach loop in the velocity macro, I have a pathconvert task:
#foreach(<iterate through something>)
<pathconvert property='filename' refid='swf.file'>
<mapper>
<chainedmapper>
<flattenmapper/>
<globmapper from='*-d.swf' to='*'/>
</chainedmapper>
</mapper>
</pathconvert>
#end
The problem I have is that the 'filename' property gets set only once, during the first iteration, since properties in ANT are immutable.
But I need the filename to be set during each iteration. Is there a way to get this done?
If there was a way to reset the property, I could do that at the end of each iteration. Or is there a better way to do this?
Any help would be highly appreciated!
Thanks in advance,
Anand
You could use ant-contrib's variables. They act like mutable properties.
http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html
Use the new lexically scoped properties in Ant 1.8:
"Lexically scoped local properties, i.e. properties that are only defined inside a target, sequential block or similar environment."
Annoucement.
Properties in Ant were designed to be immuatable, but they gave in to popular demand and gave us variables. Your alternative is to write a custom task ( in Java or a Dynamic Language) but this seems like a good compromise.
The following snippet illustrates an ant property which I guess is not documented. Properties are immutable, but references are mutable. So any data type which has no name, but a reference, is mutable. For example a fileset. But today I found a way to have a kind of mutable property. Connected with local task or some other tricks it may be a way of having variables in ant.
<property name="a" value="aaa" id="refa" />
<property name="b" refid="refa" />
<echo>${b}</echo>
<property name="c" value="ccc" id="refa" />
<property name="d" refid="refa" />
<echo>${d}</echo>
The output is:
aaa
ccc
Although in both cases a reference refa is printed.
Here is a post about it. And another one.
Use a combination of for + let task from Ant Plugin Flaka to overwrite existing properties.
See some snippets here.
Related
How to pass nested arguments from one ant target to another?
I need to pass a variable number of nested elements from one target to another.
I have a common file with all of my standard build tasks that's included in all of my projects.
I am adding a new custom task that takes a variable number of nested arguments
As a standard, all ant calls are made through the common file to ensure consistency of build style and logging.
Thus the new custom task and its nested child will be defined in the common script.
The project build script looks like this
<target name="projectBuild">
...
<ant target="_newFooTaskWrapper" antfile="commonFile">
<property name="_arg1" value="hello"/>
<property name="_arg2" value="world"/>
<nestedArg value="qux"/>
<nestedArg value="baaz"/>
...
<nestedArg value="AAAAA"/>
</ant>
...
</target>
The common script looks like this:
<target name ="_newFooTaskWrapper">
<echo message="Target _newFooTaskWrapper in project ${ant.project.name} from base directory ${basedir}"/>
<echo message="arg1 = ${_arg1}"/>
<echo message="arg2 = ${_arg2}"/>
<taskdef name="newFooTask" classname="org.foo.NewFooTask"/>
<typedef name="nestedArg" classname="org.foo.NewFooTask$NestedArg"/>
<newFooTask arg1="${_arg1}" arg2="${_arg2}">
<nestedArg value="qux"/>
<nestedArg value="baaz"/>
...
<nestedArg value="AAAAA"/>
</newFooTask>
Obviously, this isn't right. My question is, what's the right way to do this?
I need to pass a variable number of nested elements from one target to another.
For "varible", I assume you mean you don't know the exact number of the nested elements you want to pass to the task, so what you want is something like method(Object param...) in java, is it?
It's not a good idea to try such a way. Ant is not a scripting language but a build tool. It provides limited "scripting" possibilities.
However, you can try it in the following two ways:
1, If your nested element is just in the form of <elementName value="xx" />, you don't need anything complicated. Just pass another property containing a comma seperated list of the values, and process the list in your custom ant task. It's easy for Java to split the property into a list and process it.
2, If your nested element may be more complicated... maybe you can try reference:
Make a type fooTaskParams which can be referenced via an id:
<fooTaskParams id="_foo_task_params">
<nestedArg value="qux"/>
<nestedArg value="baaz"/>
...
<nestedArg value="AAAAA"/>
</fooTaskParams>
and pass the reference to the other build file:
<ant target="_newFooTaskWrapper" antfile="commonFile">
<property name="_arg1" value="hello"/>
<property name="_arg2" value="world"/>
<reference refid="_foo_task_params"/>
</ant>
and then make your task to be able to process the reference:
<newFooTask arg1="${_arg1}" arg2="${_arg2}" paramRefId="_foo_task_params" />
You may need to take care of reference override, or make your task able to process the ref as well as taking nested elements.
Read ant's manual about <ant> and <typedef> for more about this approach, and refer to SO Q&As like this when you encount any problem.
Working with simple ant's property is tricky & doesn't allow to set needed value easily (properties are immutable). Using ant-conrib's var tasks allows properties to be set and unset.
Any genuinue or good reason behind making ant property designed to work in such a complex way?.
<property name="some.ant.prop" value=""/>
<if>
<isset property="some.ant.prop"/>
<then>
<echo message="immutable ant prop - not good, defined and just even set to null string : ${some.ant.prop}"/>
<property name="some.ant.prop" value="no-effect-value"/>
<echo message="no-effect on changing already defined prop : ${some.ant.prop}"/>
<var name="some.ant.prop" unset="true"/>
<property name="some.ant.prop" value="any-value-accepted"/>
<echo message="Overwritten prop value: ${some.ant.prop}"/>
</then>
</if>
Not for discussion or argument , but its good to know on more feasible alternatives. Thanks.
Ant ain't a programming language !
Properties once set are immutable in ant by design.The Pros and Cons have been discussed (much too) often and i won't go into details.
Several possibilities to get over those limitations :
In the past people used antcall for that purpose - with all its drawbacks, search for 'antcall vs. macrodef' to get the details. Ant 1.6 introduced macrodef and Ant 1.8 came with a new local task.
If macrodef and local are not sufficient you may use script task with builtin javascript engine (since JDK 1.6) or Groovy to access ant api.
There are also Ant addons like f.e. antcontrib or Flaka. If antcontrib var / unset feels too clumsy for you, the
Flaka's let task provides a more straight approach for overwriting properties :
<!-- set a new property -->
<fl:let>foo := 'bar'</fl:let>
<!-- overwrite an existing property or userproperty
(those properties defined on the commandline via -Dfoo=bar ..)
notice the double '::' in foo ::= 'baz' -->
<fl:let>foo ::= 'baz'</fl:let>
Finally : Either get used to ant and its limitations (but don't use antcall !) oruse Ant addon use ant from groovy or switch to Gradle.
I have a property that has to contain long list of strings and to improve readability I would like to define each value (that are quite long) in separate line, something like:
<property name="items" separator=",">
<item>A</item>
<item>B</item>
</property>
as equivalent to
<property name="items" value="A,B" />
Or something similar to <path> + <pathconvert> but not expanding paths.
Is it possible ?
Turns out there are string resources and a generic resource container:
<resources id="items">
<string>A</string>
<string>B</string>
</resources>
<pathconvert property="items" refid="items" pathsep="," />
Not supported by standard ANT.
There is a popular ant-contrib plugin that has a "foreach" task which acts upon comma separated properties, but I prefer to embed a proper programming language. groovy stands out due it's excellent Java and ANT integration.
Examples of list handling:
Change values of list in ANT
How can i pass two variable in one Ant target by spliting commas
All my projects and their versions are defined in a properties file like this:
ProjectNameA=0.0.1
ProjectNameB=1.4.2
I'd like to iterate over all the projects, and use their names and versions in an Ant script.
At present I read the entire file using the property task, then iterate over a given list in a for loop like this:
<for list="ProjectNameA,ProjectNameB" param="project">
<sequential>
<echo message="#{project} has version ${#{project}}" />
</sequential>
</for>
How can I avoid the hard-coding of the project names in the for loop?
Basically iterate over each line and extract the name and the version of a project as I go.
Seeing as you're already using antcontrib for, how about making use of the propertyselector task:
<property file="properties.txt" prefix="projects."/>
<propertyselector property="projects" match="projects\.(.*)" select="\1"/>
<property file="properties.txt" />
<for list="${projects}" param="project">
...
</for>
The idea here is to read the properties once with the projects prefix, and use the resulting set of properties to build a comma-separated list of projects with the propertyselector task. Then the properties are re-read without the prefix, so that your for loop can proceed as before.
Something you want to keep in mind, if you are reading additional .property files (besides build.properties) is scoping. If you read an additional file (via the property file="foo.property") tag, ant will show that the file was read, and the properties loaded. However, when you goto reference them, they come up un-defined.
I'd like to set some properties in my ant build file, the names of which, are based on ant's build in properties. In particular, I'd like to set a property like:
<property name="${ant.project.name}.compiled" value="true" />
However, when I tried this the ${ant.project.home} portion was not expanded.
Is it possible to use the value of properties as the names of other properties, and if so, how?
<property name="name.holder" value="iamholder" />
<property name="${name.holder}.flag" value="true" />
<echoproperties></echoproperties>
result:
[echoproperties] iamholder.flag=true
this is definitely valid ant code and the property iamholder.flag gets the value of true.
If ${name.holder} does not get expanded, it means it has not been set yet (like if the first line in my sample was missing).
Anyways, this still does not quite solve your problem, as you have pretty much no means of getting the value of this property as you don't know it's name and you can't do a nested resolve in pure ant. Depending on what you are trying to do it could still be useful to you though. This one would work (keep in mind, that until 1.8 the value is irrelevant as long as the property is set):
<target name="compile_stuff" unless="${name.holder}.flag">
<echo>compiling...</echo>
</target>
To really get the value of such a property you have to use ant-contrib's propertycopy as suggested in one of the answers. That way you can get the value in a property whose name you know. Just make sure to do the trick just before use and set the override parameter to true (your post implies that you would be setting more properties like these, but without override your final property could not be changed). Another option for working with such properties is to use ant macros.
I think the only way is to echo your values to a .properties file and then load them back.
However, you should ask yourself if you really need it; when I last used ant I tried to do the same thing but concluded I didn't really need to.
Is
$ant.project.home.compiled
not just as useful?
It can be done, a bit ugly, though. You need the < propertycopy > task from ant-contrib for this. The following shows an example
<property name="projectNameCompiled" value="${ant.project.name}.compiled" />
<property name="${projectNameCompiled}" value="true" />
<propertycopy property="final" from="${ant.project.name}.compiled" />
The property final contains the value true.
There are several ways to achieve that, see Ant FAQ
One possible solution via macrodef simulates the antcontrib / propertycopy task but doesn't need any external library.