how to escape backslash in ant - 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.

Related

String replacement using propertyregex

Need your advice on string replacement using ant propertyregex function.
I actually need to manipulate classpath file content by replacing certain section of the folder to the new folder and and remove some folder paths.
The actual content of the class path looks like:
/usr/home/folder1/com/codahale/metrics/metrics-core/3.0.2/metrics-core-3.0.2.jar:/usr/home/folder1/javax/ws/rs/javax.ws.rs-api/2.0-m10/javax.ws.rs-api-2.0-m10.jar:/etc/lib/:/usr/java/lib
which should eventually look like
/var/home/newfolder/metrics-core-3.0.2.jar:/var/home/newfolder/javax.ws.rs-api-2.0-m10.jar:/etc/lib/:/usr/java/lib
Basically, whichever string contains /usr/home/folder1, the new folder name should be prefixed to the jar file. The classpath contains 500 different groupId, artifactId with /usr/home/folder1 as the base
I am trying to replace the string in the classpath property from /usr/home/folder1/ to /var/home/newfolder/ as below. Not sure if something is wrong here, but this totally doesn't work..
<target name="classpath-generate">
<propertyregex property="compileclasspath" input="${compileclasspath}" regexp="/usr/home/folder1/" replace="/var/home/newfolder/" defaultValue="${compileclasspath}"/>
</target>
Also, need some help on how to extract just the jar filename and prefix the new foldername.
Highly appreciate your input on this !!
No need for extra libraries like antcontrib or regular expressions.
Use ant api via script task with builtin JavaScript engine (since JDK 1.6.0_06) like that :
<project>
<property name="compileclasspath" value="/usr/home/folder1/com/codahale/metrics/metrics-core/3.0.2/metrics-core-3.0.2.jar:/usr/home:/usr/home/folder1/com/codahale/metrics/metrics-core/bla.jar"/>
<property name="replacefrom" value="/usr/home/folder1/com/codahale/metrics/metrics-core"/>
<property name="replaceto" value="/var/home/newfolder"/>
<echo>
$${compileclasspath} initial :
${compileclasspath}
</echo>
<script language="javascript">
//set newProperty
project.setProperty('foobar', project.getProperty('compileclasspath').replace(project.getProperty('replacefrom'), project.getProperty('replaceto')));
// overwrite existing property
project.setProperty('compileclasspath', project.getProperty('compileclasspath').replace(project.getProperty('replacefrom'), project.getProperty('replaceto')));
</script>
<echo>
$${compileclasspath} changed :
${compileclasspath}
new Property $${foobar} :
${foobar}
</echo>
</project>
output :
[echo] ${compileclasspath} initial :
[echo] /usr/home/folder1/com/codahale/metrics/metrics-core/3.0.2/metrics-core-3.0.2.jar:/usr/home:/usr/home/folder1/com/codahale/metrics/metrics-core/bla.jar
[echo]
[echo] ${compileclasspath} changed :
[echo] /var/home/newfolder/3.0.2/metrics-core-3.0.2.jar:/usr/home:/var/home/newfolder/bla.jar
[echo] new Property ${foobar} :
[echo] /var/home/newfolder/3.0.2/metrics-core-3.0.2.jar:/usr/home:/var/home/newfolder/bla.jar
[echo]
To extract the jar names you might use something like :
<project>
<property name="compileclasspath" value="/usr/home/folder1/com/codahale/metrics/metrics-core/3.0.2/metrics-core-3.0.2.jar:/usr/home:/usr/home/folder1/com/codahale/metrics/metrics-core/bla.jar"/>
<script language="javascript">
<![CDATA[
var cpitems = project.getProperty('compileclasspath').split(':');
var jars = "";
for (i=0; i < cpitems.length; i++) {
if(cpitems[i].split('/')[(cpitems[i].split('/')).length -1].endsWith('.jar'))
{
jars += cpitems[i].split('/')[(cpitems[i].split('/')).length -1] + ','
}
}
project.setProperty('cpjars', jars.substring(0, jars.length - 1));
]]>
</script>
<echo>$${cpjars} => ${cpjars}</echo>
</project>
output :
[echo] ${cpjars} => metrics-core-3.0.2.jar,bla.jar
Below is an Ant script that uses Ant's built-in file name mapping functionality:
build.xml
<project name="ant-classpath-mapper" default="run">
<property
name="original-classpath"
value="/usr/home/folder1/com/codahale/metrics/metrics-core/3.0.2/metrics-core-3.0.2.jar:/usr/home/folder1/javax/ws/rs/javax.ws.rs-api/2.0-m10/javax.ws.rs-api-2.0-m10.jar:/etc/lib/:/usr/java/lib"
/>
<target name="run">
<pathconvert property="modified-classpath">
<path>
<pathelement path="${original-classpath}"/>
</path>
<firstmatchmapper>
<regexpmapper
from="/usr/home/folder1/.*?([^/]+\.jar)$"
to="/var/home/newfolder/\1"
/>
<identitymapper/>
</firstmatchmapper>
</pathconvert>
<echo>${modified-classpath}</echo>
</target>
</project>
Output
run:
[echo] /var/home/newfolder/metrics-core-3.0.2.jar:/var/home/newfolder/javax.ws.rs-api-2.0-m10.jar:/etc/lib:/usr/java/lib
The <regexpmapper> matches the paths that start with "/usr/home/folder1".
The <regexpmapper> won't match paths such as "/etc/lib/" and "/usr/java/lib". The <firstmatchmapper> ensures that these paths will get matched by the following <identitymapper>.

