In Ant, how can I test if a property ends with a given value? - ant

In Ant, how can I test if a property ends with a given value?
For example
<property name="destdir"
value="D:\FeiLong Soft\Essential\Development\repository\org\springframework\spring-beans" />
how can I test if ${destdir} ends with "spring-beans"?
additional:
In my ant-contrib-1.0b3.jar, without 'endswith' task~~

You can test if ${destdir} ends with "spring-beans" like this (assuming you have ant-contrib, and are using Ant 1.7 or later).
<property name="destdir" value="something\spring-beans" />
<condition property="destDirHasBeans">
<matches pattern=".*spring-beans$" string="${destdir}" />
</condition>
<if>
<equals arg1="destDirHasBeans" arg2="true" />
<then>
$destdir ends with spring-beans ...
</then>
<else> ...
</else>
</if>
The '$' in the regex pattern ".*spring-beans$" is an anchor to match at the end of the string.

As Matteo, Ant-Contrib contains a lot of nice stuff, and I use it heavily.
However, in this case can simply use the <basename> task:
<basename property="basedir.name" file="${destdir}"/>
<condition property="ends.with.spring-beans">
<equals arg1="spring-beans" arg2="${basedir.name}"/>
<condition>
The property ${ends.with.spring-beans} will contain true if ${destdir} ends with string-beans and false otherwise. You could use it in the if or unless parameter of the <target> task.

You can use the EndWith condition from Ant-Contrib
<endswith string="${destdir}" with="spring-beans"/>
For example
<if>
<endswith string="${destdir}" with="spring-beans"/>
<then>
<!-- do something -->
</then>
</if>
Edit
<endswith> is part of the Ant-Contrib package that has to be installed and enabled with
<taskdef resource="net/sf/antcontrib/antlib.xml"/>

The JavaScript power can be used for string manipulation in the ANT:
<script language="javascript"> <![CDATA[
// getting the value for property sshexec.outputproperty1
str = project.getProperty("sshexec.outputproperty1");
// get the tail , after the separator ":"
str = str.substring(str.indexOf(":")+1,str.length() ).trim();
// store the result in a new property
project.setProperty("res",str);
]]> </script>
<echo message="Responce ${res}" />

Related

Ant - String contains within an array of String

I am basically trying to do the following thing in Ant (v1.9.4):
I have a list of fixed string like {a,b,c,d} --> First how should I declare this in Ant?
Then I have an input parameter such as ${mystring} and I want to check if the variable value is in my list. Which means in this example, if the variable value is equals to a or b or c or d.
If so return true else false (or 0 and 1 something like that).
Is there a simple way to do that?
Thanks,
Thiago
Use ant property task to declare your stringlist.
Use ant contains condition to check whether list contains a specific item.
Something like :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- fail if 'foobaz' is missing -->
<fail message="foobaz not in List => [${csvprop}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</project>
Or wrap it in a macrodef for resuse :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<fail message="#{item} not in List => [#{list}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
-- EDIT --
From ant manual condition :
If the condition holds true, the property value is set to true by default; otherwise, the property is not set. You can set the value to something other than the default by specifying the value attribute.
So simply use a condition to create a property that is either true or not set, f.e. combined with the new if/unless feature introduced with Ant 1.9.1 :
<project
xmlns:if="ant:if"
xmlns:unless="ant:unless"
>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<condition property="itemfound">
<contains string="${csvprop}" substring="foobaz"/>
</condition>
<!-- echo as example only instead of
your real stuff -->
<echo if:true="${itemfound}">Item #{item} found => OK !!</echo>
<echo unless:true="${itemfound}">Warning => Item #{item} not found !!</echo>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
output :
[echo] Warning => Item foobaz not found !!
Note that you need the namespace declarations to activate the if/unless feature.

exception when using if statment in ant script

