How to set an Ant property only if it is unset - ant

I can't figure out how to set an Ant property on the condition that it has not been set (i.e it is not defined in the properties file and should automatically default).
So far, I only have the following code:
<condition property="core.bin" value="../bin">
<isset property="core.bin"/>
</condition>
But this only seems to work if the value is defined in a <property> tag.
Does anyone know how to conditionally set a property for the first time if it currently unset?

You simply can set the property with the property-task. If the property is already set, the value is unchanged, because properties are immutable.
But you can also include 'not' in your condition:
<condition property="core.bin" value="../bin">
<not>
<isset property="core.bin"/>
</not>
</condition>

Ant does this by default; if the property is already set; setting it again has no effect:
<project name="demo" default="demo">
<target name="demo" >
<property name="aProperty" value="foo" />
<property name="aProperty" value="bar" /> <!-- already defined; no effect -->
<echo message="Property value is '${aProperty}'" /> <!-- Displays 'foo' -->
</target>
</project>
Gives
/c/scratch> ant -f build.xml
Buildfile: build.xml
demo:
[echo] Property value is '${aProperty}'
BUILD SUCCESSFUL
Total time: 0 seconds
/c/scratch> ant -f build.xml
Buildfile: build.xml
demo:
[echo] Property value is 'foo'
BUILD SUCCESSFUL
Properties cannot be redefined; to do this you need to use something like the variable task from ant-contrib.

The easiest way to do what you want:
<if>
<not>
<isset property="your.property"/>
</not>
<then>
<property name="your.property" value="your.value"/>
</then>
</if>

There is support of using 'else' within : https://ant.apache.org/manual/Tasks/condition.html to serve your exact purpose.
else
The value to set the property to if the condition evaluates to false. By default the property will remain unset. Since Apache Ant 1.6.3
So change to :
<condition property="core.bin" else="../bin">
<isset property="core.bin"/>
</condition>

Properties in Ant are immutable. After defined they cannot be changed.
But the Ant Contrib package offers the variable task. It works like a property but the values can be modified and unset.
Exmaple from the variable task documentation:
<var name="x" value="6"/>
<if>
<equals arg1="${x}" arg2="6" />
<then>
<var name="x" value="12"/>
</then>
</if>
<echo>${x}</echo> <!-- will print 12 -->

Related

Ant property not setting correctly?

I'm reasonably new to ant and I'm not quite sure why
I am getting the following error when I run ant: Cannot locate target java: please set JAVA_HOME to its location. I've pasted the relevant source code below. From what I can see, the target -check-langtools.jdk.home is being executed. But because it depends on -def-check, that gets executed. Do the attributes (name, property, marker) get passed into -def-check when -check-langtools.jdk.home is being called? If so - the failure must be happening at the condition where is the property is not being set (i.e isset must be returning false). I don't understand how the property is not being set, if it is able to print out the value (i.e. JAVA_HOME).
Background: Trying to build langtools from OpenJDK
<target name="-def-check">
<macrodef name="check">
<attribute name="name"/>
<attribute name="property"/>
<attribute name="marker" default=""/>
<sequential>
<fail message="Cannot locate #{name}: please set #{property} to its location">
<condition>
<not>
<isset property="#{property}"/>
</not>
</condition>
</fail>
<fail message="#{name} is not installed in ${#{property}}">
<condition>
<and>
<not>
<equals arg1="#{marker}" arg2=""/>
</not>
<not>
<available file="${#{property}}/#{marker}"/>
</not>
</and>
</condition>
</fail>
</sequential>
</macrodef>
</target>
<target name="-check-langtools.jdk.home" depends="-def-check">
<!-- <check name="target java" property="langtools.jdk.home" marker="${java.marker}"/> -->
<check name="target java" property="JAVA_HOME" marker="${java.marker}"/>
</target>
<target name="-check-jtreg.home" depends="-def-check">
<check name="jtreg" property="jtreg.home" marker="lib/jtreg.jar"/>
</target>
This question was a bit of a blonde one but I ended up approaching this problem the wrong way, but I'll post up the answer here if anyone is new to Ant, and looking to do the same thing. To build the langtools portion of javac, what they need to do is set langtools.jdk.home=path_to_jdk_installation in a separate build.properties file that is included.
(eg. langtools.jdk.home=/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home)

