ant-contrib for loop task fails - ant

To search for multiple string in a fileset I try to use the ant-contrib for .. loop without success.
The documentation has the following simple example
<project name="testing" default="main" basedir=".">
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="/usr/share/java/ant-contrib-0.3.jar"/>
</classpath>
</taskdef>
<task name=main">
<echo message="The first five letters of the alphabet are:"/>
<for list="a,b,c,d,e" param="letter">
<sequential>
<echo>Letter #{letter}</echo>
</sequential>
</for>
</task>
</project>
That fails with
xTest.xml:12: Problem: failed to create task or type for
Cause: The name is undefined.
What's wrong with this?
Not sure if I need the taskdef for ant-contrib-0.3.jar
Note: ANT is running within Eclipse and it has version: "Apache ANT 1.8.2v20110505-1300"

You need to add the taskdef for ant-contrib-0.3.jar. The ant-contrib installation page tells you how to do so:
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="/usr/share/java/lib/ant-contrib-version.jar"/>
</classpath>
</taskdef>
Doing this, I have the following definitions in build.xml:
<project name="sample" basedir=".">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="C:\\Users\\userdomains\\Downloads\\ant-contrib\\ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<echo message="The first five letters of the alphabet are:"/>
<for list="a,b,c,d,e" param="letter">
<sequential>
<echo>Letter #{letter}</echo>
</sequential>
</for>
</project>
which should now give:
Buildfile: c:\build.xml
[echo] The first five letters of the alphabet are:
[echo] Letter a
[echo] Letter b
[echo] Letter c
[echo] Letter d
[echo] Letter e
BUILD SUCCESSFUL
Total time: 0 seconds

Also the basic example works, the need as described with first posting
To search for multiple strings in a fileset
isn't solved. Here is what I have right now:
<loadfile property="dtdNAMES" srcFile="_dtdNAMES_1.txt"/>
<echo>.:${dtdNAMES}:.</echo>
<target name="main">
<for list="xyz.name,xyz.version,xyz.general,xyz.generalXXX,xyz.ok" param="search4" delimiter=",">
<!--for list="${dtdNames}" param="search4" delimiter=","-->
<!-- do the stuff here with param -->
<sequential>
<fileset id="existing" dir="../src">
<patternset id="files">
<include name="content/**/*.xul"/>
</patternset>
</fileset>
<resourcecount property="count">
<fileset id="matches" dir="../src">
<patternset refid="files" />
<contains text="#{search4}" />
</fileset>
</resourcecount>
<echo message="Found '#{search4}' in files : '${count}'"/>
</sequential>
</for>
</target>
This has 2 problems:
ad 1. the use of <for list=" .. csv .." just outputs a list with all files and one result like this:
[echo] Found 'xyz.name' in files : '3'
[echo] Found 'xyz.version' in files : '3'
[echo] Found 'xyz.general' in files : '3'
[echo] Found 'xyz.generalXXX' in files : '3'
The result '3' belongs to the very first loop with 'xyz.name', and yes there are 3 matches in all files. But the other strings have other matches in all files. There is no 'xyz.generalXXX' string in any file!
Question: How to get correct results for all strings in all files?
ad 2. For flexibility a final solution needs to replace the list string with a property like
<for list="${dtdNames}" param="search4" delimiter=",">
To the property ${dtdNames} is read a string from a srcFile (see above), and yes it's comma separated, no line breaks! And checked with a echo command.
But that reference fails with
[echo] Found '${dtdNames}' in files : '0'
So it seems the <for /> doesn't allow to work with property?
How to write that correctly?

Related

Ant script + parsing csv file