I am trying to compare the value of a properties variable with a string as following
<if>
<equals "${mat.projectName}"="seal">
<then>
When done so, I'm getting following message.
Element type "equals" must be followed by either attribute specifications,">" or
"/>"
I'm using eclipse framework to do this.
Read the manual first:
http://ant.apache.org/manual/Tasks/conditions.html
clearly, from the manual we know for equals:
arg1 First value to test
arg2 Second value to test
So it should be
<if>
<equals arg1="${mat.projectName}" arg2="seal" />
<then>
...
I recommend you to read guides about XML first, and then, Ant's manual.
Update:
<if> task is not provided by Ant; it is provided by Ant-Contrib. So you need <taskdef>.
For example, I have ant-contrib.jar put in my project's lib directory (${basedir}/lib), so I can write the following:
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="lib/ant-contrib.jar"/>
</classpath>
</taskdef>
For more, you can check taskdef's manual page, as well as Ant-contrib's webpage:
http://ant.apache.org/manual/Tasks/taskdef.html
http://ant-contrib.sourceforge.net/
Exactly what you're error message says...
Element type "equals" must be followed by either attribute specifications,">" or "/>"
You want this:
<if>
<equals arg1="${mat.projectName}" arg2="seal"/>
<then>
<yadda, yadda, yadda/>
</then>
</if>
This is XML, so you need parameters with values. Take a look at the equals condition on this page. It takes two parameters.
Notice the format of the <if>. The condition ends with a />. The <then> is a sub-entity of the <if>, and the if clause is a sub-entity of the <then> clause. Notice that you basically indent twice.
If you're doing a not equals condition, it would look like this:
<if>
<not>
<equals arg1="${mat.projectName}" arg2="seal"/>
</not>
<then>
<yadda, yadda, yadda/>
</then>
</if>

Ant: how to write optional nested elements

