Ant - If condition / and-or - ant

I was wondering if it was possible to make something like that in Ant (v1.9.4):
if((a=1 or a=2) and (b=3)) then ...
I tried
<ac:if>
<or>
<equals arg1="${aa}" arg2=""/>
<not>
<isset property="a"/>
</not>
</or>
<and>
<contains string="${b}" substring="${c}" casesensitive="false"/>
</and>
<then>
<property name="b" value="true" />
</then>
</ac:if>
But I got than error while running it...
Thanks for your help,
Regards,

Using Ant-contrib, you must have a single condition under the if task as shown below (you cannot have both <or> and <and>). You also don't need to check if the property is set as it is semantically covered when comparing the property to a value with equals:
<if>
<and>
<or>
<equals arg1="${a}" arg2="1" />
<equals arg1="${a}" arg2="2" />
</or>
<equals arg1="${b}" arg2="3" />
</and>
<then>
<!-- do stuff -->
</then>
<else>
<!-- do other stuff -->
</else>
</if>

Related

Number of parameters passed in a Ant command line

I would know if it's possible using an Ant task to know the number of parameters passed to an Ant target ? For example, with the following command :
ant myTarget -Darg1="arg1" -Darg2="arg2"
I would like to be able, inside the "myTarget" target, to get that the user passed exactly 2 arguments.
I have built this condition:
<condition property="params.set">
<and>
<isset property="arg1"/>
<isset property="arg2"/>
</and>
</condition>
but I would like to add in it a check on the number of passed parameters.
Or perhaps is it possible to get the same information using a groovy task in the "myTarget" target ? I think getting the whole command line would be enough (but how to do this ?) because I can then count the number of " -D" tokens.
Thanks in advance.
Personally, I would recommend checking for specific properties that the user should not be setting, as opposed to simply counting them and assuming any extras are unwanted. That could make the script rather annoying to deal with if someone is modifying or debugging it later on.
This would be my approach:
<fail>
<condition>
<or>
<not>
<or>
<isset property="arg1" />
<isset property="arg2" />
</or>
</not>
<isset property="doNotSet1" />
<isset property="doNotSet2" />
<isset property="doNotSet3" />
</or>
</condition>
</fail>
However, if you're dead-set on doing it the way you described, it should technically be possible. Ant stores any properties defined by the initial command in a propertyset named "commandline". However, this set includes more than just user properties defined with -D.... It will also contain generated properties such as ant.file that are set automatically. The number of these properties can vary depending on how your script is configured (for example specifying a default target in the root element), so those will need to be filtered out. Fortunately, these generated properties all begin with ant.file or ant.project, so they're relatively simple to identify.
<fail>
<condition>
<or>
<not>
<or>
<isset property="arg1" />
<isset property="arg2" />
</or>
</not>
<resourcecount when="ne" count="2">
<intersect>
<propertyset>
<propertyref builtin="commandline" />
</propertyset>
<propertyset>
<propertyref regex="^(?!ant\.(?:file|project))" />
</propertyset>
</intersect>
</resourcecount>
</or>
</condition>
</fail>
I finally used:
<resourcecount when="ne" count="2">
<difference>
<propertyset>
<propertyref builtin="commandline"/>
</propertyset>
<union>
<propertyset>
<propertyref prefix="ant.file"/>
</propertyset>
<propertyset>
<propertyref prefix="ant.project"/>
</propertyset>
</union>
</difference>
</resourcecount>
with also:
<condition>
<or>
<equals arg1="${library.name}" arg2=""/>
<equals arg1="${suffix}" arg2=""/>
</or>
</condition>
and it works well. Thanks again for your answers containing very interesting trails.

ant: condition command does not find pattern when pattern is a file path

I am using the following code with the idea of finding a file in a directory that is also part of a list in a file:
<loadfile property="ReportFileContent" srcFile="${ReportFile}"/>
<for param="file">
<path>
<fileset dir="${MainDir}" includes="**/**"/>
</path>
<sequential>
<basename file="#{file}" property="#{file}" />
<condition property="found-file${index2}">
<matches pattern="#{file}" string="${ReportFileContent}"/>
</condition>
<if>
<isset property="found-file${index2}"/>
<then>
<echo message=" Found file #{file}" level="warning" />
</then>
<else>
<echo message="Not Found file #{file}" level="warning" />
</else>
</if>
<math result="index2" operand1="${index2}" operation="+" operand2="1" datatype="int" />
</sequential>
</for>
The command is not working though as it is not finding the file that is available in ${ReportFileContent}.
The content of the ReportFileContent property is the following:
c:\___tools\test\file1.txt;2
c:\___tools\test\file2.txt;2
c:\___tools\test\file3.txt;2
Any idea why the condition is not working correctly?
Thanks
Tony