Hi I am having a csv file with 2 lines :
mf1,eg1,eg2,br1,br2
mf2,eg2,eg3,br2,br3
I want to store each comma separated value in separate variables using ant.
I am able to parse lines, but not individual values since list is not supporting nesting.
Below is my script :
<?xml version="1.0" encoding="UTF-8"?>
<project name="ForTest" default="getLine" basedir="."
xmlns:ac="antlib:net.sf.antcontrib">
<taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml"
classpath="C:\Manju\apache-ant-1.8.4\ant-contrib-1.0b3-bin\ant-contrib\ant-contrib-1.0b3.jar" />
<loadfile property="message" srcFile="build_params.csv" />
<target name="getLine">
<ac:for list="${message}" delimiter="${line.separator}" param="val">
<sequential>
<echo>#{val}</echo>
<property name="var1" value=#{val}/>
</sequential>
</ac:for>
</target>
<target name="parseLine" depends="getLine">
<for list=#{val} delimiter="," param="letter">
<sequential>
<echo>#{letter}</echo>
</sequential>
</for>
</target>
</project>
Target parseline is giving error saying for list is expecting open quotes. Help is appreciated.
Have you considered embedding a scripting language like groovy instead? Far simpler compared to fighting ant-contrib.
<project name="demo" default="run">
<target name="run">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
new File("build_params.csv").splitEachLine(",") { fields ->
println "===================="
println "field1: ${fields[0]}"
println "field2: ${fields[1]}"
println "field3: ${fields[2]}"
println "field4: ${fields[3]}"
println "field5: ${fields[4]}"
println "===================="
}
</groovy>
</target>
</project>
You can add a special bootstrap target to install the groovy jar automatically:
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/code
haus/groovy/groovy-all/2.2.1/groovy-all-2.2.1.jar"/>
</target>
For one thing, your parseLine target should start like this:
<for list="#{val}" delimiter="," param="letter">
Note the quotes around #{val}.

ant script throwing an exception while calculating md5