ant warning : could not load antlib.xml

I have the antcontrib.jar in my lib folder of Ant. I set my ant home as "C/Prog Files/apache-ant".
But still when I run my build.xml, i get the warning "could not load antlib.xml and antcontrib.prop".
Because of this, I am not able to do any "regex" operations.
I properly loaded the antcontrib.jar in the lib folder of the ant.
Where I am wrong here?
Provide resource and classpath in your taskdef correctly as follows
<typedef resource="net/sf/antcontrib/antlib.xml" classpath="<path to ant-contrib.jar>"/>
Here's an example of an Ant script that uses Ant-Contrib's <propertyregex> task:
build.xml
<project name="ant-propregex-simple" default="run">
<taskdef resource="net/sf/antcontrib/antlib.xml" />
<target name="run">
<property name="line.to.test" value="First Second" />
<property name="the.regex" value="^([^ ]*) ([^ ]*)$" />
<propertyregex
input="${line.to.test}"
regexp="${the.regex}"
select="\2"
property="the.match"
/>
<echo>${the.match}</echo>
</target>
</project>
The key is the <taskdef ...> line.
Output
run:
[echo] Second
BUILD SUCCESSFUL

How to create a Java file dynamically into certain package using Ant concat task?

I have an Ant script file in which I use concat task to create a Java cource file in the specified package which is defined in a properties file.
For example, I define the package name:
ma.package=com.my.package
In Ant script, I call:
<concat destfile="./${prject.root}/${ma.package}/MyClass.java">
However, MyClass.java was created in a subfolder com.my.package, instead of folder structure com\my\package. How to fix it?
I use Eclipse Helios under Windows XP.
You can use a PathConvert with a nested UnpackageMapper to convert the package name to a path. For example:
<project default="test">
<property name="ma.package" value="com.my.package"/>
<target name="test">
<pathconvert property="ma.package.dir">
<path path="${ma.package}"/>
<unpackagemapper from="*" to="*"/>
</pathconvert>
<echo message="ma.package : ${ma.package}"/>
<echo message="ma.package.dir : ${ma.package.dir}"/>
</target>
</project>
The output is:
Buildfile: C:\tmp\ant\build.xml
test:
[echo] ma.package : com.my.package
[echo] ma.package.dir : C:\tmp\ant\com\my\package
So you could use the converted property value in your concat:
<concat destfile="${ma.package.dir}/MyClass.java">

trouble using replaceregexp when replacing string DIR location

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' />

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.

Resources