How to call some Ant target only if some environment variable was not set? - ant

I would like to not call a target in build.xml in the case that there is a certain environment variable.
Using Ant 1.7.0, the following code does not work:
<property environment="env"/>
<property name="app.mode" value="${env.APP_MODE}"/>
<target name="someTarget" unless="${app.mode}">
...
</target>
<target name="all" description="Creates app">
<antcall target="someTarget" />
</target>
Target "someTarget" executes whether there is the environment variable APP_MODE or not.

The docs for the unlessattribute say:
the name of the property that must not be set in order for this target to execute, or something evaluating to false
So in your case, you need to put the name of the property, rather than an evaluation of the property:
<target name="someTarget" unless="app.mode">
...
</target>
Notes
In Ant 1.7.1 and earlier, these attributes could only be property names.
As of Ant 1.8.0, you may instead use property expansion; a value of true (or on or yes) will enable the item, while false (or off or no) will disable it.
Other values are still assumed to be property names and so the item is enabled only if the named property is defined.
Reference
if/unless on the ant manual

Unless attribute suggest in simple language that if property is set then the task would not be get executed. for ex.
<target name="clean" unless="clean.not">
<delete dir="${src}" />
<property name="clean.not" value="true" />
<delete dir="${dest}" />
</target>
Here , if you call clean target , it gets executed first then its value is set. And if you want to call it again in script then it would not as property must not be set in order to get the task executed.

Related

How to check a property or variable is empty and set a value then test for that value

We are using Ant 1.8. I am not an Ant developer but I have to pretend sometimes.
A new property, ${noReportDSUpgrade}, is intended to be "true" or "false".
By default it is empty (not exist?) which is "false" for our purposes.
If this property is empty it should be set to "false".
A command line using this parameter should set it to true.
1) How do I set ${noReportDSUpgrade} to false if empty and true if supplied?
2) For the target, how to execute only if false?
I have tried several suggestions I've found but can't get it to work.
At the beginning of the script:
<target name="init">
<antcall target="setnoReportDSUpgradeProperty"/>
Further down:
<target name="setnoReportDSUpgradeProperty">
<condition>
<or>
<equals arg1="${noReportDSUpgrade}" arg2=""/>
<not>
<isset property="false"/>
</not>
</or>
</condition>
<echo message="noReportDSUpgrade set to ${noReportDSUpgrade}"/>
</target>
Here's how to set a default property value in Ant:
<property name="noReportDSUpgrade" value="false" />
That's it! Properties are immutable in Ant, so if you set a value via command line or earlier in the script, subsequent <property> tasks won't change it. This won't account for the property being set to a blank value (i.e. ""), but as a general good practice, try to avoid setting properties to blank.
Even though I don't think you need a <condition> task for your goals here, I feel I should clear some things up in your example. The <condition> task doesn't affect the <target> that it's nested in; it simply sets a property, specified by the property attribute. Additionally, the isset condition's property attribute is used to point to the name of the property you're checking, not the value.
<condition property="noReportDSUpgrade">
<or>
<equals arg1="${noReportDSUpgrade}" arg2=""/>
<not>
<isset property="noReportDSUpgrade" />
</not>
</or>
</condition>
But like I said above, don't use that unless you really need to check for a blank value for some reason. Just use <property>.
As for running targets conditionally, the <target> block supports if and unless attributes that control whether or not the entire thing runs. This can be a bit confusing because there are two modes in which this operates.
<target name="myTarget" if="myCondition">
<echo message="Running myTarget" />
</target>
The above target will run if myCondition is set (not if its value is true). So if it evaluates to "true", "false", "asdf", or just blank, the target will still run. Conversely, if we used the unless attribute, it wouldn't run if myCondition is set to anything. This is usually convenient for when you're using the <condition> task to set your properties (since <condition> does not set a value if the boolean evaluates to false).
<target name="myTarget" if="${myCondition}">
<echo message="Running myTarget" />
</target>
Notice the ${} around myCondition. When you expand the property like this, Ant will only run the target if the property's value is "true", "on", or "yes".
Lastly, you typically don't need to make a separate target just for setting conditions. In relatively simple scripts, you can just use the implicite root target (i.e. put the tasks at root level outside of all other targets).
In short, here's the simplest way to write your script.
<project name="myProject">
<property name="noReportDSUpgrade" value="false" />
<target name="myTarget" if="${noReportDSUpgrade}">
<echo message="Running myTarget" />
</target>
</project>
If you really need an initialization target (note the depends attribute):
<project name="myProject">
<target name="init">
<property name="noReportDSUpgrade" value="false" />
</target>
<target name="myTarget" if="${noReportDSUpgrade}" depends="init">
<echo message="Running myTarget" />
</target>
</project>

