Optional parameter to <ant> task call? - ant

I would like to be able to pass an optional parameter to an ant task call, so that it appears as unset to the called target if it is omitted (important in conditions or when using the unless or if attributes). I don't know if optArg is set, so I cannot hard-code the parameter.
Example: The ant target someTarget requires a mandatory parameter mandatoryArg and supports an optional parameter optArg.
I can achieve this by cludgy duplication like so:
<if><equals arg1="${optArg}" arg2="true" />
<then>
<ant dir="someDir" target="someTarget" inheritAll="false">
<property name="mandatoryArg" value="42" />
<property name="optArg" value="true" />
</ant>
</then>
<else>
<ant dir="someDir" target="someTarget" inheritAll="false">
<property name="mandatoryArg" value="42" />
</ant>
</else>
</if>
I would like to leave out the if statement so that the ant call is not duplicated, without losing the optional nature of optArg. I already found this question, which appears to cover a different problem.
I use Ant 1.7 and ant-contrib.
Any ideas? Thanks!
EDIT: I also accept answers that explain why it really isn't possible.

You might be able to get the behavior you want by using the <if> block to build a property set, and then referencing it inside a single <ant> task call later with <propertyset refid="whatever"/>

Related

Why does ANT update the contents of a fileset after it was created, and can I override this?

I think this may be easiest explained by an example, so here goes:
<target name="test">
<fileset id="fileset" dir="target">
<include name="*"/>
</fileset>
<echo>${toString:fileset}</echo>
<touch file="target/test"/>
<echo>${toString:fileset}</echo>
</target>
Outputs:
test:
[echo]
[touch] Creating target/test
[echo] test
What I ideally want is to have the fileset stay the same so I can have a before/after set (in order to get a changed set using <difference>, so if you know of a way to skip right to that...).
I've tried using <filelist> instead, but I can't get this correctly populated and compared in the <difference> task (they're also hard to debug since I can't seem to output their contents). I also tried using <modified/> to select files in the fileset, but it doesn't seem to work at all and always returns nothing.
Even if there is an alternative approach I would appreciate a better understanding of what ANT is doing in the example above and why.
The path selector is evaluated on the fly. When a file is added, it will reflect in the set when you use it.
You may able to evaluate and keep it in variable using pathconvert. Then this can be converted back to filest using pathtofilest
A fileset is something like a selector. It's a set of "instructions" (inclusions, exclusions, patterns) allowing to get a set of files.
Each time you actually do something with the fileset (like printing the files it "references"), the actual set of files is computed based on the "instructions" contained in the fileset.
As Jayan pointed out it might be worth posting the final outcome as an answer, so here's a simplified version with the key parts:
<fileset id="files" dir="${target.dir}"/>
<pathconvert property="before.files" pathsep=",">
<fileset refid="files"/>
</pathconvert>
<!-- Other Ant code changes the file-system. -->
<pathconvert property="after.files" pathsep=",">
<fileset refid="files"/>
</pathconvert>
<filelist id="before.files" files="${before.files}"/>
<filelist id="after.files" files="${after.files}"/>
<difference id="changed.files">
<filelist refid="before.files"/>
<filelist refid="after.files"/>
</difference>

Passing optional path arguments to ant

I have an ant task that uses an apply task to run a script on a group of files.
I have a directory structure resultant of something like this:
mkdir -p a/{b,c,d,e}/f
Normally (if I pass no arguments), I would like ant to run on all fs.
That is, if I called ant mytask, it should process: a/b/f, a/c/f, a/d/f, a/e/f. This already works using apply and patternsets.
However, when I pass it an optional argument called foo, it should only call the script on a/foo/f.
So if I called ant mytask -foo b, it should process a/b/f only, and not the others.
I have read this SO post, which explains ways of passing arguments, and I have looked at the ant documentation regarding properties, and conditionals. But I am still unable to piece them together in a way that works.
Also, I do not want to use one of the suggestions from the SO above which called for arguments like this:
<arg value="${arg0}"/>
<arg value="${arg1}"/>
I want to be able to call it as ant mytask -foo valueoffoo for any arbitrary foo.
Thanks.
I tried martin clayton's suggestion below and have code like:
<target name="mytask">
<property name="foo" value="*" />
<apply executable="perl">
<arg value="somescript"/>
<dirset id="them" dir="a">
<include name="${foo}/*/f" />
</dirset>
</apply>
</target>
The above does what I want.
Note 1: In my actual code I use a patternset instead of dirset but it should work the same.
Note 2: In my original question I said the directory structure was a/{b,c,d,e}/f. It is in fact a bit more complicated, hence the * in the include above. I omitted that the first time around because it did not seem relevant.
You can do this - albeit with a slightly different command-line syntax -
using a property 'override'.
First, in the buildfile, construct your fileset or dirset from a property foo,
something like this:
<property name="foo" value="*" />
<dirset id="them" dir="a">
<include name="${foo}/f" />
</dirset>
This will give you your default behaviour - processing all
subdirectories of a that themselves have a subdirectory f.
Now, if you run Ant like this:
ant -Dfoo=d
Only directory a/d/f will be processed.
This works because Ant properties are not mutable - well, not normally anyway -
so the command-line definition of foo prevents the one within the buildfile from being used.

