Multiple ANT properties (from file) into the one property - ant

I use task to run a target for all values from the list, taken from one property.
<foreach list="val1,val2" delimiter="," target="my.target" param="param_name"/>
Now, I want to put those values to the separate properties file as there is a lot of them.
So the question is: how can I read multiple (don't know how many) properties (lines in file in fact) from the file into one property?
The property file should look like this:
val1
val2
anothervalue
foobar
And the output should be:
"val1,val2,anothervalue,foobar"
be put in one property.

You can achieve this using LineTokenizer filter with loadfile. For example:
<target name="t">
<loadfile property="data_range" srcFile="ls.txt">
<filterchain> <!-- this filter outputs lines delimited by "," -->
<tokenfilter delimoutput=","/>
</filterchain>
</loadfile>
<foreach list="${data_range}" param="line" delimiter="," target="print" />
</target>
<target name="print">
<echo>line [${line}]</echo> <!-- you can do anything here -->
</target>

Related

Override fileset ref in ANT

I have populated a fileset at the start of script as follows;
<!-- Define the list of projects to be built -->
<fileset id="ivy.buildlist.fileset" dir="${ivy.buildlist.dir}" includes="${ivy.buildlist.includes}" excludes="${ivy.buildlist.excludes}" />
But I want to update this ref if user select a particular task. For that I have written a new target with <intersect> which will be called but its not updating the reference;
<target name="getPreReleaseList" description="Target to override the component list for pre release" >
<echo message="Existing List : ${toString:ivy.buildlist.fileset}" />
<intersect>
<fileset refid="ivy.buildlist.fileset" />
<fileset dir="${ivy.buildlist.dir}"
includes="${ivy.pre.buildlist.includes}"
excludes="${ivy.pre.buildlist.excludes}" />
</intersect>
<echo message="Updated List : ${toString:ivy.buildlist.fileset}" />
</target>
Before and after list in ivy.buildlist.fileset is same :(. Am I missing anything or do I have adapt a different approach.
Your problem is due to the fact that ant properties are immutable.
In order to modify a property, you could either use the variable task or use a macrodef.
I suggest you take a look at the following question for more detail.

Create a fileset from a semicolon-separated list in a property

I have an ant property ${src.dirs} that contains a list of dirs separated by a semi colon.
Now i need to specify fileset (for replaceregexp) and that fileset has to contain all java files from all dirs listed in ${src.dirs}.
How can i do it (I don't use any ant-contrib funcky stuff, I use plain vanilla ant).
The src.dirs have this form: /usr/work/dir1/src;/usr/work/java/dir2/src;/usr/libabc/src
There's is an example on how to use propertyregex, but when I try to use it I get this error:
build.xml:98: Problem: failed to create task or type propertyregex
Edit:
Here's what was my final solution:
<loadresource property="source.dir.javafiles">
<propertyresource name="source.dir"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="\s*([;,]\s*)*$" replace="/**/*.java"/>
<replaceregex pattern="\s*([;,]\s*)+" replace="/**/*.java," flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
<fileset dir="" includes="${source.dir.javafiles}"/>
These regexes ensure that trailing commas or semicolons don't produce wrong fileselectors.
You might be able to do this without using ant-contrib. Here's a possibility:
<property
name="dirlist"
value="/usr/work/dir1/src;/usr/work/java/dir2/src;/usr/libabc/src" />
<property name="file.wildcard" value="*.java" />
<loadresource property="dirs.include">
<propertyresource name="dirlist"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="^/" replace="" />
<replaceregex pattern=";/" replace="/**/${file.wildcard}," flags="g"/>
<replaceregex pattern="$" replace="/**/${file.wildcard}" />
</tokenfilter>
</filterchain>
</loadresource>
<fileset id="files" dir="/" includes="${dirs.include}" />
The work is split into two: first string processing to convert the semicolon-separated list into patterns suitable for use in a fileset includes attribute; second make a fileset from the pattern.
The loadresource task here is simply being used as a wrapper around a sequence of simple regular expression replacements. The three replacements deal with the leading root directory \, expanding the intra-string semicolons into Ant patterns and commas (which are used in includes attributes to separate entries), and adding a pattern at the end of the string.
In your case you might consider tuning this to not use the root directory in the dir attribute of the fileset.
propertyregex is from ant-contrib, which is why the example is not working for you.
Here is one way to achieve what you want.
<pathconvert property="src.dirs.includes" pathsep="/**/*.java,">
<path path="${src.dirs}" />
</pathconvert>
<replaceregexp match="\s+" replace=" " flags="g" byline="true">
<files id="files" includes="${src.dirs.includes}/**/*.java" />
</replaceregexp>
However spaces in any of the filenames (including their path) will stuff you up.
Do you simply have to go through these directories and do your compile, or must these directories be compiled together because of dependencies?
If there are no dependencies, you could try the <for/> task in Ant-Contrib. This lets you loop through a list like the one you have:
<for list="${src.dirs}"
param="my.src.dir"
delimiter=";">
<sequential>
<javac destdir="${javac.destdir}"
srcdir="#{my.src.dir}"
classpathref="main.classpath"/>
</sequential>
</for>
Of course, you might have to munge things for your correct destdir. You may find the <var/> task convenient when you use the <for/> task. The <var/> task allows you to reset variable names. When you repeat the <sequential/> set of tasks, you may find you want to reset certain properties.
By the way, if you have Ant 1.8 or higher, you can use the <local/> task instead of <var/>.

how to call multiple ant targets for foreach

here is what am trying to do, I want to replace name and address from my large number of property files during build, but unfortunately I cant do this, is there a better way of doing this without having to copy paste the foreach twice. can someone help?
<target name="replace" >
<foreach target="replace.name,replace.address" param="foreach.file" inheritall="true">
<path>
<fileset dir="${build.tmp.dir}/resource">
<!-- some complicated conditions go here -->
</path>
</foreach>
</target>
<target name="replace.address">
<echo>replacing #Address# for ${foreach.file}</echo>
<replace file="${foreach.file}" token="#Address#" value="${address}" />
</target>
<target name="replace.name">
<echo>replacing #Name# for ${foreach.file}</echo>
<replace file="${foreach.file}" token="#Name#" value="${Name}" />
</target>
.properties file looks like
name=#Name#
address=#Address#
target of foreach is not designed to take more than one target name. It only iterates through the provided list, not the provided targets.
To make the implementation more DRY, you may
use a for loop instead of foreach with two antcalls;
use macrodef with for loop -- macrodef can pack several ant xml code into a task-like thing
Actually, for the two targets -- replace.address and replace.name, are you sure that you want to call them from the commandline?
If not, name them -replace.address and -replace.name or use macrodef -- exposing the iteration body of foreach is not a good practice.

Ant Fileset to Comma Separated List

I'm trying to pass a fileset to a macrodef, and have the macro generate a comma separated list of the classes. More over, I also need to change the list to contain java package & class names instead of "/" delimmited names.
We're using Ant, OSGi, and bnd and what I'm ultimately trying to do is create an entry in the Manifest that contains the fully qualified class name of each entry of the fileset.
End Goal example:
Manifest-Entry: org.foo.bar.ClassOne, org.foo.bar.ClassTo
You could do this using the Ant pathconvert task with a nested mapper, for example:
<property name="classes" location="classes" />
<fileset dir="${classes}" id="classes" />
<pathconvert dirsep="." refid="classes" property="manifest.entry" pathsep=", ">
<mapper type="regexp" from="${classes}/(.*).class" to="\1" />
</pathconvert>
<echo message="Manifest-Entry: ${manifest.entry}" />
Since you are using bnd, you could also try using the ${classes} macro in the bnd file.

How do I remove non-tokens during copy in Ant?

I have files that I need cleaned up during the build process. There is a fixed string that I need removed everywhere it appears. The files are being copied so during that copy I tried including a filterset where the token is the text to be removed and the value is the empty string. This didn't work because I set begintoken and endtoken to the empty string and Ant didn't like that.
This is not a one time operation so it needs to be part of the build process. The files contain SQL INSERT statements and are used to populate tables at runtime. Each line references the schema plus the table name and I need just the table name, e.g.
insert into Schema1.Table1 ...
should be
insert into Table1 ...
Thank you!
Use a nested filterchain with tokenfilter, something like =
<copy todir="...">
<fileset dir="..." />
<filterchain>
<tokenfilter>
<replacestring from="Schema1." to="" />
</tokenfilter>
</filterchain>
</copy>
if you need regexp for replacement use =
...
<tokenfilter>
<replaceregex pattern="..." replace="..." flags="".../>
</tokenfilter>
...
instead.

Resources