trouble using replaceregexp when replacing string DIR location - ant

I am having trouble in doing this.
there is 1 batch file with this line:
set TEST_DIR=C:\temp\dir1
I just want to set some new value to TEST_DIR
But, when I use in my ant script, it escapes forward slashes and gives this result:
set TEST_DIR=C:homedir2
Instead, I want to give it:
set TEST_DIR=C:\home\dir2
I am using this command:
<replaceregexp file="${MT_BATCH_FILE_LOCATION}\myfile.bat" match="TEST_DIR=C:\\temp\\dir1" replace="TEST_DIR=C:\home\dir2" byline="true" />

You can get the result you want by using this replace pattern:
replace="TEST_DIR=C:\\\\home\\\\dir2"
The reason is that you must escape the backslash once for the regex and once for Java - backslash is an escape character in both those contexts.
In answer to your subsequent questions in comments...
I expect the answer will be the same. You will need to double-escape the backslash in the value of ${new_loc}, i.e. use C:\\\\my_projcode not C:\my_projcode.
If new_loc is coming in as an environment variable, you could use the propertyregex task from ant-contrib to escape backslashes in the value:
<project default="test">
<!-- import ant-contrib -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="C:/lib/ant-contrib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<target name="test">
<!-- load environment variables -->
<property environment="env"/>
<!-- escape backslashes in new_loc -->
<propertyregex property="loc" input="${env.new_loc}" regexp="\\" replace="\\\\\\\\\\\\\\\\" />
<echo message="env.new_loc: ${env.new_loc}"/>
<echo message="loc: ${loc}"/>
<!-- do the replace -->
<replaceregexp file="test.bat" match="TEST_DIR=C:\\temp\\dir1" replace="TEST_DIR=${loc}\\\\home\\\\dir2" byline="true" />
</target>
Output:
c:\tmp\ant>set new_loc=c:\foo\bar
c:\tmp\ant>ant
Buildfile: c:\tmp\ant\build.xml
test:
[echo] new_loc: c:\foo\bar
[echo] env.new_loc: c:\foo\bar
[echo] loc: c:\\\\foo\\\\bar
BUILD SUCCESSFUL
Total time: 0 seconds
c:\tmp\ant>type test.bat
set TEST_DIR=c:\foo\bar\home\dir2

I have found another simple solution use replace instead of replaceregexp.
<replace file="${MT_BATCH_FILE_LOCATION}\myfile.bat"
token='TEST_DIR=C:\temp\dir1'
value='TEST_DIR=${new_loc}\home\dir2' />

Related

Propertyregex to read a CSV line and assign fields to variables

I have a csv/txt file with below entries
abc,123
xyz,678
ijk,921
I'm trying to read the file through for loop and assign first element to var1, and second to var2
var1=abc
var2=123
I need to use these variables to perform some task and return back to the loop to read the next line of the file and assign new values.
Below is what I have, and I'm not able to assign the variable
<loadfile property="message" srcFile="test.txt" />
<target name="compile">
<for param="line" list="${message}" delimiter="${line.separator}">
<sequential>
<echo>#{line}</echo>
<propertyregex property="var1"
input="#line"
regexp="/^(.+?),(.+)/"
select="\1" />
<echo message="${var1}" />
</sequential>
</for>
</target>
Below is the output I get, showing no assignment of value to var1.
[echo] abc,123
[echo] ${var1}
[echo] xyz,678
[echo] ${var1}
[echo] ijk,921
[echo] ${var1}
You have a couple of errors, the below loop body works for me, see output at the end.
The first problem is that the #{line} parameter substitution syntax in the for loop uses an antcontrib macrodef, and the {} brakets are not optional - you had missed them out of the input="" attribute, whereas in the echo task you had included them.
The second problem is that you need not specify enclosing slashes /../ in the rexexp= attribute.
<echo>#{line}</echo>
<propertyregex property="var1"
override="yes"
input="#{line}"
regexp="^(.+?),(.+)"
select="\1"/>
<propertyregex property="var2"
override="yes"
input="#{line}"
regexp="^(.+?),(.+)"
select="\2"/>
<echo message="${var1},${var2}" />
Output:
[echo] abc,123
[echo] abc,123
[echo] xyz,678
[echo] xyz,678
[echo] ijk,921
[echo] ijk,921

