How do I use a patternset to filter a list of files? - ant

This seems like something that should be obvious, but I don't think it is. Given:
a space-delimited list of files (or comma-delimited, etc.)
a <patternset> of whitelisted patterns
How do I come up with a <fileset> that contains all of the files in the list that match the whitelisted pattern?
Getting a list of files from the list is easy enough:
<patternset id="the-patternset" includes="${list.of.files}" />
<fileset id="the-fileset" dir="${basedir}">
<patternset refid="the-patternset" />
</fileset>
<pathconvert pathsep="${line.separator}" property="the-filelist" refid="the-fileset"/>
<echo>fileset: ${the-filelist}</echo>
…will happily produce a fileset with all of the files in ${list.of.files}. But adding a filter of sorts:
<patternset id="the-filter">
<include name="includeme/**/*.java" />
<exclude name="excludeme/**/*.java" />
</patternset>
<patternset id="the-patternset" includes="${list.of.files}" />
<fileset id="the-fileset" dir="${basedir}">
<patternset refid="the-patternset" />
<patternset refid="the-filter" />
</fileset>
<pathconvert pathsep="${line.separator}" property="the-filelist" refid="the-fileset"/>
<echo>fileset: ${the-filelist}</echo>
…will list a union of the patternsets—i.e., all files that match either the-filter or the-patternset.
How do I produce a fileset containing files that are in ${list.of.files} and match the-patternset?

Here's a potted example. Create two filesets (or perhaps filelists) one from each of your patternsets. I'll just use fixed lists here:
<property name="list.1" value="a,b,c" />
<property name="list.2" value="b,c,d" />
<fileset dir="." id="set.1" includes="${list.1}" />
<fileset dir="." id="set.2" includes="${list.2}" />
Then use the <intersect> resource collection to get the required 'overlap' set:
<intersect id="intersect">
<resources refid="set.1"/>
<resources refid="set.2"/>
</intersect>
Most Ant tasks will allow you to use a resource collection in place of a simple fileset.

Related

Add .class to ant build classpath

I am trying to add a few folders to the classpath in our ant build file.
<dirset dir="${env.WT_HOME}/codebase/com/lcs/wc/">
<include name="flexbom flexQuerySpec flextype foundation material util moa" />
</dirset>
All these folders (i.e. 'flexbom' 'flexQuerySpec'...) are inside codebase/com/lcs/wc folder. Each folder has several class files. I want to add all these class files to the path.
Above script doesn't seem to be working. I am still getting class not found for these folder/packages.
Nested <include> elements in a <fileset> or <dirset> specify matching patterns, one pattern per element, rather than lists.
An alternative is to use the includes attribute instead like this:
<dirset dir="${env.WT_HOME}/codebase/com/lcs/wc/"
includes="flexbom flexQuerySpec flextype foundation material util moa" />
Or multiple include elements:
<dirset dir="${env.WT_HOME}/codebase/com/lcs/wc/">
<include name="flexbom" />
<include name="flexQuerySpec" />
<include name="flextype" />
<include name="foundation" />
<include name="material" />
<include name="util" />
<include name="moa" />
</dirset>

How to to pass configurable file mapping lists to ant macros?

I'm trying to refactor an Ant buildfile with many similar targets into a buildfile that uses macros. This roughly is what it looks like:
<macrodef name="build-text">
<argument name="lang" />
<element name="file-list"/>
<sequential>
<property name="lang" value="#{lang}" />
<xslt style="my_stylesheet.xsl" destdir="build" basedir="src">
<!-- lots of params here -->
<file-list />
</xslt>
</sequential>
</macrodef>
<target name="buildTextDE">
<build-text lang="DE">
<file-list>
<mapper>
<mapper type="glob" from="Text1_${lang}.html" to="Text1_${lang}.fo"/>
<mapper type="glob" from="Text2_${lang}.html" to="Text2_${lang}.fo"/>
</mapper>
</file-list>
</build-text>
</target>
There is another task called buildTextEN that is nearly identical except for the lang attribute. In some cases, the file list differs however. Now how would I like to simplify the buildfile further by defining a "global" mapping list that contains the file lists for German and English, each file with the placeholder for the language. I would like to reference this global mapping where no special case is needed. How would I do that?

Exporting zipfilesets

We are currently generating a zip file using multiple targets as follows.
<zipfile>
<zipfileset dir="alpha" prefix="alpha" />
<zipfileset dir="beta" prefix="alpha" excludes="*.bar" />
<zipfileset dir="gamma/G" prefix="gamma" />
</zipfile>
A requirement has come up in that we need to generate (and include) a list of the included files and their corresponding MD5 checksum values.
If we use a <fileset>/<patternset>/<pathconvert> combination, I can get a text file containing all the files, and generate from there. However, I can't seem to find a way to do this with <zipfileset /> targets.
Is there a way to do a 'dry-run' and obtain a list of the targets that will be included? Or is there a (simple) method of extracting the required information from the generated ZIP itself?
If you have already generated file (with checksum) you can just add it with help of another fileset.
The sample:
<target name="ziptest">
<zip destfile="${src}\output.zip">
<fileset dir="${src}">
<include name="dir1\*"/>
<include name="dir2\fileprefix*"/>
</fileset>
<fileset dir="${src}">
<!-- You have property with filename: file.name.checksum-->
<include name="${file.name.checksum}"/>
</fileset>
</zip>
</target>

