How can I exclude files from a reference path in Ant? - ant

In a project we have several source paths, so we defined a reference path for them:
<path id="de.his.path.srcpath">
<pathelement path="${de.his.dir.src.qis.java}"/>
<pathelement path="${de.his.dir.src.h1.java}"/>
...
</path>
Using the reference works fine in the <javac> tag:
<src refid="de.his.path.srcpath" />
In the next step, we have to copy non-java files to the classpath folder:
<copy todir="${de.his.dir.bin.classes}" overwrite="true">
<fileset refid="de.his.path.srcpath">
<exclude name="**/*.java" />
</fileset>
</copy>
Unfortunately, this does not work because "refid" and nested elements may not be mixed.
Is there a way I can get a set of all non-java files in my source path without copying the list of source paths into individual filesets?

Here's an option. First, use the pathconvert task to make a pattern suitable for generating a fileset:
<pathconvert pathsep="/**/*,"
refid="de.his.path.srcpath"
property="my_fileset_pattern">
<filtermapper>
<replacestring from="${basedir}/" to="" />
</filtermapper>
</pathconvert>
Next make the fileset from all the files in the paths, except the java sources. Note the trailing wildcard /**/* needed as pathconvert only does the wildcards within the list, not the one needed at the end:
<fileset dir="." id="my_fileset" includes="${my_fileset_pattern}/**/*" >
<exclude name="**/*.java" />
</fileset>
Then your copy task would be:
<copy todir="${de.his.dir.bin.classes}" overwrite="true" >
<fileset refid="my_fileset" />
</copy>
For portability, instead of hard-coding the unix wildcard /**/* you might consider using something like:
<property name="wildcard" value="${file.separator}**${file.separator}*" />

Related

Ant concat exclude directory

My application folder structure looks like this...
-js
-libs
-jquery.js
-jquery-ui.js
-app.js
-ui.js
I wish to concatenate the .js files that are in the /js directory but not those in the /js/libs directory. I am using the following code, but it is ignoring the exclude statement:
<concat destfile="${build.dir}/js/foot-${build.major}-${build.minor}.concat.js">
<fileset dir="${build.dir}/js">
<exclude name="**/libs/**" />
</fileset>
</concat>
The <fileset> should specify both include and exclude patterns. In addition, it may be good to specify a destination directory for <concat> separate from the <fileset> input directory.
<target name="concat-test">
<concat destfile="${basedir}/concat.js" fixlastline="yes">
<fileset dir="${basedir}/js">
<include name="**/*.js" />
<exclude name="**/libs/**" />
</fileset>
</concat>
</target>

How to preserve file order in Ant concat?

