Ant script + parsing csv file - ant

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}.

Related

Ant Script Loop through property file and replace values dynamically

I got a requirement to loop through some XML files, replace the environment specific values in it and create new set of XML files. The environment specific values are to be taken from property file. I am able to loop through a directory to read all the files and replace some specific value using xmltask as below.
<target name="updateConfig" description="update the configuration" depends="init">
<xmltask todir="${ConfigDestDirectory}" report="false" failwithoutmatch="true">
<fileset dir="${ConfigSourceDirectory}">
<include name="*.xml"/>
</fileset>
<replace path="/:application/:NVPairs/:NameValuePair[:name='Connections/HTTP/HostName']/:value/text()" withXml="localhost"/>
</xmltask>
<echo>Replaced Successfully</echo>
</target>
But I would like to read through a property file and get the path/value from it.
I tried using property selector,property,var as different options for this case and manage to get the path but not the value. Below are the snippet of property file and the target that I am using.
#DEV.properties
HostName.xpath=/:application/:NVPairs/:NameValuePair[:name='Connections/HTTP/HostName']/:value/text()
HostName.value=localhost
<project name="TestBuild" default="ReadPropertyFile" basedir=".">
<target name="init">
<property file="DEV.properties"/>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpath="${xmltaskPath}"/>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${antcontribPath}"/>
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
</target>
<target name="ReadPropertyFile" description="update the configuration" depends="init">
<property file="DEV.properties" prefix="x"/>
<propertyselector property="propertyList" delimiter="," select="\0" match="([^\.]*)\.xpath" casesensitive="true" distinct="true"/>
<for list="${propertyList}" param="sequence">
<sequential>
<propertyregex property="destproperty" input="#{sequence}" regexp="([^\.]*)\." select="\1" />
<property name="tempname" value="${destproperty}.value" />
<var name="localprop" value="${tempname}"/>
<echo> #{sequence} </echo>
<echo> ${x.#{sequence}} </echo>
<echo>destproperty --> ${destproperty}</echo>
<echo>tempname --> ${tempname}</echo>
<echo> localprop --> ${localprop}</echo>
<echo>${x.${localprop}} </echo> <!--This is not working -->
</sequential>
</for>
</target>
It would be really helpful if you guys can throw some light.
Thanks,
Venkat
Would this work better ?
I think you got yourself confused with the "x." prefix.
<project name="TestBuild" default="ReadPropertyFile" basedir=".">
<target name="init">
<property file="DEV.properties"/>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpath="${xmltaskPath}"/>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${antcontribPath}"/>
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
</target>
<target name="ReadPropertyFile" description="update the configuration" depends="init">
<property file="DEV.properties" prefix="x"/>
<local name="propertyList"/>
<propertyselector property="propertyList" delimiter="," select="\1" match="x\.([^\.]*)\.xpath" casesensitive="true" distinct="true"/>
<for list="${propertyList}" param="sequence">
<sequential>
<echo> #{sequence} </echo>
<echo> #{sequence}.xpath = ${x.#{sequence}.xpath} </echo>
<echo> #{sequence}.value = ${x.#{sequence}.value} </echo>
</sequential>
</for>
</target>
</project>

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">

Ant read files in a directory and regex

I am trying to read the names of a set of files in a directory and apply regex to those names and obtain a list with comma seperated values. The names of the files are in the format of build_level1_D1.properties, build_level1.D2.properties, build_level2.D1.properties etc...
I need to read all the file names and apply regex and parse the names to get level1_D1, level1_D2, level2_D1 etc.. I need it in the format of property name="build.levels" value="level1_D1,level1_D2,level2_D1" This is what i tried. Need some pointers and help.
<target name="build-levels-all">
<for param="program">
<path><fileset dir="${root.build.path}/build" includes="*"/>
</path>
<sequential>
<propertyregex override="yes" property="file" input="#{program}" regexp="build\_([^\.]*)" select="\1" />
<echo>${file}</echo>
</sequential>
</for>
<echo>${program}</echo>
<-- This prints the files regexed Level1_D1, level2_D2 etc....But i need to capture it in the format of <property name="build.levels" value="level1_D1,level1_D2,level2_D1" /> -->
</target>
Try using an embedded scripting language, like groovy, to do this kind of complex logic.
<target name="process-files">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
def list = []
new File('build').eachFile() {
def matcher = it.name =~ /(build_level\d_D\d).properties/
list.add matcher[0][1]
}
properties."build.levels" = list.join(",")
</groovy>
</target>
<target name="doSomething" depends="process-files">
<echo>${build.levels}</echo>
</target>
Just like ant-contrib, groovy needs an additional jar. I normally include a "bootstrap" target to install this:
<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/codehaus/groovy/groovy-all/2.1.6/groovy-all-2.1.6.jar"/>
</target>

How to <foreach> in a <macrodef>?

I have a xml just like below:
<data>
<foo>value1</foo>
<foo>value2</foo>
<foo>value3</foo>
</data>
I want to create macrodef which implements below function:
<?xml version="1.0"?>
<project name="OATS" default="execute" basedir=".">
<xmlproperty file="data.xml" collapseAttributes="true"/>
<target name="execute">
<foreach list="${data.foo}" target="runScript" param="script"/>
</target>
<target name="runScript">
<echo>Doing things with ${script}</echo>
</target>
</project>
Anybody knows how to ? Thanks in advance.
xmltask is the best choice in the Ant community for this purpose, and you don't have to define your own macrodef.
So for instance:
<tools:xmltask source="data.xml" report="false" >
<tools:call path="data/foo">
<param name="value" path="text()"/>
<actions>
<echo>Doing things with #{value}</echo>
</actions>
</tools:call>
</tools:xmltask>
I encourage you to read the user manual, for xmltask has lots of options. It basically supports XPath to extract and iterate any portion of your xml. It also supports calls to existing targets in addition to anonymous code blocks (as in the example).
It's just hard to beat.
The following example uses the groovy ANT task
<project name="OATS" default="execute" basedir=".">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
<classpath>
<pathelement location="lib/groovy-all-2.1.0-rc-2.jar"/>
</classpath>
</taskdef>
<target name="execute">
<groovy>
def data = new XmlSlurper().parse(new File("data.xml"))
data.foo.each {
properties["script"] = it
ant.project.executeTarget("runScript")
}
</groovy>
</target>
<target name="runScript">
<echo>Doing things with ${script}</echo>
</target>
</project>
This is my macrodef.
<?xml version="1.0" encoding="UTF-8"?>
<project name="OATS" default="test" basedir=".">
<property environment = "env"/>
<path id = "antcontrib.path">
<fileset file = "${env.ANT_HOME}/../net.sf.antcontrib_1.1.0.0_1-0b2/lib/ant-contrib.jar"/>
</path>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="antcontrib.path"/>
<macrodef name="runOATS">
<attribute name="suite"/>
<attribute name="toDir"/>
<sequential>
<delete dir="#{toDir}"/>
<mkdir dir="#{toDir}"/>
<xmlproperty file="#{suite}" collapseAttributes="true"/>
<for list="${data.foo}" param="script">
<sequential>
<runScript script="#{script}"/>
</sequential>
</for>
</sequential>
</macrodef>
<macrodef name="runScript">
<attribute name="script"/>
<sequential>
<echo>Doing things with #{script}</echo>
</sequential>
</macrodef>
<target name="test">
<runOATS toDir="/OATS/results" suite="data.xml"/>
</target>
</project>

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

Resources