Remove last three character from ant property - ant

I have an ant property which has value of the abcdefghijklmn
I want to remove the last three character from the property to abcdefghijk.
Please help.

Example
build:
[echo] x = abcdefghijklmn
[echo] y = abcdefghijk
build.xml
<project name="demo" default="build">
<property name="x" value="abcdefghijklmn"/>
<target name="build">
<script language="javascript">
project.setProperty("y", project.getProperty("x").substr(0,11));
</script>
<echo message="x = ${x}"/>
<echo message="y = ${y}"/>
</target>
</project>

Related

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?

Pretty-printing comma-separated list of strings in ant

I have a comma-separated string in an ant property, like this:
<property name="prop" value="a,b,c"/>
I would like to be able to print or log it like this:
Line 1: a
Line 2: b
Line 3: c
Doesn't sound like it should be too difficult, but I cannot figure out which ant components I should be putting together.
You can do this by using loadresource specifying the property value as a string resource. Now you can use a replaceregex filter to convert comma to newline.
<project default="test">
<property name="prop" value="a,b,c"/>
<target name="test">
<loadresource property="prop.fmt">
<string value="${prop}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="," replace="${line.separator}" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
<echo message="${prop.fmt}"/>
</target>
</project>
The output is:
test:
[echo] a
[echo] b
[echo] c
The sample using Ant-Contrib Tasks
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<target name="test_split">
<property name="prop" value="a,b,c"/>
<for list="${prop}" param="letter">
<sequential>
<echo>#{letter}</echo>
</sequential>
</for>
</target>
The output is:
a
b
c
Another solution from here:
<scriptdef name="split" language="javascript">
<attribute name="value"/>
<attribute name="delimiter"/>
<attribute name="prefix"/>
<![CDATA[
values = attributes.get("value").split(attributes.get("delimiter"));
for(i=0; i<values.length; i++) {
project.setNewProperty(attributes.get("prefix")+i, values[i]);
}
]]>
</scriptdef>
<target name="test_split2">
<property name="prop" value="a,b,c"/>
<property name="prefix_str" value="Line_"/>
<split value="${prop}" delimiter="," prefix="${prefix_str}"/>
<echoproperties prefix="${prefix_str}"/>
</target>
The output is:
Ant properties
Tue Nov 22 17:12:55 2011
Line_0=a
Line_1=b
Line_2=c

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 strings comparison

I have a script in ant, and I need to compare 2 strings lexicographically.
something like:
"1.2.3".compareTo("1.2.4")
I can't find a way to do so... Any ideas? I'm using ant 1.8, and ant-contrib.
Thanks
For this solution to work you will need to have your JAVA_HOME pointing to JRE 1.6 or later.
<project name="test" default="test">
<scriptdef name="compare" language="javascript">
<attribute name="lhs" />
<attribute name="rhs" />
<attribute name="property" />
<![CDATA[
var lhs = attributes.get("lhs");
var rhs = attributes.get("rhs");
project.setProperty(attributes.get("property"), lhs > rhs);
]]>
</scriptdef>
<target name="test">
<compare lhs="1.2.3" rhs="1.2.4" property="result"/>
<echo message="Result is : ${result}"/>
</target>
</project>
Output :
test:
[echo] Result is : false

Retrieve property value from include'd / import'ed project

I am trying to use ant's include or import tasks to use a common build file. I am stuck at retrieving properties from included file.
These are my non-working samples, trying to retrieve "child-property"
Using ant import
parent file
<?xml version="1.0" encoding="UTF-8"?>
<project name="parent" basedir=".">
<import file="child.xml" />
<target name="parent-target">
<antcall target="child-target" />
<echo message="(From Parent) ${child-property}" />
</target>
</project>
child file
<?xml version="1.0" encoding="UTF-8"?>
<project name="child" basedir=".">
<target name="child-target">
<property name="child-property" value="i am child value" />
<echo message="(From Child) ${child-property}" />
</target>
</project>
output
parent-target:
child-target:
[echo] (From Child) i am child value
[echo] (From Parent) ${child-property}
Using ant include
parent file
<project name="parent" basedir=".">
<include file="child.xml" />
<target name="parent-target">
<antcall target="child.child-target" />
<echo message="(From Parent) ${child-property}" />
<echo message="(From Parent2) ${child.child-property}" />
</target>
</project>
child file
same as above
output
parent-target:
child.child-target:
[echo] (From Child) i am child value
[echo] (From Parent) ${child-property}
[echo] (From Parent2) ${child.child-property}
How can I access "child-property" from parent?
When you use the antcall task a new Ant cycle is started for the antcall'ed task - but that doesn't affect the context of the caller:
The called target(s) are run in a new
project; be aware that this means
properties, references, etc. set by
called targets will not persist back
to the calling project.
One way to make your simple example to work would be to change the first parent to:
<target name="parent-target" depends="child-target">
<echo message="(From Parent) ${child-property}" />
</target>
Then the child-target will be executed in the parent context before the parent-target.
But, you may find that there are side affects to running the child task in the context of the parent that you don't want.
It is a different approach but you may use macrodef.
parent.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="parent" basedir=".">
<import file="child.xml"/>
<target name="parent-target">
<child-macro myid="test"/>
<echo message="(From Parent) ${child-property}" />
</target>
child.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="child" basedir=".">
<macrodef name="child-macro">
<attribute name="myid" default=""/>
<sequential>
<property name="child-property" value="i am child value" />
<echo message="(From Child) ${child-property}" />
<echo message="Received params: myId=#{myid}"/>
</sequential>
</macrodef>
</project>
output
parent-target:
[echo] (From Child) i am child value
[echo] Received params: myId=test
[echo] (From Parent) i am child value
Ant-contrib's runtarget task has sufficiently solved my problem. It mignt not be suitable for others since it runs the target in parent's context. Guess there is no "one solution for all" for these kind of problems until Ant officially supports variables.
Parent
<project name="parent" basedir=".">
<!-- insert necessary antcontrib taskdef here-->
<include file="child.xml" />
<target name="parent-target">
<var name="x" value="x"/>
<runtarget target="child.child-target"/>
<echo message="From Parent: ${x}"/>
</target>
</project>
Child
<project name="child" basedir=".">
<property name="pre" value="childpre" />
<target name="child-target">
<var name="x" value="${x}y" />
</target>
</project>
Output
parent-target:
child.child-target:
[echo] From Parent: xy

Resources