Passing optional path arguments to ant - 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.

Related

How to pass nested arguments from one ant target to another

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.

how to pass an optional argument to Ant and run specific test case

I have a task in which a user might (and might not) pass an argument - a JUnit test class - to Ant via command line.
If the user pass the argument then only this specific test class will execute.
If not, a all test classes will run i.e. "*/.java".
How do I accomplish the condition above? I already know how to run specific test class but the conditional thing - class name passed through command line with -D vs. a predefined list (*/.java) - eludes me.
Thanks!.
I use some thing like this
<batchtest todir="${test.results.dir}">
<fileset dir="${tests.dir}">
<include name="**/*${mytest}.class" if="mytest"/>
<include name="**/*Test.class" unless="mytest"/>
</fileset>
</batchtest>
The key is the fileset becomes a function of command line argument passed
ant tests -Dmytest=TestnamePattern

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>

Run pngquant through an Ant task

I've been attempting unsuccessfully to create a custom Ant task that processes a bunch of PNG files using pngquant.
Here's what I've been trying to so far (and I've been running it as a part of the HTML5 Boilerplate Build Script, so that's where the dynamic values are coming from):
<apply executable="${basedir}/${dir.build.tools}/pngquant" dest="./${dir.publish}/${dir.images}/" osfamily="unix">
<fileset dir="./${dir.source}/${dir.images}/" includes="**/*.png" excludes="${images.bypass}, ${images.default.bypass}"/>
<arg value="-force 256"/>
<targetfile/>
<srcfile/>
<mapper type="identity"/>
</apply>
Currently, each image errors with "cannot open for reading".
I know this may not be very helpful, but I really don't know where to go from here. Any help would be very much appreciated.
I don't know what the problem is, but I think there are something wrong with your Ant XML itself.
First of all, your excludes has a additional space after the comma.
excludes: comma- or space-separated list of patterns of files that must be excluded.
That is to say, you should either use comma, or space, not together. So it should be ${images.bypass},${images.default.bypass}. ---- I found that it is not right. It uses StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens) and passes false to the third parameter, so that you can use , together.
Also, I recommend you use nested <include> and <exclude> element to make it more clear.
Second, you don't need to put <targetfile/> and <srcfile/> inside <apply> if you don't need to use them.
Third, <arg value="-force 256" /> should be <arg value="-force"/> and <arg value="256"/>.

Renaming files with dir values using Ant?

I have the following simple thing to do with Ant but did not find how to do that:
move build/xxx/file.ext to dest/xxxfile.ext
I'm no Ant Guru .
file.ext is constant in this particular case
Nota : xxx can take many values so I want to apply to all these values
You need to use a mapper element to generate the destination file names. This is derived from the Ant mapper docs:
<move todir="dest">
<fileset dir="build" includes="*/*.ext" />
<mapper type="regexp" from="^([^/]*)/([^/]*)" to="\1\2"/>
</move>
When in doubt, an exec will do the job for you, but it's not always the best way.
Try the move task.
<move file="build/xxx/file.ext" tofile="dest/xxxfile.ext"/>

Resources