Break or Continue Implemented?

Does the for/foreach loops in ant-contrib support the equivalent of a "break" or "continue" statement? As far as I can tell, they do not.
Are there any viable work-arounds?
Thanks
-T
There is no easy way to implement this behavior, but maybe the following suggestion will help.
use the the for task (i.e. not the foreach)
set the keepgoing attribute to true
use the fail task with a condition so that the items that need to be skipped will fail.
you can obtain something like a break by defining a property myBreakProperty whenever you detect that you need to break
<for list="a,b,c,d,e" param="letter" keepgoing="true">
<sequential>
<if>
<equals arg1="#{letter}" arg2="c" />
<then>
<property name="myBreakProperty" value="nevermind the value"/>
</then>
</if>
<fail if="myBreakProperty"/>
<echo>Letter #{letter}</echo>
</sequential>
</for>
The output will be: Letter a Letter b
To obtain something like a continue :
<for list="a,b,c,d,e" param="letter" keepgoing="true">
<sequential>
<if>
<equals arg1="#{letter}" arg2="c" />
<then>
<fail/>
</then>
</if>
<echo>Letter #{letter}</echo>
</sequential>
</for>
The output will be: Letter a Letter b Letter d Letter e
You can make a break process flow without running something as harsh as a fail. Using a property to detect when you want to break you can implement something like this:
<var name="break.flag" unset="true"/>
<for list="a,b,c,d,e" param="letter">
<sequential>
<if>
<not>
<isset property="break.flag"/>
</not>
<then>
<if>
<equals arg1="#{letter}" arg2="c" />
<then>
<property name="break.flag" value="true"/>
</then>
</if>
<if>
<not>
<isset property="break.flag"/>
</not>
<then>
<echo>Letter #{letter}</echo>
<echo>Do the rest of the loop here</echo>
</then>
</if>
</then>
</if>
</sequential>
</for>
To really break the loop you could use fail together with trycatch
<trycatch>
<try>
<for param="i" begin="1" end="99">
<sequential>
...
<fail message="break" />
</sequential>
</for>
</try>
<catch />
</trycatch>

How to check if a property has value in Ant

