Check value of variable to skip task in Ant - ant

I have the following target in my build file:
<target name="copyLibrary">
<copy toDir="${workingDir}/${location}" includeEmptyDirs="false">
<fileset dir="${librariesRoot}/${libraryDir}" includes="*"/>
</copy>
</target>
What I want to do is check the value of ${libraryDir} and if it is a particular directory, do not perform the copy.
I have tried to change the fileset to use nested include and exclude tags but it doesn't like this. I have also tried to add an unless attribute to the target and copy, but these are not allowed. I am currently working on the if attribute on the target to see where I get. I have a feeling that I will probably need to change from a fileset to something like a dirset.

A <fileset> can have nested <include> and <exclude> elements. These <include> and <exclude> elements can have if and unless attributes.
In your case, an <include> with an unless may work:
<condition property="libraryDir-is-scorned">
<equals arg1="${libraryDir}" arg2="unlovedLibrary"/>
</condition>
<copy toDir="${workingDir}/${location}" includeEmptyDirs="false">
<fileset dir="${librariesRoot}/${libraryDir}">
<include name="*" unless="libraryDir-is-scorned"/>
</fileset>
</copy>

Related

Call a <macrodef> for each <pathelement> in a <path> in Ant

I have a path as follows:
<path refid="myjarlocation"/>
Now I want to iterate over this path and for each value present in the path I want to call a macrodef with that value as one of the property to be used inside the marcodef.
In case of target we can easily do it as follows:
<foreach target="mytarget" param="jarloc">
<path refid="myjarlocation"/>
</foreach>
I cannot use for each because I need to pass multiple parameters , so I am using macrodef. So, therefore the question how to iterate over a path and call a macrodef instead of a target.
I've made something similar work by using ant-contrib's for task to iterate a path and passing the path element along to a macrodef.
First get ant-contrib in your project - see http://ant-contrib.sourceforge.net/
Next, define your macrodef in your ant build however you want including some attribute that will take your path element. eg:
<macrodef name="awesome-macro">
<attribute name="path-to-deal-with"/>
<attribute name="unrelated-attribute"/>
<sequential>
...
</sequential>
</macrodef>
Then, use the for task to iterate the path into pathelements and invoke the macro:
<for param="path.element">
<fileset dir="${jars.dir}">
<include name="*.jar"/>
</fileset>
<sequential>
<awesome-macro path-to-deal-with="#{path.element}" unrelated-attribute="whatever"/>
</sequential>
</for>
Note the use of #{path.element} as opposed to ${path.element} inside the for loop to refer to the looping parameter!

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>

Creating an empty placeholder fileset in Ant

So, here's the situation: I have a parent buildfile that defines a compilation task, and I want child buildfiles to optionally be able to add more JARs (which could be wherever) on to the classpath used by that compilation task.
Not all child buildfiles will have these additional dependencies, so I don't want to force them to define the additional dependency fileset. They should just be able to include the parent, and the compile task should just work.
(Obviously there are other required properties that configure the source directory and so on, but they don't enter into this. Also, the actual include/inheritance problem is a good bit more complicated, but hopefully whatever the right thing is for the simple case will work in the complex case too.)
I have something that works: The compile task in the parent buildfile refers to the additional dependency fileset regardless:
<target name="compile" depends="init-additional-dependencies">
<fileset id="global.dependency.fileset" dir="${global.library.directory}">
<include name="**/*.jar"/>
</fileset>
<javac ...>
<classpath>
<!-- should be the same for all buildfiles -->
<fileset refid="global.dependency.fileset"/>
<!-- should be populated by child buildfiles -->
<fileset refid="additional.dependency.fileset"/>
</classpath>
</javac>
</target>
...and the parent buildfile also has a task that creates this fileset, empty, so that javac doesn't blow up. However, the way I'm creating the empty fileset is dopey:
<target name="init-additional-dependencies">
<!-- override me! -->
<fileset id="additional.dependency.fileset" dir=".">
<include name="placeholder.does.not.exist.so.fileset.is.empty"/>
</fileset>
</target>
This works, but seems dumb, and it's hard to believe there isn't a better approach. What is that better approach?
I don't think there's been much discussion about this, so no 'convention' as such exists. The way that fileset works though, exclusions 'trump' inclusions, thus
<fileset refid="additional.dependency.fileset" dir="." excludes="**" />
should always be empty. That seems slightly preferable to both your placeholder file name technique, and the placeholder directory name and erroronmissingdir method.
The problem arises because, by default, there is an implicit include of all files beneath the parent directory of a fileset. Another option - perhaps not of direct use in your case - is to use a filelist instead. Because filelists are constructed from explicitly named files, if you don't name any, they are empty.
<filelist id="additional.dependency.filelist" />
By generalising, you can mix filesets and filelists, if you modify your classpath to use resources:
<filelist id="additional.dependency.resources" />
...
<classpath>
<!-- should be the same for all buildfiles -->
<fileset refid="global.dependency.fileset"/>
<!-- should be populated by child buildfiles -->
<resources refid="additional.dependency.resources"/>
</classpath>
the reference additional.dependency.resources can be either a fileset or a filelist (including the empty filelist), or any other file-based resource collection.
In the parent build file add:
<fileset id="additional.dependency.fileset" erroronmissingdir="false" dir="noop" />
For children that require additional artifacts to be added, define the fileset in the child build file:
<fileset id="additional.dependency.fileset" dir="..." includes="..." />

Is there a way to skip a specific test case via the command line?

I am using apache ant, and do not want to change my source tests, but I'd like the option to turn one off. I know that it is possible to only RUN tests you choose (-Dtestcase=whatever), but I'm not sure if you can exclude one.
You might use ant -DexcludedTest=SomeExcludedTest and have your batch test configured like this:
<batchtest ...>
<!-- define the excludedTest property to an unexisting test name in case
nothing is passed as a system property -->
<property name="excludedTest" value="THIS_TEST_NAME_DOES_NOT_EXIST"/>
<fileset dir="${src.tests}">
<include name="**/*Test.java"/>
<exclude name="**/${excludedTest}.java"/>
</fileset>
</batchtest>

File Enumeration with Ant

I feel like I'm missing something obvious at the moment. I want to collect a set of dirs / files together in Ant. I know I can do it using a fileset with an optional patternset inside it, but that involves searching for files based a specific criterion - filetype, name etc.
I already know the paths to the files I want to collect. I have n properties which reference these paths. I want a way to collect these paths in a fileset, though I cannot find a way to do it.
This represents what I want to achieve (I know it isn't valid code, but hopefully it will describe what I mean):
<fileset>
<path>${src.dir}</path>
<path>${test.dir}</path>
<path>${third.party.src.dir}</path>
<path>${bin.dir}</path>
<path>${docs.build.txt}</path>
</fileset>
You could try using a files element.
<files>
<include name="${src.dir}/**/*.*">
<include name="${test.dir}/**/*.*">
<include name="${third.party.src.dir}/**/*.*">
<include name="${bin.dir}/**/*.*">
<include name="${docs.build.txt}">
</files>
Thanks for the answer which works fine, however I managed to achieve the same thing even more simply using path with nested pathelements:
<path
id="srcdirs">
<pathelement location="${src.dir}"/>
<pathelement location="${test.dir}"/>
<pathelement location="${assets.dir}"/>
</path>

Resources