ant-contrib for loop task fails

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?

how to escape backslash in ant

I am writing Ant scripts.
I have a property which has the value:
"C\:Program Files\\test1\\test2"
Is there a method in Ant to convert it to:
C:Program Files\test1\test2
You could use : http://ant-contrib.sourceforge.net/tasks/tasks/propertyregex.html
although I am not sure if this will do what you are asking for. Are the backslashes visible when you echo your property?
In any case to use the above task you will have to have ant-contrib installed and simply write a task like this :
<project name="test" default="build">
<!--Needed for antcontrib-->
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<target name="build">
<property name="path" value="C\:Program Files\\test1\\test2"/>
<echo message="Path with slashes : ${path}"/>
<propertyregex property="removed.backslash.property"
input="${path}"
global="true"
regexp="\\(\\|:)"
replace="\1"
/>
<echo message="Path with single slashes : ${removed.backslash.property}"/>
</target>
</project>
Output :
build:
[echo] Path with slashes : C\:Program Files\\test1\\test2
[echo] Path with single slashes : C:Program Files\test1\test2
In addition you could use any of the BSF languages :
http://ant.apache.org/manual/Tasks/script.html
provided you are using jre 1.6 and above.

How to pass multiple parameters to a target in Ant?

I have this dummy target:
<mkdir dir="${project.stage}/release
<war destfile="${project.stage}/release/sigma.war">
...
...
</war>
What I want to do is provide two parameters say "abc" & "xyz" which will replace the word release with the values of abc and xyz parameters respectively.
For the first parameter say abc="test", the code above will create a test directory and put the war inside it.Similarly for xyz="production" it will create a folder production and put the war file inside it.
I tried this by using
<antcall target="create.war">
<param name="test" value="${test.param.name}"/>
<param name="production" value="${prod.param.name}"/>
</antcall>
in the target which depends on the dummy target provided above.
Is this the right way to do this.I guess there must be some way to pass multiple parameters and then loop through the parameters one at a time.
unfortunately ant doesn't support iteration like for or foreach loops unless you are refering to files. There is however the ant contrib tasks which solve most if not all of your iteration problems.
You will have to install the .jar first by following the instructions here : http://ant-contrib.sourceforge.net/#install
This should take about 10 seconds. After you can simply use the foreach task to iterate through you custom list. As an example you can follow the below build.xml file :
<project name="test" default="build">
<!--Needed for antcontrib-->
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<!--Iterate through every token and call target with parameter dir-->
<foreach list="${test},${production}" param="dir" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${dir}"/>
</target>
</project>
Output :
build:
create.war:
[echo] My path is : value_1
create.war:
[echo] My path is : value_2
BUILD SUCCESSFUL
Total time: 0 seconds
I hope it helps :)
Second solution without using ant contrib. You could encapsulate all your logic into a macrodef and simply call it twice. In any case you would need to write the two parameters at some point in your build file. I don't think there is any way to iterate through properties without using external .jars or BSF languages.
<project name="test" default="build">
<!--Needed for antcontrib-->
<macrodef name="build.war">
<attribute name="dir"/>
<attribute name="target"/>
<sequential>
<antcall target="#{target}">
<param name="path" value="#{dir}"/>
</antcall>
</sequential>
</macrodef>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<build.war dir="${test}" target="create.war"/>
<build.war dir="${production}" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${path}"/>
</target>
</project>
I admit that I don't understand the question in detail. Is ${project.stage} the same as the xyz and abc parameters? And why are there two parameters xyz and abc mentioned, when only the word "release" should be replaced?
What I know is, that macrodef (docu) is something very versatile and that it might be of good use here:
<project name="Foo" default="create.wars">
<macrodef name="createwar">
<attribute name="stage" />
<sequential>
<echo message="mkdir dir=#{stage}/release " />
<echo message="war destfile=#{stage}/release/sigma.war" />
</sequential>
</macrodef>
<target name="create.wars">
<createwar stage="test" />
<createwar stage="production" />
</target>
</project>
The output will be:
create.wars:
[echo] mkdir dir=test/release
[echo] war destfile=test/release/sigma.war
[echo] mkdir dir=production/release
[echo] war destfile=production/release/sigma.war
Perhaps we can start from here and adapt this example as required.

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>

Resources