In Ant, can I use a property inside a target's "depends"? - ant

I m trying to do this with Ant:
<property name="test" value="123"/>
<target name="helloworld" depends="${test}"/>
But I'm getting error "Target ${test} does not exist in this project."
So I m guessing I can do this?

You can use the AntCall Task to call a Task inside another Task.
<project>
<target name="asdf">
<property name="prop" value="qwer" />
<antcall target="${prop}" />
</target>
<target name="qwer">
<echo message="in qwer" />
</target>
</project>
To make one depend on the other, you can set a parameter in the dependent task and check it in your calling task.

Rather than depends, you can check a property using the if attribute. See the manual for more details.
For example:
<target name="helloworld" if="test"/>
Note this only checks if the property is set (you can use unless to check if it is unset).
An alternative, more complex but powerful, approach is to use a nested condition on a depended target:
<target name="helloworld" depends="myTarget.check" if="myTarget.run">
...
</target>
<target name="myTarget.check">
<condition property="test">
<and>
<available file="foo.txt"/>
<available file="bar.txt"/>
</and>
</condition>

Related

how to ignore a failure ant task?

I have this ant script that is reading from a parameter a list of components and running other ant tasks (build.xml's):
<for list="${components.locations}" param="component" failonany="false">
<sequential>
<property name="#{component}" value="true"/>
<if>
<and>
<available file="${repository.location}/#{component}"/>
<available file="${repository.location}/${jars.location}"/>
</and>
<then>
<ant inheritAll="false" antfile="${repository.location}/#{component}/build.xml">
<!-- failonerror="false" -->
<property name="copy.libs" value="${copy.libs}"/>
<property name="repository.location" value="${repository.location}"/>
<property name="jars.location" value="${repository.location}/${jars.location}"/>
</ant>
</then>
</if>
</sequential>
</for>
The problem is if one component is failing, the script doesn't continue to next one.
I tried running with -k (-keep-going) argument but it doesn't help.
I found this property failonerror="false" but it's valid for "exec" tasks and couldn't integrate it with "ant" tasks or inside a "target".
Other direction was "failonany" property of the "for" but I didn't manage setting it up explicitly.
Can you please advice...
Thanks.
First of all, I would suggest deleting ant-contrib.jar and never looking back. Believe me, you will be doing yourself a favor.
You can use the subant task to iterate Ant builds on a set of directories or files. Simply define a dirset and pass any extra properties you need.
Instead of using ant-contrib's <if> block, use the standard target's if attribute to switch the entire target on or off. This is much safer and better practice.
<property name="repository.location" location="repository_location" />
<property name="jars.location" location="${repository.location}/jars" />
<property name="components" value="dir1,dir2,dir3" />
<target name="init">
<condition property="jars.available">
<available file="${jars.location}" />
</condition>
</target>
<target name="default" depends="init" if="jars.available">
<subant inheritall="false" failonerror="false">
<dirset id="components.dirs" dir="${repository.location}" includes="${components}" />
<property name="copy.libs" value="${copy.libs}" />
<property name="repository.location" value="${repository.location}" />
<property name="jars.location" value="${jars.location}" />
</subant>
</target>

Running an Ant target under certain conditions

I have the following Ant targets in my project.xml:
<target name="to.run.under.conditions">
</target>
<target name="deploy1">
<antcall target="deploy2"/>
</target>
<target name="deploy2">
<antcall target="to.run.under.conditions"/>
</target>
<target name="another.target">
<antcall target="deploy1"/>
</target>
My intent is to be able to exclude the target to.run.under.conditions when running another.target. I am not very familiar with ANT and I am struggling to understand how to approach the issue. I have tried to employ unless="${target.running}" in and set the property as true in the condition task inside the target name ="target.running"
Can you help with this?
Thank you for your help,
I.
----EDIT UPDATED SOLUTION----
This is my current attempt (I am using ANT 1.8.2):
<target name="to.run.under.conditions" if="${target.running}">
</target>
<target name="another.target">
<property name="target.running" value="false"/>
</target>
If I am not mistaken, since the property is set to false inside another.target, then to.run.under.conditions should not be run (I might be wrong, though). Does it make sense? Any comment is much appreciated!
Try this:
<target name="build-module-A" if="module-A-present"/>
<target name="build-own-fake-module-A" unless="module-A-present"/>
In the first example, if the module-A-present property is set (to any value, e.g. false), the target will be run. In the second example, if the module-A-present property is set (again, to any value), the target will not be run.
Please see Any Targets for more information.
I have ended up with this solution that seems to be work as expected:
<target name="deploy2">
<if>
<equals arg1="${target.running}" arg2="true" />
<then>
<echo message="the target will not run" />
</then>
<else>
<echo message="the target will run" />
<antcall target="to.run.under.conditions"/>
</else>
</if>
</target>
<target name="to.run.under.conditions">
</target>
<target name="another.target">
<property name="target.running" value="true"/>
</target>
Hope this helps,
I.

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

Ant antcall a target that defines a property

In Ant I want to define a target (called A) that define a property and antcall it from another target (called B). I want that the target B, after antcalling the target A, can access the property defined in the target A.
For example:
<target name="B">
<antcall target="A" inheritAll="true" inheritRefs="true" />
<echo>${myprop}</echo>
</target>
<target name="A">
<property name="myprop" value="myvalue" />
</target>
However it doesn't work and <echo>${myprop}</echo> doesn't print myvalue (I think because the property myprop isn't defined in B).
Is there any way to do that?
According to the Apache Ant FAQ:
<target name="cond" depends="cond-if"/>
<target name="cond-if" if="prop1">
<antcall target="cond-if-2"/>
</target>
<target name="cond-if-2" if="prop2">
<antcall target="cond-if-3"/>
</target>
<target name="cond-if-3" unless="prop3">
<echo message="yes"/>
</target>
Note: <antcall> tasks do not pass property changes back up to the environment they were called from, so you wouldn't be able to, for example, set a result property in the cond-if-3 target, then do <echo message="result is ${result}"/> in the cond target.
In this respect, it is impossible to do what you want using antcall.
========== edit ===========
Try antcallback: AntCallBack is identical to the standard 'antcall' task, except that it allows properties set in the called target to be available in the calling target.
http://antelope.tigris.org/nonav/docs/manual/bk03ch20.html
Sample code pasted from the above page:
<target name="testCallback" description="Test CallBack">
<taskdef name="antcallback" classname="ise.antelope.tasks.AntCallBack" classpath="${antelope.home}/build" />
<antcallback target="-testcb" return="a, b"/>
<echo>a = ${a}</echo>
<echo>b = ${b}</echo>
</target>
<target name="-testcb">
<property name="a" value="A"/>
<property name="b" value="B"/>
</target>
Another approach is to refactor your targets into macros. You are trying to use targets like functions and they are just not intended to be used that way. I typically write the bulk of my logic as macros, so that I can compose it more easily into more complicated macros. Then I write simple wrapper targets for the command-line entry points that I need.
Rather than using <antcall>, why not just have target B depend on target A?
<target name="B" depends="A">
<echo>${myprop}</echo>
</target>
<target name="A">
<property name="myprop" value="myvalue" />
</target>
I think you want to use a param.
<project default="B">
<target name="B">
<antcall target="A">
<param name="myprop" value="myvalue"/>
</antcall>
</target>
<target name="A">
<echo>${myprop}</echo>
</target>
</project>
I surrounded this with a project tag and moved the echo statement into "A". My output says
B:
A:
[echo] myvalue
BUILD SUCCESSFUL
#alem0lars, since you said you would like to subdivide a target, let me offer a different solution (that unfortunately doesn't answer your original question).
<project default="mytarg">
<target name="mytarg">
<property name="tgt" value="build"/>
<antcall target="deps"/>
</target>
<target name="deps" depends="aTgt,bTgt"/>
<target name="aTgt">
<echo>"In aTgt doing a ${tgt}"</echo>
</target>
<target name="bTgt">
<echo>"In bTgt doing a ${tgt}"</echo>
</target>
</project>
This subdivides the build into aTgt and bTgt.
Output will be
aTgt:
[echo] "In aTgt doing a build"
bTgt:
[echo] "In bTgt doing a build"
deps:
BUILD SUCCESSFUL

Testing Macrodef Attribute without IF

I am attempting to remove all lines that begin with log if a macrodef attribute is set to prod (example below). I plan on using replaceregexp to remove all lines beginning with log. However, I am not sure how to test if an attribute is set to a specific value, besides using the if task. I would like to not introduce any non-core Ant tasks to perform this, but I can't come up with any other solutions. Do I have any other options besides using the if-task?
Thanks
<macrodef name="setBuildstamp">
<attribute name="platform" />
<sequential>
<if>
<equals arg1="platform" arg2="prod" />
<then>
<replaceregexp match="^log\(.*" value="" />
</then>
</if>
</sequential>
</macrodef>
You should use a reference to a parameter, like this #{platform}.
Also, your replaceregexp task is missing a few parameters.
I think that in your particular case it is better to use linecontainsregexp filter reader. Here is modified code (note negate argument to linecontainsregexp).
<macrodef name="setBuildstamp">
<attribute name="platform" />
<sequential>
<if>
<equals arg1="#{platform}" arg2="prod" />
<then>
<copy todir="dest-dir">
<fileset dir="src-dir"/>
<filterchain>
<linecontainsregexp
regexp="^log\(.*"
negate="true"
/>
</filterchain>
</copy>
</then>
</if>
</sequential>
</macrodef>
They may be a couple of ways to solve this, but none are as straightforward as using the ant-contrib element. I'm not sure if this will get you what you need for your application, but you could try the following:
Using conditional targets. If you can replace your macrodef with a target to call, this may work for you. Note that this will set the property globally, so it might not work for your application.
<target name="default">
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<antcall target="do-buildstamp" />
</target>
<target name="do-buildstamp" if="platformIsProd">
<echo>doing prod stuff...</echo>
</target>
Handle the 'else' case. If you need to handle an alternate case, you'll need to provide a few targets...
<target name="default">
<property name="platform" value="prod" />
<antcall target="do-buildstamp" />
</target>
<target name="do-buildstamp">
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<antcall target="do-buildstamp-prod" />
<antcall target="do-buildstamp-other" />
</target>
<target name="do-buildstamp-prod" if="platformIsProd">
<echo>doing internal prod stuff...</echo>
</target>
<target name="do-buildstamp-other" unless="platformIsProd">
<echo>doing internal non-prod stuff...</echo>
</target>
Using an external build file. If you need to make multiple calls with different values for your property, you could isolate this in another build file within the same project. This creates a bit of a performance hit, but you would not need the additional library.
in build.xml:
<target name="default">
<ant antfile="buildstamp.xml" target="do-buildstamp" />
<ant antfile="buildstamp.xml" target="do-buildstamp">
<property name="platform" value="prod" />
</ant>
<ant antfile="buildstamp.xml" target="do-buildstamp">
<property name="platform" value="nonprod" />
</ant>
</target>
in buildstamp.xml:
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<target name="do-buildstamp">
<antcall target="do-buildstamp-prod" />
<antcall target="do-buildstamp-other" />
</target>
<target name="do-buildstamp-prod" if="platformIsProd">
<echo>doing external prod stuff...</echo>
</target>
<target name="do-buildstamp-other" unless="platformIsProd">
<echo>doing external non-prod stuff...</echo>
</target>
Add ant-contrib to your project. Of course, if you can add a file to your project, the easiest thing would be to just add the ant-contrib.jar file. You could put it under a "tools" folder and pull it in using a taskdef:
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${basedir}/tools/ant-contrib.jar" />
It looks like when you are building your project specifically for your Production environment - you are stripping out code you don't want to run in Production. Thus you are creating a different binary than what will run in your Dev or Testing environment.
How about using an environment variable or property file at run-time instead of build-time which determines whether or not logging happens? This way when you're having trouble in Production and you want to use the same exact binary (instead of determining the revision, checking out the code, rebuilding with a different environment flag) you just re-deploy it to your Dev or Test environment and turn on debugging in a properties file or environment variable?

Resources