Ant: Conditional Copy - ant

I want to overwrite the hosts file on the Windows machine if the user allows it:
<input message="Do you want to overwrite the HOSTS file?"
addproperty="overwrite.hosts" validargs="yes,no" />
<copy tofile="${env.WINDIR}/system32/drivers/etc/hosts.backup">
<fileset file="${env.WINDIR}/system32/drivers/etc/hosts" />
</copy>
<copy todir="${env.WINDIR}/system32/drivers/etc">
<fileset file="${trainer.dir}/hosts" />
</copy>
How do I do the copies only if the user says yes?
EDIT:
I tried this:
<input message="Do you want to overwrite the HOSTS file?" addproperty="overwrite.hosts" validargs="yes,no" />
<if>
<equals arg1="${overwrite.hosts}" arg2="yes" />
<then>
<copy tofile="${env.windir}/system32/drivers/etc/hosts.backup">
<fileset file="${env.windir}/system32/drivers/etc/hosts">
</fileset>
</copy>
<copy todir="${env.windir}/system32/drivers/etc">
<fileset file="${trainer.dir}/hosts">
</fileset>
</copy>
</then>
</if>
and I get this output:
C:\trainer\build.xml:16: Problem: failed to create task or type if
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
I'm an ant rookie... What do I need to do?

You could use a condition or a if task for that. (The latter is part of the ant-contrib project.)

You can use an "if" parameter on a target to make it conditional on the property being set.
I've never used the "input" task -- I didn't know it existed until just now (thanks for the heads up!) -- but a quick look at the documentation indicates that it sets the named property to the value entered, i.e. after an "input" the property is always set. So I guess you would need a "condition" to test the value and set or not set some other property.
Something like this. I just ran a quick test and this does work. Namely, if you answer the question "y" it prints the message, and if you answer "n" it does not.
<project name="test" default="do.whatever">
<target name="decide.do.whatever">
<input message="So you wanna do this or not?" validargs="y,n" addproperty="wanna"/>
<condition property="wanna.yes">
<equals arg1="${wanna}" arg2="y"/>
</condition>
</target>
<target name="do.whatever" depends="decide.do.whatever" if="wanna.yes">
<echo message="Yeah he wannas."/>
</target>
</project>

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>

Set ant property when comparing directories

I have two directories that I need to compare for having same files. I succesfully do this as follows:
<fileset dir="d:\test" id="onlyinbar">
<not>
<present targetdir="A_DIR"/>
</not>
</fileset>
<echo>these files are only in bar : ${toString:onlyinbar}</echo>
<fileset dir="A_DIR" id="differentbarfoo">
<different targetdir="d:\test" ignoreFileTimes="true"/>
</fileset>
<echo>these files are different in bar compared to foo : ${toString:differentbarfoo}</echo>
However, I need to issue an other task if either of these are true. So long the <condition> tag does seem to support only file to file comparison and I cannot see how to assign a property within the <fileset> tag. Help will be appreciated.
We needed to avoid any third party contribs for this solution. My major problem was the combination of the tags. We knew that our "tests" i.e fileset tags had to be in the condition but didn't know how. The resourcecount though short out the issue:
<target name="export-report-icons" description="A description">
<condition property="test2" else="false">
<or>
<resourcecount when="gt" count="0" property="flength">
<fileset dir="d:\test" id="onlyinbar">
<present targetdir="DIRs_A" present="srconly"/>
</fileset>
</resourcecount>
<resourcecount when="gt" count="0" property="flength">
<fileset dir="DIR_A" id="differentbarfoo">
<different targetdir="d:\test" ignoreFileTimes="true"/>
</fileset>
</resourcecount>
</or>
</condition>
</target>
<target name="copyThis" depends="export-report-icons" if="${test2}">
....
</target>
So what this does, sets an OR for the case that one of the two filesets succeeds, the counter wraps the fileset resource so that it can be hosted under the condition and the condition has a property true or false depending on ORed counts. The "copy-This" target executes if the ${test2} is true. Please note that if you set id=test2 it will always qualify as true as in this case it checks for value presence.
The <union> set operator groups resources from multiple collections into one collection.
Similarly, take a look at <intersect> and <difference>.
You mention "if", which I assume refers to the <if> task from the third-party Ant-Contrib library. Here's an example that echoes if the filesets combined by <union> match any files:
<if>
<resourcecount when="gt" count="0">
<union id="Check">
<resources refid="onlyinbar"/>
<resources refid="differentbarfoo"/>
</union>
</resourcecount>
<then>
<echo>There are differences: ${toString:Check}</echo>
</then>
</if>

Where "if" task can be inserted?

I can see, that "if" tasks can be used in "target" root or anywhere, where some action is expected. But can I use it when I'm specifying some parameter?
For example there's ant-javafx task fx:deploy, in which we can declare classpath:
<fx:deploy ...>
<fx:resources>
<fx:fileset dir="..." ...>
<fx:fileset dir="..." ...>
</fx:resources>
</fx:deploy>
The question is can I use "if" in that usecase? Example:
<fx:deploy ...>
<fx:resources>
<if>
<available file="${lib.dir}" type="dir" />
<then><fx:fileset dir="${lib.dir}" ...></then>
</if>
<fx:fileset dir="..." ...>
</fx:resources>
</fx:deploy>
Okay, where are you getting your <if> tasks?
Are these from Ant-Contrib? If so, these are tasks and not sub-entities that can be used with in a task.
However, it MIGHT be possible to define a resource with in an <if> statement:
<if>
<avaliable file="${lib.dir}" type="dir"/>
<then>
<fileset dir="${lib.dir}" id="lib.fileset">
<includes name="..."/>
</fileset>
</then>
<else>
<fileset dir="${foo.dir}" id="lib.fileset">
<include name="..."/>
</fileset>
</else>
</fi>
Now you would have a fileset with an id of lib.fileset that could be one of two different definitions. You can then use that as part of a sub-entity:
<jar destfile="${jar.name}">
<fileset refid="lib.dir"/>
</jar>
I said MIGHT because I've never tried this, but I really can't see why it wouldn't. I have never used the JavaFX tasks, so I didn't want to give an example with that, but the documentation does say that <fx:resources> can use a reference id.

How can we use search for a file under particular directory in ant

Hi all this is my code for checking if a particular file is present e.g. ${file}=license
<target name="File.check" >
<condition property="File.exists" >
<available file="${File}" type="file" />
</condition>
although if the file present is exactly license it works fine but sometimes the file can be either license.txt or even in uppercase also.
So I want my above code to work under all conditions even if the file is License or LICENSE or license or LICENSE.txt or anything that starts with l or L.
It probably would be easiest to include all possible variations, as the file attribute needs a real file and does not allow wildcards:
<condition property="File.exists" >
<or>
<available file="license.txt" type="file" />
<available file="LICENSE.txt" type="file" />
<available file="license" type="file" />
<available file="LICENSE" type="file" />
</or>
</condition>
The other possibility is to write your own condition.
You could use the Contains condition to check whether ${file} contains the text "license". It even has a casesensitive argument. Not sure whether
anything that starts with l or L
is a good idea though.
<target name="SearchForfile">
<delete dir="../filepresent" />
<copy todir="../filepresent" failonerror="yes" flatten="true">
<fileset dir="../result/unzip/${param1}" casesensitive="false">
<include name="**/*license*"/>
</fileset>
</copy>
<antcall target="CheckFileExistance"/>
</target>
in that "CheckFileExistance" target just check if "filepresent" folder is present or not if it is then the file is present in your source directory and else if "filepresent" folder is not there that means file is not present anywhere in your search directory...i hope this makes everything clear

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.

Resources