Say that I need to do something like:
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<if>
<equals arg1="${SPECIAL_BUILD}" arg2="true"/>
<then>
<fileset dir="dir7" />
<fileset dir="dir8" />
...
</then>
</if>
</copy>
(The real task is not copy, I'm just using it to illustrate the point.)
Ant will complain that my task doesn't support nested <if> which is fair enough. I've been thinking along these lines:
I could add a macrodef with an "element" attribute like this:
<macrodef name="myCopy">
<element name="additional-path" />
<sequential>
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<additional-path/>
</copy>
</sequential>
</macrodef>
But that would mean that the caller (target) must specify the additional path which I want to avoid (if many targets call this task, they would have to repeat the fileset definitions in the additional-path element).
How to code the additional filesets inside the macrodef so that Ant doesn't complain?
AntContrib has an Ant FileSet object augmented with if and unless conditions.
http://ant-contrib.sourceforge.net/fileset.html
if Sets the property name for the 'if' condition. The fileset will be
ignored unless the property is
defined. The value of the property is
insignificant, but values that would
imply misinterpretation ("false",
"no") will throw an exception when
evaluated.
unless Set the property name for the 'unless' condition. If named
property is set, the fileset will be
ignored. The value of the property is
insignificant, but values that would
imply misinterpretation ("false",
"no") of the behavior will throw an
exception when evaluated.
You could use it like this:
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<fileset dir="dir7" if="SPECIAL_BUILD" />
<fileset dir="dir8" if="SPECIAL_BUILD" />
</copy>
One way (not sure if a good one) to achieve that is to create two macrodefs - one "public" for general use and one "internal" that does the real work and is intended to be called only from the "public" macro. Like this:
<macrodef name="task-for-public-use">
<sequential>
<if>
<equal arg1="${SPECIAL_BUILD}" arg2="true" />
<then>
<internal-task>
<additional-path>
...
</additional-path>
</internal-task>
</then>
<else>
<internal-task ... />
</else>
</if>
</sequential>
</macrodef>
<macrodef name="internal-task">
<element name="additional-path" />
<sequential>
<copy ...>
...
<additional-path/>
</copy>
</sequential>
</macrodef>
I don't like it much though and hope there's a better way.

How can I compare two properties with numeric values?

How can I find out which of two numeric properties is the greatest?
Here's how to check wheather two are equal:
<condition property="isEqual">
<equals arg1="1" arg2="2"/>
</condition>
The Ant script task allows you to implement a task in a scripting language. If you have JDK 1.6 installed, Ant can execute JavaScript without needing any additional dependent libraries. For example, this JavaScript reads an Ant property value and then sets another Ant property depending on a condition:
<property name="version" value="2"/>
<target name="init">
<script language="javascript"><![CDATA[
var version = parseInt(project.getProperty('version'));
project.setProperty('isGreater', version > 1);
]]></script>
<echo message="${isGreater}"/>
</target>
Unfortunately, Ant's built in condition task does not have an IsGreaterThan element. However, you could use the IsGreaterThan condition available in the Ant-Contrib project. Another option would be to roll out your own task for greater than comparison. I'd prefer the former, because it's easier and faster, and you also get a host of other useful tasks from Ant-Contrib.
If you don't want to (or cannot) use the Ant-Contrib libraries, you can define a compare task using javascript:
<!-- returns the same results as Java's compareTo() method: -->
<!-- -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2 -->
<scriptdef language="javascript" name="compare">
<attribute name="arg1" />
<attribute name="arg2" />
<attribute name="result" />
<![CDATA[
var val1 = parseInt(attributes.get("arg1"));
var val2 = parseInt(attributes.get("arg2"));
var result = (val1 > val2 ? 1 : (val1 < val2 ? -1 : 0));
project.setProperty(attributes.get("result"), result);
]]>
</scriptdef>
You can use it like this:
<property name="myproperty" value="20" />
...
<local name="compareResult" />
<compare arg1="${myproperty}" arg2="19" result="compareResult" />
<fail message="myproperty (${myproperty}) is greater than 19!">
<condition>
<equals arg1="${compareResult}" arg2="1" />
</condition>
</fail>

Ant (1.6.5) - How to set two properties in one <condition> or <if>

I am trying to assign two different strings to two different variables dependent on two booleans in Ant.
Pseudocode (ish):
if(condition)
if(property1 == null)
property2 = string1;
property3 = string2;
else
property2 = string2;
property3 = string1;
What I've tried is;
<if>
<and>
<not><isset property="property1"/></not>
<istrue value="${condition}" />
</and>
<then>
<property name="property2" value="string1" />
<property name="property3" value="string2" />
</then>
<else>
<property name="property2" value="string2" />
<property name="property3" value="string1" />
</else>
</if>
But i get a null pointer exception for the line containing "<if>". I can get it to work using <condition property=...> tags but can only set one property at a time. I tried using <propertyset> but that wasn't allowed either.
I'm new to ant as you will probably have guessed :).
Gav
There are several ways to do this. The most straightforward is to just use two condition statements, and take advantage of property immutability:
<condition property="property2" value="string1">
<isset property="property1"/>
</condition>
<condition property="property3" value="string2">
<isset property="property1"/>
</condition>
<!-- Properties in ant are immutable, so the following assignments will only
take place if property1 is *not* set. -->
<property name="property2" value="string2"/>
<property name="property3" value="string1"/>
This is a bit cumbersome and doesn't scale well, but for just two properties I would probably use this approach.
A somewhat better way is to use a conditional target:
<target name="setProps" if="property1">
<property name="property2" value="string1"/>
<property name="property3" value="string2"/>
</target>
<target name="init" depends="setProps">
<!-- Properties in ant are immutable, so the following assignments will only
take place if property1 is *not* set. -->
<property name="property2" value="string2"/>
<property name="property3" value="string1"/>
<!-- Other init code -->
</target>
We are again taking advantage of property immutability here. If you don't want to do that, you can use the unless attribute, and an extra level of indirection:
<target name="-set-props-if-set" if="property1">
<property name="property2" value="string1"/>
<property name="property3" value="string2"/>
</target>
<target name="-set-props-if-not-set" unless="property1">
<property name="property2" value="string2"/>
<property name="property3" value="string1"/>
</target>
<target name="setProps" depends="-set-props-if-set, -set-props-if-not-set"/>
<target name="init" depends="setProps">
<!-- Other init code -->
</target>
It is important to note that the if and unless attributes of target only check if the property is set, not the value of the property.
You can use Ant-Contrib library to have access to a neat <if><then><else> syntax, however it will require a few download/install steps.
See this other SO question: ant-contrib - if/then/else task

Resources