Call Ant target directly and indirectly based on condition

I have the following default target defined in my build file:
<target name="main" depends="generate.doc" unless="generated.doc.present"/>
The property is set when the doc files already exist. In that case I don't want to do anything. However, it doesn't work since the dependent target is always executed before the condition is evaluated.
I still need to be able to call the dependent target directly and execute it, no matter if the output already exists or not. Hence something like this would not work:
<target name="main" depends="generate.doc"/>
<target name="generate.doc" unless="generated.doc.present">...</target>
Is there a solution without using antcall in the main target?
In the example below, the main <target> has been changed to have two dependencies. A new <target> named -pre-conditions will run before generate.doc.
The -pre-conditions <target> sets the skip-generate.doc property only if the generated.doc.present property has already been set.
The generate.doc <target> has been changed so it will be skipped if -pre-conditions set the skip-generate.doc property.
With these changes, generate.doc will always run when it's called directly.
<target name="-pre-conditions">
<condition property="skip-generate.doc">
<isset property="generated.doc.present"/>
</condition>
</target>
<target name="main" depends="-pre-conditions, generate.doc"/>
<target name="generate.doc" unless="skip-generate.doc">
<echo>generate.doc running</echo>
</target>

how to pass parameters to ant task's depends field

I have a build.xml that should receive dynamically parameters to the depends field.
I define this parameter in some other app.xml such as:
ops=op1, op2, op3,op4,op5,.... opn
then I import this app.xml into build.xml and want to use the parameter ops there.
<project name="Project" basedir="." default="help">
<target name="test" depends="{$ops}" description="executea series of commands in ant">
<echo message="batch operation job done. tasks = {$ops}"/>
</target>
</project>
How can I pass a parameter from one ant file to another?
The depends parameter does not take properties.
Ant uses a dependency matrix to determine what should be built and in what order. This matrix is calculated before any part of the build file itself is executed, so properties aren't even set when this is done.
What are you trying to accomplish? Maybe if we have a better idea what you want, we can help you with it. Ant isn't a scripting language like BASH or Python.
As already mentioned, you can't put properties into the Depends field. However, if you are setting a property, you can use it in the If field. Example
<project name="appProject">
<target name="test" depends="target1,target2,target3" description="execute series of commands"/>
<target name="target1" if="do.target1">
<echo message="Target1 executed." />
</target>
<target name="target2" if="do.target2">
<echo message="Target2 executed." />
</target>
<target name="target3" if="do.target3">
<echo message="Target3 executed." />
</target>
</project>
Then you set in your build.xml the given target flag do.target1, do.target2 or do.target3 and it gets executed. Basically what you wanted to have. In the If field properties are only checked for value. Also, you don't have to use the ${ } construction for the properties.

[ANT]Property and Classpathref inherit broken in "foreach"