Can a macrodef Task be Called Dynamically

I have a number of macrodef tasks that I would like to call but would like to wrap the calls with some timestamping code. This could be easily done if the tasks were targets instead of macrodefs by using antcall.
Is it possible to do the same thing with macrodef?
Example:
The "macrocall" line is the hypothetical kind of task that I would like to use (akin to "antcall")
<target name="run.tests">
<run.named.test name="macro1" />
<run.named.test name="macro2" />
</target>
<macrodef name="run.named.test">
<attribute name="name" />
<sequential>
<echoTime />
<macrocall name="#{name}" />
<echoTime />
</sequential>
</macrodef>
<macrodef name="macro1">
</macrodef>
<macrodef name="macro2">
</macrodef>
Why not wrap your macro1 macro2 with targets and use an antcall for the "macrocall". the new macro1, macro2 targets will each run in their own project (properties and ref passed in, but not back out) which may or may not be a good thing depending on what you're trying to accomplish.
There no pure ant way to accomplish what you want as far as i know -- dynamically calling a task. You'd probably need to find some outside package to even come close, but it would probably be uglier.
This is a very late reply, but I had been struggling with the exact same issue for a while and just now came up with a solution, so I figured I'd contribute.
First of all, I think it's safe to definitively say that there is no way to do this simply with Ant alone, outside of doing something extremely hacky like echoing Ant code to a new file and then calling a macrodef from the file.
Anyway, I decided to use the Groovy Ant task to run some Groovy code. Here's what I came up with:
<groovy>
ant."${properties["macrodef.name"]}"("dir":properties["dir"])
</groovy>
Explanation:
-ant. is simply the prefix for telling Groovy to run an Ant task. For example, ant.echo() runs the <echo> task.
-"${properties["macrodef.name"]}" pulls the property named "macrodef.name" from my Ant project.
-With the two above combined together like this, I'm telling Groovy to run an Ant task with the same name as the value of the property "macrodef.name". For example, if ${macrodef.name} in my Ant project currently holds the value of "compile", Groovy will read this line as ant.compile.
-("dir":properties["dir"]) tells Groovy to run the macrodef with the attribute "dir" using the value of the Ant property also named "dir". To be clear, this is because my macrodef requires this attribute. In Ant, it would look like this: <compile dir="${dir}" />
I hope this helps anyone who comes across it! For the record, I wanted to avoid using the more generic <script> task, because apparently it runs noticeably slower than basic Ant or the Groovy task. The ideal solution would probably be to actually write a custom Ant task, but unfortunately I don't quite have to knowledge to do that yet.
There are two ways to resolve macrodef name dynamically
1) Macrodef names are not constant and resolved during load time depending on "what-to-say" variable. As a result, only one macrodef gets "say-something" name, there other one's name is not resolved (so not available to call)
<property name="what-to-say" value="bye"/>
<property name="say-${what-to-say}" value="say-something"/>
<macrodef name="${say-hi}">
<sequential>
<echo>hi!</echo>
</sequential>
</macrodef>
<macrodef name="${say-bye}">
<sequential>
<echo>bye!</echo>
</sequential>
</macrodef>
<target name="test">
<say-something/>
</target>
2) Create two additional files with macrodef definitions, e.g.
<project name="macrodefs-hi.xml>
<macrodef name="say-something">
<sequential>
<echo>hi!</echo>
</sequential>
</macrodef>
</project>
<project name="macrodefs-bye.xml>
<macrodef name="say-something">
<sequential>
<echo>bye!</echo>
</sequential>
</macrodef>
</project>
And include just one of them to your main project
<property name="what-to-say" value="bye"/>
<import file="macrodefs-${what-to-say}.xml"/>
<target name="test">
<say-something/>
</target>

How to reset a property in ANT?

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.

Ant target with property part of the name attribute

I want to define a target using a property as part of its name attribute, but the property doesn't seem to resolve.
<property name="foo" value="FOO" />
<target name="${foo}.init.win32" />
<antcall target="${foo}.init.win32" />
The error I get is: Target "FOO.init.win32.x86" does not exist in the project.
I guess Ant doesn't allow this behavior?
Yes, ant doesn't allow variable name of the target. Otherwise dependency calculation can be very difficult task

Resources