Ant build.xml $$

I have a Ant build.xml that does a check as below, i was just wondering what the $$ signifies?
Thanks in advance for your help.
<equals casesensitive="false" arg1="${subPlan}" arg2="$${subPlan}"/>
From ant manual Properties and PropertyHelpers :
..Ant will expand the text $$ to a single $ and suppress the normal property expansion mechanism..
It's often used for output like that :
<property name="foo" value="bar"/>
<echo>$${foo} => ${foo}</echo>
output :
[echo] ${foo} => bar
In your case it checks whether a property with the name subPlan is set within your project, as ${subPlan} won't be expanded if it doesn't exist, f.e. :
<project>
<property name="subPlan" value="whatever"/>
<echo>${subPlan}</echo>
</project>
output :
[echo] whatever
whereas :
<project>
<echo>${subPlan}</echo>
</project>
output :
[echo] ${subPlan}
It's actually possible to set the propertyvalue for Property subPlan to ${subPlan} :
<property name="subPlan" value="$${subPlan}"/>
but that doesn't make sense, so your snippet does a combined check => is Property subPlan set and has a useful value ? could be used like that :
<fail message="Property not set or invalid value !">
<condition>
<equals casesensitive="false" arg1="${subPlan}" arg2="$${subPlan}"/>
</condition>
</fail>
Finally the standard way to check whether a property is set is using the isset condition, f.e. :
<fail message="Property not set !">
<condition>
<not>
<isset property="subPlan"/>
</not>
</condition>
</fail>

Available tag in ant is always true if a file is unavailable also

This code is always returning a true value even if file at given path does not exists
<available file="${x}/schema/#{componentname}-schema.sql" type="file" property="schema.file" />
<if>
<equals arg1="true" arg2="${schema.file}" />
<then>
<debug message="****schemafile is ${schema.file} ******" />
</then>
</if>
Output is always :-
*schemafile is true***
even if file is not available at that path.
Please help me to find the error.
I've refactored your example, in order to use standard ANT tasks:
<project name="demo" default="run" xmlns:if="ant:if">
<property name="src.dir" location="src"/>
<target name="run">
<available file="${src.dir}/schema/schema.sql" type="file" property="schema.file" />
<echo message="****schemafile is ${schema.file} ******" if:set="schema.file"/>
</target>
</project>
Notes:
I don't recognise the "debug" task so use the standard "echo" task instead
I recommend not using the ant-contrib "if" task. ANT 1.9.1 introduced an if attribute which can be used instead.
The following alternative variant will work with older versions of ANT. It uses an "if" target attribute to perform conditional execution:
<project name="demo" default="run">
<property name="src.dir" location="src"/>
<available file="${src.dir}/schema/schema.sql" type="file" property="schema.file" />
<target name="run" if="schema.file">
<echo message="****schemafile is ${schema.file} ******"/>
</target>
</project>
problem was i was iterating above code in for loop, and since property is immutable, it is always set to true if set at-least once. Thats why after 1 iteration even if the file was not found, it echoes schemafile is true** .
i have added below code to set property to false after that code
<var name="schema.file" unset="true"/>
<property name="schema.file" value="false"/>

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 to check if a property exists?

How do I check the existence of a property using Ant?
I am open to the use of ant-contrib, if Ant doesn't provide a similar thing.
Also, ant-contrib has an assert task, which provides exists, but the assertion is not what I need here since I would prefer a boolean return value.
You can use the Condition task with an isset condition.
<project default="test">
<property name="a" value="a"/>
<target name="test">
<condition property="a.set" else="false">
<isset property="a"/>
</condition>
<condition property="b.set" else="false">
<isset property="b"/>
</condition>
<echo message="a set ? ${a.set}"/>
<echo message="b set ? ${b.set}"/>
</target>
</project>
Output:
test:
[echo] a set ? true
[echo] b set ? false
Since Ant 1.9.1 it is possible to use "if" and "unless" attributes. You can use these new attributes if you add the 2 namespaces xmlns:if="ant:if" and xmlns:unless="ant:unless" to the project.
<!DOCTYPE project>
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
<property unless:set="property" name="property.is.set" value="false"/>
<property if:set="property" name="property.is.set" value="true"/>
<echo>${property.is.set}</echo>
</project>
see also https://ant.apache.org/manual/ifunless.html

Resources