HI I am using ant script to calcalte md5 of two files in a particular folder.This the is the script which i have written
<?xml version="1.0"?>
<project name="Hello World Project" basedir="." default="info">
<property name="cms.dir" value="D:\CMS\webclient\components\CMS\Address\AddressSearch" />
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<target name="info">
<echo>Hello World - Welcome to Apache Ant!</echo>
<fileset id="src.files" dir="${cms.dir}" casesensitive="yes">
<include name="**/*.uim"/>
<include name="**/*.properties"/>
</fileset>
<pathconvert pathsep="${line.separator}" property="sounds" refid="src.files">
</pathconvert>
<echo file="sounds.txt">${sounds}</echo>
<loadfile property="files" srcFile="./sounds.txt"/>
<for list="${files}" delimiter="," param="file1">
<sequential>
<echo>#{file1}</echo>
<checksum file="#{file1}" todir="./checksum" />
</sequential>
</for>
</target>
</project>
The file name is getting printed correctly but when i am using the same file to calculate the md5 it is throwing an exception like this
BUILD FAILED
C:\build.xml:15: The following error occurred while executing this line:
C:\build.xml:18: Could not find file D:\CMS\webclient\components\CMS\Address\Add
ressSearch\CMS_addressSearchPopUp.properties
D:\CMS\webclient\components\CMS\Address\AddressSearch\CMS_addressSearchPopUp.uim
to generate checksum for.
any help regarding this
You are using new line when creating "sounds", but is using comma to split.
<pathconvert pathsep="${line.separator}" property="sounds" refid="src.files">
Then this is written to a file - sounds.txt
Then reads the file, to split using comma. (","
<for list="${files}" delimiter="," param="file1">
If I understood the question correctly, you should split using new line
<for list="${files}" delimiter="${line.separator}" param="file1">

How do I select the first element of a filelist in ant?

How do I take only the first element of an ant <filelist> and also <echo> that filename as a string?
Here's a solution that doesn't require external tasks
<project name="demo" default="run">
<path id="files.path">
<first>
<filelist dir="dir1" files="foo.jar,file1.jar,file2.jar"/>
</first>
</path>
<target name="run">
<pathconvert property="path.output" refid="files.path"/>
<echo message="Output: ${path.output}"/>
</target>
</project>
You will need ant-contrib and the trick used in the code is the fact that properties cannot be changed once they are set.
<for param="file">
<path>
<filelist
id="docfiles"
dir="toto"
files="foo.xml
bar.xml"/>
</path>
<sequential>
<basename property="package" file="#{file}"/>
</sequential>
</for>
<echo>${package}</echo>
EDIT:
An alternative solution is using the break task from Antelope

Ant path convert

Good afternoon
I am running ant to process some code now I have path "com/source/project" in properties but I need to pass "com.source.project" to my java code is there anyway I can convert "/" to "." using ant command
thanks
PropertyRegex task works for you, but you need to install ant-contrib.
<project>
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="./ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<property name="path" value="com/source/project"/>
<echo message="Path=${path}"/>
<propertyregex property="java.package.name"
input="${path}"
regexp="/"
replace="."
global="true"
defaultValue="${path}" />
<echo message="package=${java.package.name}"/>
</project>
Here's some complete project that uses the Ant Plugin Flaka. I also had to replace the ${path.separator} with '.' to start some java classes. See the comments starting with ';'
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:install-property-handler/>
<property name="srcroot" value="path/to/srcrootdir"/>
<property name="classroot" value="path/to/classrootdir"/>
<!-- determine all main classes -->
<fileset dir="${srcroot}" includes="**/*.java" id="mainclasses">
<contains text="public static void main"/>
</fileset>
<!-- iterate over those main classes and
call the corresponding classfile -->
<fl:for var="file" in="split('${toString:mainclasses}', ';')">
<fl:let>
; strip the .java Extension
file = replace(file, '', '.java')
; replace fileseparator with '.'
; on Windows you have to use the following line
; replace(file, '\.', '${file.separator}${file.separator}')
file = replace(file, '\.', '${file.separator}')
</fl:let>
<fl:echo>
starting => #{file} in ${classroot}
</fl:echo>
<java classname="#{file}">
<classpath>
<!--
when using a fileset you'll get a
java.util.zip.ZipException because you're
referencing classfiles and no jars
therefore you have to use
pathelement and location
-->
<pathelement location="${classroot}"/>
</classpath>
</java>
</fl:for>
</project>

can't overwrite reference with ant task using nested reference element

I have a main build file with a path declaration
<path id="path.app.src">
<pathelement location="myfolder/src"/>
</path>
Then i call a task in sub file with <ant>
<ant antfile="subbuild.xml" inheritAll="false" inheritRefs="false">
<reference refid="path.app.src"/>
</ant>
in subbuild.xml i have:
<path id="subpath.app.src">
<pathelement location=".. some locations .."/>
<path refid="path.app.src" />
</path>
In my understanding the call to <ant> with a nested should overwrite path.app.src in subbuild.xml.
But i get an error like: subbuild.xml:xx: Reference path.app.src not found.
Am i doing something wrong ? is it a bug in ant ?
I'm using Apache Ant version 1.7.0 compiled on December 13 2006
Thanks,
Lionel
in fact it seems to have the right behavior now, but i can't explain what i did wrong the first time.
here is the code sample:
build.xml
<?xml version="1.0"?>
<project name="test" default="build" basedir=".">
<path id="mainpath">
<pathelement location="my/main/path"/>
</path>
<target name="build">
<ant antfile="subbuild.xml" target="test">
<reference refid="mainpath" torefid="globalpathid"/>
<reference refid="mainpath" torefid="localtotargetpathid"/>
</ant>
</target>
</project>
subbuild.xml
<?xml version="1.0"?>
<project name="subbuild">
<path id="globalpathid">
<pathelement location="my/sub/location"/>
</path>
<target name="test">
<path id="localtotargetpathid">
<pathelement location="my/target/location"/>
</path>
<property name="p.localtotargetpathid" refid="localtotargetpathid" />
<echo>p.localtotargetpathid: ${p.localtotargetpathid}</echo>
<property name="p.globalpathid" refid="globalpathid" />
<echo>p.globalpathid: ${p.globalpathid}</echo>
</target>
</project>
here is the console log:
$ ant
Buildfile: build.xml
build:
[ant] Parent project doesn't contain any reference 'mainpath'
test:
[echo] p.localtotargetpathid: d:\my\target\location
[echo] p.globalpathid: d:\my\main\path
BUILD SUCCESSFUL
Total time: 0 seconds
we can see globalpathid has been override but not localtotargetpathid, which is the behvior mentioned in the spec.
still I can't explain the first message ...
I think you have an incomplete declaration here in the subbuild file of refid path.app.src.
<path id="subpath.app.src">
<pathelement location=".. some locations .."/>
<path refid="path.app.src" /> <=======
</path>
It should not have the 2nd nested path element () since there is no location associated with it. The way you wrote the main build file to overwrite no reference //other than// this refid looks good to me.

Resources