To explain it briefly, here is an example:
In build.xml, local-db.xml is imported. And in local-db.xml, there is a target named "warmup" which calls one target of the third file -- local-gr.xml using task.
All the common properties and classpath defs are imported and set in build.xml.
in project.properties:
dest-dir=./destination
in build.xml:
<path id="gr-classpath"> ... </path>
<import file="local-db.xml" />
in local-db.xml:
<ant antfile="local-gr.xml" target="deploy" inheritAll="true" inheritRefs="true" />
In local-gr.xml, there are two targets like this:
<target name="deploy">
<tar ....../>
<foreach list="${list1}" delimiter="," parallel="true" trim="true" param="item" target="deploy-single" />
</target>
<target name="deploy-single">
something using property ${dest-dir} and path "gr-classpath"
</target>
Now here is the problem:
The property ${dest-dir} and path "gr-classpath" can be used in "deploy" because I set inheritAll and inheritRefs, but it can't be used directly in "deploy-single". "inherit" doesn't when the target is called by foreach?
I managed to pass ${dest-dir} to "deploy-single" with the help of the , but I didn't find any way to pass the classpathref "gr-classpath" to "deploy-single".
What I did to work around it was to claim the again in "deploy-single", but I don't like it at all.
Why this happens? What can I do to make it more elegant?
The ant-contrib foreach task doesn't by default propagate all properties and references to it's target. But it does have inheritall and inheritrefs attributes that you can use to make that happen.
<foreach list="${list1}" delimiter="," parallel="true" trim="true"
param="item" target="deploy-single"
inheritall="true" inheritrefs="true"
/>

Ant manifestclasspath: property already set

I want to use manifestclasspath Ant task. I have a very large build.xml file with a couple of imported other build files and when I run it I get this:
build.xml:1289: The following error occurred while executing this line:
build.xml:165: Property 'some.property' already set!
I am sure that this property is defined only in manifestclasspath task. Here is my code:
<manifestclasspath property="some.property" jarfile="some.jar">
<classpath refid="some.classpath"/>
</manifestclasspath>
This code is located inside of <project>.
What am I doing wrong? Is there a way to add something like condition to set property only if it is not already set? I don't want to use custom Ant tasks such as Ant Contrib's if if there is other way around.
Antcall opens a new project scope, but by default, all of the properties of the current project will be available in the new project. Also if you used something like =
<antcall target="whatever">
<param name="some.property" value="somevalue"/>
</antcall>
in the calling project then ${some.property} is also already set and won't be overwritten, as properties once set are immutable in ant by design.
Alternatively, you may set the inheritAll attribute to false and only "user" properties (those passed on the command-line with -Dproperty=value) will be passed to the new project.
So, when ${some.property} ain't no user property, then use inheritAll="false" and you're done.
btw. it's better to use a dependency between targets via depends="..." attribute than to use antcall, because it opens a new project scope and properties set in the new project won't get back to the calling target because it lives in another project scope..
Following a snippet, note the difference, first without inheritAll attribute
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar"/>
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value1
second with inheritAll=false
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar" inheritAll="false" />
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value2
some rules of thumb for antcall, it's rarely used for good reasons :
1. it opens a new project scope (starting a new 'ant -buildfile yourfile.xml yourtarget') so it uses more memory, slowing down your build
2. depending targets of the called target will be called also !
3. properties don't get passed back to the calling target
In some cases it might be ok when calling the same 'standalone' target (a target that has no target it depends on) with different params for reuse. Normally macrodef or scriptdef are used for that purpose. So, think twice before using antcall which also puts superfluous complexity to your scripts, because it works against the normal flow.
Answer to your question in the comment, using a dependency graph instead of antcall
you have some target that holds all conditions and sets the appropriate properties which may be evaluated by targets via if and unless attributes to control the further flow
<project default="main">
<target name="some.target">
<echo>starting..</echo>
</target>
<!-- checking requirements.. -->
<target name="this.target">
<condition property="windowsbuild">
<os family="windows"/>
</condition>
<condition property="windowsbuild">
<os family="unix"/>
</condition>
<!-- ... -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="unixbuild">
-->
<target name="another.target" depends="this.target" unless="windowsbuild">
<!-- your unixspecific stuff goes here .. -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="windowsbuild">
-->
<target name="yet.another.target" depends="this.target" unless="unixbuild">
<!-- your windowspecific stuff goes here .. -->
</target>

Resources