Ant: how to write optional nested elements

Say that I need to do something like:
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<if>
<equals arg1="${SPECIAL_BUILD}" arg2="true"/>
<then>
<fileset dir="dir7" />
<fileset dir="dir8" />
...
</then>
</if>
</copy>
(The real task is not copy, I'm just using it to illustrate the point.)
Ant will complain that my task doesn't support nested <if> which is fair enough. I've been thinking along these lines:
I could add a macrodef with an "element" attribute like this:
<macrodef name="myCopy">
<element name="additional-path" />
<sequential>
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<additional-path/>
</copy>
</sequential>
</macrodef>
But that would mean that the caller (target) must specify the additional path which I want to avoid (if many targets call this task, they would have to repeat the fileset definitions in the additional-path element).
How to code the additional filesets inside the macrodef so that Ant doesn't complain?
AntContrib has an Ant FileSet object augmented with if and unless conditions.
http://ant-contrib.sourceforge.net/fileset.html
if Sets the property name for the 'if' condition. The fileset will be
ignored unless the property is
defined. The value of the property is
insignificant, but values that would
imply misinterpretation ("false",
"no") will throw an exception when
evaluated.
unless Set the property name for the 'unless' condition. If named
property is set, the fileset will be
ignored. The value of the property is
insignificant, but values that would
imply misinterpretation ("false",
"no") of the behavior will throw an
exception when evaluated.
You could use it like this:
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<fileset dir="dir7" if="SPECIAL_BUILD" />
<fileset dir="dir8" if="SPECIAL_BUILD" />
</copy>
One way (not sure if a good one) to achieve that is to create two macrodefs - one "public" for general use and one "internal" that does the real work and is intended to be called only from the "public" macro. Like this:
<macrodef name="task-for-public-use">
<sequential>
<if>
<equal arg1="${SPECIAL_BUILD}" arg2="true" />
<then>
<internal-task>
<additional-path>
...
</additional-path>
</internal-task>
</then>
<else>
<internal-task ... />
</else>
</if>
</sequential>
</macrodef>
<macrodef name="internal-task">
<element name="additional-path" />
<sequential>
<copy ...>
...
<additional-path/>
</copy>
</sequential>
</macrodef>
I don't like it much though and hope there's a better way.

Using mapper & fileset to copy files into a different subdirectory?

I want to create an Ant target that copies files in a directory to a destination directory with the same folder structure, plus one more subfolder appended.
For example, the source is:
a/b/c/foo.pdf
d/e/f/bar.pdf
I want the destination to be:
a/b/c/x/foo.pdf
d/e/f/x/bar.pdf
Here is my target so far, but it doesn't appear to be doing anything:
<copy todir="${dest.dir}">
<fileset dir="${src.dir}" casesensitive="yes">
<include name="**${file.separator}foo.pdf" />
</fileset>
<mapper type="glob"
from="foo.pdf" to="x${file.separator}foo.pdf" />
</copy>
What am I missing?
You could use a regexp mapper:
<copy todir="${dest.dir}">
<fileset dir="${src.dir}" casesensitive="yes">
<include name="**/*.pdf"/>
</fileset>
<mapper type="regexp" from="^(.*)/(.*\.pdf)" to="\1/x/\2" />
</copy>
I've used hard-coded file.separators to shorten. Basically, you split the path to the input file (from) into directory and filename (capture \1 and \2) and then insert the \x extra element between them (to).
I'm not clear on your example - it looks like you want to match 'bar.pdf' and rename it to 'foo.pdf', as well as changing the directory. If you need to do that, you might consider chaining a couple of simpler regexp mappers, rather than trying to cook up one complex one:
<copy todir="${dest.dir}">
<fileset dir="${src.dir}" casesensitive="yes">
<include name="**/*.pdf"/>
</fileset>
<chainedmapper>
<mapper type="regexp" from="^(.*)/(.*\.pdf)" to="\1/x/\2" />
<mapper type="regexp" from="^(.*)/(.*\.pdf)" to="\1/foo.pdf" />
</chainedmapper>
</copy>
When using a glob mapper, you need to specify one wildcard * in the from field:
Both to and from are required and
define patterns that may contain at
most one *. For each source file that
matches the from pattern, a target
file name will be constructed from the
to pattern by substituting the * in
the to pattern with the text that
matches the * in the from pattern.
Source file names that don't match the
from pattern will be ignored.
So something like this might work:
<mapper type="glob" from="*/foo.pdf" to="*/x/foo.pdf" />

Resources