How to preserve file order in Ant concat?
Simple concat with fileset & includesfile produces rather "random" order, as order is not guaranteed:
<concat destfile="C:/targetdir/concatenated.file">
<fileset dir="C:/sourcedir/">
<includesfile name="C:/targetdir/includes.file" />
</fileset>
</concat>
What I need is concatenation in specific order that the files are listed in the includes file.
So far I've found resourcelist, which should preserve order, but I can't seem to be able to produce any concatenated file with it. :/
<concat destfile="C:/targetdir/concatenated.file">
<resourcelist>
<file file="C:/targetdir/includes.file"/>
<filterchain>
<striplinecomments>
<comment value="#"/>
</striplinecomments>
<prefixlines prefix="C:/sourcedir/"/>
</filterchain>
</resourcelist>
</concat>
Plus, the resourcelist can't seem to handle rows like
LibraryX/A/Stuff/Morestuff/*
Instead the row just produces a ".../Morestuff/* does not exist." -error
Includes file has list of relative paths:
LibraryX/A/Stuff/FileA.txt
LibraryX/A/Stuff/FileB.txt
LibraryX/A/Stuff/FileC.txt
LibraryX/A/Stuff/FileY.txt
I was able to get a filelist working pretty easily:
<concat destfile="C:/targetdir/concatenated.file">
<filelist dir="C:/sourcedir/">
<file name="i.txt" />
<file name="n.txt" />
<file name="o.txt" />
<file name="r.txt" />
<file name="d.txt" />
<file name="e.txt" />
<file name="r.txt" />
</filelist>
</concat>
Hope that helps!
If you are using Ant 1.7+, you can use the sort command
<concat destfile="C:/targetdir/concatenated.file">
<sort>
<fileset dir="C:/sourcedir/">
<include name="C:/targetdir/*.file" />
</fileset>
</sort>
</concat>
You can find the documentation of sort here
[On Ant 1.8.2+] You can also pass the fileset via a sort, and sort on filename, like below:
<concat destfile="./${dir.publish}/${dir.js}/b.main-${build.number}.debug.js">
<sort xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators">
<fileset dir="./${dir.publish}/">
<include name="**/${dir.js.main}/**/*.js"/>
<exclude name="**/${dir.js.main}/**/*.min.js"/>
</fileset>
<rcmp:name />
</sort>
</concat>
Couple of things to watch out for:
Directories are sorted before files
Capitals come before lowercase
UPDATE: Another alternative if you need to manually specify order:
<!-- create a ordered list of all the build files so that CIAPI & CIAPI.widget are built first
(can't find a smarter way to do this, since ant filesets are unordered) -->
<fileset id="a" dir="."><include name="CIAPI/build.project.xml"/></fileset>
<fileset id="b" dir="."><include name="CIAPI.widget/build.project.xml"/></fileset>
<fileset id="c" dir=".">
<include name="**/build.project.xml"/>
<exclude name="CIAPI/build.project.xml" />
<exclude name="CIAPI.widget/build.project.xml" />
</fileset>
<union id="all_build_files">
<fileset refid="a"/>
<fileset refid="b"/>
<fileset refid="c"/>
</union>
Ugly, but, erm, this is ant?
try this, put in alphabetical order
<project name="concatPath" default="full">
<target name="full">
<fileset id="fs" dir="./files" />
<pathconvert refid="fs" property="concatList" pathsep=";" targetos="unix"/>
<echo>${concatList}</echo>
</target>
</project>
this can be used with hierarchical structure of directories, and the order will be the exposed by David.
Remember that XML is not order-dependent, by definition.
To concatenate files in a sorted order, consider using <replace> instead.
Create an order file that defines the order. Then, in your build file:
Copy the order file to the destination file with <copy>
Concatenate your files together into a temporary file with <concat>
Load the files into properties with <loadfile>
Insert the text from those files into the destination file with <replace>
Example order file order_file.txt:
FILE_A_HERE
CONCAT_FILES_HERE
Example ant build file build.xml:
<copy file="order_file.txt" tofile="destination.txt" overwrite="yes">
<concat destfile="tempfile.txt">
<fileset dir="includes/">
<include name="*.txt">
<exclude name="fileA.txt">
</fileset>
</concat>
<loadfile property="fileA" srcFile="includes/fileA.txt" />
<loadfile property="concatFile" srcFile="tempfile.txt" />
<replace file="destination.txt" token="FILE_A_HERE" value="fileA" />
<replace file="destination.txt" token="CONCAT_FILES_HERE" value="concatFile" />

Ant script: Prevent duplication of JAR in javac-classpath war-lib

I have a ANT script and I have a lot of duplicated path to same set JAR files.
But there is so many double wording in the classpath and also in the war element.
<path id="my.classpath">
<pathelement location="folderA/subFolderA/1.0/A.jar"/>
<pathelement location="folderC/subFolderB/1.0/B.jar"/>
<pathelement location="folderF/subFolderZ/2.0/Z.jar"/>
<pathelement location="compile/subFolderX/1.0/onlyForJavac.jar"/>
</path>
....
<javac ...>
<classpath refid="my.classpath" />
</javac>
....
<war ...>
<lib file="folderA/subFolderA/1.0/A.jar"/>
<lib file="folderC/subFolderB/1.0/B.jar"/>
<lib file="folderF/subFolderZ/2.0/Z.jar"/>
<lib file="moreFolderF/subFolderZ/2.0/additionFile.jar"/>
<lib file="moreFolderF/subFolderZ/2.0/additionRuntimeFile.jar"/>
</war>
I want to summary them into ONE list which is easier to keep update.
But I am blocked as I have no idea how to share a path-like-structure with a fileset-like-structure.
Since Ant 1.8.0 there is a new resource collection - mappedresources that
can be used in place of the war task lib element.
So, the task might look like this (pretty much straight from the docs):
<war ... >
<mappedresources>
<restrict>
<path refid="my.classpath"/>
<type type="file"/>
</restrict>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="WEB-INF/lib/*"/>
</chainedmapper>
</mappedresources>
</war>
This feature was added to resolve a long-standing feature request to make
the task flatten jars when deploying to WEB-INF/lib.
previous answer:
Although you can't easily convert a path to a fileset with vanilla Ant, you can go the other way.
So one option would be to define your jars in a fileset, and derive the path from it.
Something like this perhaps:
<fileset id="my.fileset" dir="${basedir}">
<include name="folderA/subFolderA/1.0/A.jar"/>
<include name="folderC/subFolderB/1.0/B.jar"/>
<include name="folderF/subFolderZ/2.0/Z.jar"/>
<include name="moreFolderF/subFolderZ/2.0/additionFile.jar"/>
<include name="moreFolderF/subFolderZ/2.0/additionRuntimeFile.jar"/>
</fileset>
<path id="my.classpath">
<fileset refid="my.fileset" />
</path>
<!-- javac stays the same -->
<war ...>
<lib refid="my.fileset" />
</war>
Another possibility is to use the ant-contrib pathtofileset task.
Another solution, possibly 'not the best' will be to place required jar file in WEB-INF/lib, and then set the classpath from there.
<path id="compile.classpath">
<fileset dir="${lib.dir}" includes="*.jar"/>
</path>
When its time to build the war, you need not worry about the <lib> at all, as jars are already placed in WEB-INF/lib folder.
<war destfile="${dist.dir}/${project.name}.war" webxml="${web.dir}/WEB-INF/web.xml">
<fileset dir="${web.dir}"/>
<classes dir="${build.dir}/classes"/>
</war>

How does ant treat a pathelement that does not exist?

How does ant behave if I define a path with a pathelement which points to a non-existent directory?
<path id="foo.bar">
<pathelement location="this/might/not/exist/">
</path>
The scenario is that the ant file is used for several projects - some have this additional folder, and some do not.
Does ant just ignore it, or does it fail?
It depends on the context.
When used as a classpath for the javac task, the missing directories are simply ignored:
This task will drop all entries that point to non-existent
files/directories from the classpath it passes to the compiler.
But if you use a path containing a non-existent directory, say as the source for a copy, you'll get an error.
For example, here directories 'one' and 'three' exist, but 'two' does not:
<path id="mypath">
<pathelement path="one" />
<pathelement path="two" />
<pathelement path="three" />
</path>
<copy todir="dest">
<path refid="mypath" />
</copy>
BUILD FAILED
/.../build.xml:14: Warning: Could not find resource file ".../two" to copy.
You could use a dirset to filter out the missing items perhaps:
<pathconvert property="dirs.list" pathsep="," refid="mypath">
<map from="${basedir}/" to="" />
</pathconvert>
<dirset id="exists.dirs" dir="." includes="${dirs.list}" />
<copy todir="dest">
<dirset refid="exists.dirs" />
</copy>
[copy] Copied 2 empty directories to 2 empty directories under /.../dest

How do I "expand" an ant path (accessed with refId=..) to all files in the path except some?

I am trying to get ant4eclipse to work and I have used ant a bit, but not much above a simple scripting language. We have multiple source folders in our Eclipse projects so the example in the ant4eclipse documentation needs adapting:
Currently I have the following:
<target name="build">
<!-- resolve the eclipse output location -->
<getOutputpath property="classes.dir" workspace="${workspace}" projectName="${project.name}" />
<!-- init output location -->
<delete dir="${classes.dir}" />
<mkdir dir="${classes.dir}" />
<!-- resolve the eclipse source location -->
<getSourcepath pathId="source.path" project="." allowMultipleFolders='true'/>
<!-- read the eclipse classpath -->
<getEclipseClasspath pathId="build.classpath"
workspace="${workspace}" projectName="${project.name}" />
<!-- compile -->
<javac destdir="${classes.dir}" classpathref="build.classpath" verbose="false" encoding="iso-8859-1">
<src refid="source.path" />
</javac>
<!-- copy resources from src to bin -->
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset refid="source.path">
<include name="**/*"/>
<!--
patternset refid="not.java.files"/>
-->
</fileset>
</copy>
</target>
The task runs successfully, but I cannot get the to work - it is supposed to copy all non-java files over too to emulate the behaviour of eclipse.
So, I have a pathId named source.path which contains multiple directories, which I somehow needs to massage into something the copy-task like. I have tried nesting which is not valid, and some other wild guesses.
How can I do this - thanks in advance.
You might consider using pathconvert to build a pattern that fileset includes can work with.
<pathconvert pathsep="/**/*," refid="source.path" property="my_fileset_pattern">
<filtermapper>
<replacestring from="${basedir}/" to="" />
</filtermapper>
</pathconvert>
That will populate ${my_fileset_pattern} with a string like:
1/**/*,2/**/*,3
if source.path consisted of the three directories 1, 2, and 3 under the basedir. We're using the pathsep to insert wildcards that will expand to the full set of files later.
The property can now be used to generate a fileset of all the files. Note that an extra trailing /**/* is needed to expand out the last directory in the set. Exclusion can be applied at this point.
<fileset dir="." id="my_fileset" includes="${my_fileset_pattern}/**/*">
<exclude name="**/*.java" />
</fileset>
The copy of all the non-java files then becomes:
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset refid="my_fileset" />
</copy>
That will copy the source files over retaining the source directory structure under todir. If needed, the flatten attribute of the copy task can be set to instead make all the source files copy directly to todir.
Note that the pathconvert example here is for a unix fileseystem, rather than windows. If something portable is needed, then the file.separator property should be used to build up the pattern:
<property name="wildcard" value="${file.separator}**${file.separator}*" />
<pathconvert pathsep="${wildcard}," refid="source.path" property="my_fileset">
...
You could use the foreach task from the ant-contrib library:
<target name="build">
...
<!-- copy resources from src to bin -->
<foreach target="copy.resources" param="resource.dir">
<path refid="source.path"/>
</foreach>
</target>
<target name="copy.resources">
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset dir="${resource.dir}" exclude="**/*.java">
</copy>
</target>
If your source.path contains file paths as well then you could the if task (also from ant-contrib) to prevent attempting to copy files for a file path, e.g.
<target name="copy.resources">
<if>
<available file="${classes.dir}" type="dir"/>
<then>
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset dir="${resource.dir}" exclude="**/*.java">
</copy>
</then>
</if>
</target>

Resources