In ant, I have defined some properties that define some paths (absolute) needed in my build system.
Most of ant tasks need filesets, so to build a fileset from a property I would have to do:
<fileset dir="" includes="${myprop}"/>
The problem is that myprop
is absolute and I should omit the dir attribute (which is not possible), so is there a way to define (absolute) properties and efficiently use them to create filesets, dirsets, etc.. or in ant is this a bad practice (only relative paths should be used)?
Thanks.
There's no particular rules about absolute versus relative with Ant. You should avoid hard-coding absolute paths if possible - to make your build more portable. If you have to use absolute paths for some part of the build, try to construct them - say from the ${basedir}
of the project - so that changes are easier to make.
Two things that may be useful for converting absolute paths to relative paths for use in filesets and the like:
- the
property
task supports an attribute relative=
that can be used to convert from an absolute path to relative.
- the
pathconvert
task can be used to do the same, when there are several absolute paths in one property.
Examples:
<!-- Absolute paths -->
<property name="myprop" value="${basedir}/x" />
<property name="myprop2" value="${basedir}/x:${basedir}/y" />
<!-- Convert single path to relative to basedir -->
<property name="myprop_rel" location="${myprop}" relative="yes"/>
<!-- Go via path/pathconvert for the property with multiple paths -->
<path id="mypath2" path="${myprop2}" />
<pathconvert property="myprop2_rel" refid="mypath2" pathsep=",">
<map from="${basedir}/" to="" />
</pathconvert>
<fileset id="my_fileset" dir="." includes="${myprop2_rel}" />
In response to a comment: I'm not aware of a simple way to get the longest common prefix directory of a fileset in Ant,
but here's a macro wrapping a script task that does what you might call 'shrink wrapping'.
You call it with a reference to the 'input' fileset, and the name of the property to set.
<macrodef name="common-prefix-dir">
<attribute name="refid" />
<attribute name="outputproperty" />
<sequential>
<script language="javascript"><![CDATA[
srcFiles = project.getReference( "@{refid}" )
.getDirectoryScanner( project )
.getIncludedFiles( );
if ( srcFiles.length > 0 ) {
prefix = "" + srcFiles[0];
for ( i = 0; i < srcFiles.length; i++ ) {
while ( prefix.length && srcFiles[i].substr( 0, prefix.length ) != prefix ) {
prefix = prefix.substr( 0, prefix.length - 1);
}
if ( !prefix.length ) {
break;
}
}
}
else {
prefix = "";
}
prefix = prefix.substring( 0, prefix.lastIndexOf( '/' ) );
project.setProperty( "@{outputproperty}", prefix );
]]></script>
</sequential>
</macrodef>
(This was derived from a php implementation.)
You can try it out with something like:
<property name="my.dir" location="...your dir here..." />
<fileset id="my.fs" dir="${my.dir}">
<!-- define fileset here -->
</fileset>
<echo message="Input fileset is: '${toString:my.fs}'" />
<common-prefix-dir refid="my.fs" outputproperty="prefix" />
<echo message="Longest common prefix is: '${prefix}'" />
The pathconvert
task can now be used to create a shrink-wrapped fileset:
<pathconvert property="shrink" refid="my.fs" pathsep=",">
<map from="${my.dir}/${prefix}/" to="" />
</pathconvert>
<fileset id="my.fs.out" dir="${my.dir}/${prefix}" includes="${shrink}" />
<echo message="Shrink-wrapped fileset is: '${toString:my.fs.out}'" />
I would suggest you to use a different property for the dir
target, if you are doing an absolute reference to ${myprop}, I guess it's a file name. Try it separating it into ${parent.dir} and ${target.filename}.
<fileset dir="${parent.dir}" includes="${target.filename}"/>