I have an Ant XML file which I use for build.
I have 3 properties. I want to break the build if these properties does not contain any value. Also I want to break the build if the value is empty.
How can I do this in Ant?
I a using Ant and not Ant-contrib.
You can use conditions using the <fail> task:
<fail message="Property "foo" needs to be set to a value">
<condition>
<or>
<equals arg1="${foo}" arg2=""/>
<not>
<isset property="foo"/>
</not>
</or>
</condition>
This is equivalent to saying if (not set ${foo} or ${foo} = "") is pseudocode. You have to read the XML conditions from the inside out.
You could have used the <unless> clause on the <fail> task if you only cared whether or not the variable was set, and not whether it has an actual value.
<fail message="Property "foo" needs to be set"
unless="foo"/>
However, this won't fail if the property is set, but has no value.
There's a trick that can make this simpler
<!-- Won't change the value of `${foo}` if it's already defined -->
<property name="foo" value=""/>
<fail message="Property "foo" has no value">
<condition>
<equals arg1="${foo}" arg2=""/>
</condition>
</fail>
Remember that I can't reset a property! If ${foo} already has a value, the <property> task above won't do anything. This way, I can eliminate the <isset> condition. It might be nice since you have three properties:
<property name="foo" value=""/>
<property name="bar" value=""/>
<property name="fubar" value=""/>
<fail message="You broke the build, you dufus">
<condition>
<or>
<equals arg1="${foo}" arg2=""/>
<equals arg1="${bar}" arg2=""/>
<equals arg1="${fubar}" arg2=""/>
</or>
</condition>
</fail>
Building on the other answers, this is my preferred form, as a Macro:
<!-- Macro to require a property is not blank -->
<macrodef name="prop-require">
<attribute name="prop"/>
<sequential>
<fail message="Property "#{prop}" must be set">
<condition>
<not>
<isset property="#{prop}"/>
</not>
</condition>
</fail>
<fail message="Property "#{prop}" must not be empty">
<condition>
<equals arg1="${#{prop}}" arg2=""/>
</condition>
</fail>
</sequential>
</macrodef>
To Be used as:
<target name="deploy.war" description="Do the war deployment ;)">
<prop-require prop="target.vm" />
<prop-require prop="target.vip" />
<!-- ... -->
For brevity you can collapse the two fail elements into one by using an <or>, but I prefer my error messages to treat me like I cannot think for myself ;)
You could try using conditions... or creating a target with unless
With Ant addon Flaka you may use patterns like :
<property name="foo" value="bar"/>
...
<fl:unless test="has.property.foo">
...
</fl:unless>
...
<fl:when test="has.property.foo">
...
</fl:when>
Concrete check for emptyness :
<fl:when test=" empty '${foo}' ">
<fail message="Houston we have a problem!!"/>
</fl:when>
A complete example, also using some equals check with 'eq' (opposite would be 'neq'):
<project xmlns:fl="antlib:it.haefelinger.flaka">
<!-- some if/then/else construct -->
<fl:choose>
<!-- if -->
<when test=" '${buildtype}' eq 'prod' ">
<!-- then -->
<echo>..starting ProductionBuild</echo>
</when>
<when test=" '${buildtype}' eq 'test' ">
<!-- then -->
<echo>..starting TestBuild</echo>
</when>
<!-- else -->
<otherwise>
<fl:unless test="has.property.dummybuild">
<fail message="No valid buildtype !, found => '${buildtype}'"/>
</fl:unless>
<echo>.. is DummyBuild</echo>
</otherwise>
</fl:choose>
</project>
output with ant -f build.xml -Dbuildtype=prod or
ant -f build.xml -Dbuildtype=prod -Ddummybuild=whatever
[echo] ..starting ProductionBuild
output with typo => ant - build.xml -Dbuildtype=testt
BUILD FAILED
/home/rosebud/workspace/AntTest/build.xml:21: No valid buildtype !, found => 'testt'
output with ant -f build.xml -Ddummybuild=whatever
[echo] .. is DummyBuild
I'm on an older version of Ant, so isset wasn't available. Instead I used the following notation with the double $ in the equals.
<target name="xxx">
<echo message="${contextRoot}" />
<if>
<!-- check if the contextRoot property is defined. -->
<equals arg1="${contextRoot}" arg2="$${contextRoot}" />
<then>
<!-- it isn't set, set a default -->
<property name="contextRoot" value="/WebAppCtx" />
</then>
</if>
<echo message="${contextRoot}" />
</target>
Try this.
<condition property="isPropertySet" value="true" else="false">
<and>
<isset property="my_property"/>
<length string="${my_property}" trim="true" when="greater" length="0"/>
</and>
</condition>
<fail unless="isPropertySet" message="The property my_property is not set."/>
Since Ant 1.9.1, it is possible to add if and unless attributes on all
tasks and nested elements using special namespaces.
In order to use this feature you need to add the following namespace declarations
xmlns:if="ant:if"
xmlns:unless="ant:unless"
The if and unless namespaces support the following conditions:
true - true if the value of the attribute evaluates to true
blank - true if the value of the attribute is null or empty
set - true if the specified property is set
Sample:
<project name="tryit"
xmlns:if="ant:if"
xmlns:unless="ant:unless">
<exec executable="java">
<arg line="-X" if:true="${showextendedparams}"/>
<arg line="-version" unless:true="${showextendedparams}"/>
</exec>
<condition property="onmac">
<os family="mac"/>
</condition>
<echo if:set="onmac">running on MacOS</echo>
<echo unless:set="onmac">not running on MacOS</echo>
</project>
From Ant manual "If And Unless"

How can I check if file exists, and if not kill the build?

How can I stop a build, and notify the user if a file does not exist? I know I can use the available task to set a property if a file exists, but I'm not sure how I would stop a build and echo something.
I would like to stick with core tasks if possible.
You can use the fail task for all your failing needs. The last example on that page is actually pretty much what you need
<fail message="Files are missing.">
<condition>
<not>
<resourcecount count="2">
<fileset id="fs" dir="." includes="one.txt,two.txt"/>
</resourcecount>
</not>
</condition>
</fail>
A little simpler (I wish it could be made simpler)
<fail message="file ${myfile} not set or missing">
<condition>
<not>
<available file="${myfile}" />
</not>
</condition>
</fail>
Set your property and use the Fail task with the if attribute.
This can be done more compactly (as indicated by Jason Punyon). Specifically, assuming the file you want is in the property file, do:
<available file="${file}" property="file.exists" />
<fail message="File missing: ${file}" unless="file.exists" />
These kind of checks are common, so it might pay off to use a macro.
Here is a macro based on the solution by leonbloy:
<macrodef name="require">
<attribute name="file"/>
<attribute name="message" default="file #{file} not set or missing"/>
<sequential>
<fail message="#{message}">
<condition>
<not>
<available file="#{file}" />
</not>
</condition>
</fail>
</sequential>
</macrodef>
Use like this:
<require file="${myfile}" />
or
<require file="${myfile}" message="my custom message" />

Resources