Failing task if variable undefined - ant

I would like my Ant task to fail if a variable it uses is not defined. E.g. currently
<mkdir dir="${some.dir}"/>
always succeeds, if some.dir is defined, it creates a directory under the variable's value, if not it creates a directory named literally ${some.dir}.
Is there a way and how to switch between the currently lenient and a more strict mode of resolving variables in Ant? I am running this in Eclipse.

<fail unless="some.dir"/>
<mkdir dir="${some.dir}"/>
or
<fail>
<condition>
<not>
<isset property="some.dir"/>
</not>
</condition>
</fail>
<mkdir dir="${some.dir}"/>

Related

Getting condition doesn't support the nested "then" element in <condition>

I'm new to Ant/Apache. When I tried to use <condition> tag in XML it's throwing an error. condition doesn't support the nested "then" element. Here is my code
<target name="determine-ae-build">
<condition property="ApplicationName">
<equals arg1="${ApplicationName}" arg2="new"/>
<then>
<echo>3.9 Robots Config Copied</echo>
</then>
<else>
<condition property="ApplicationName">
<equals arg1="${ApplicationName}" arg2="old"/>
<then>
<echo>3.8 Robots Config Copied</echo>
</then>
<else>
<echo>3.9 Robots Config Copied</echo>
</else>
</condition>
</else>
</condition>
</target>
I've tried with IF also but since my Ant version is not supporting to do this. Can someone help to resolve this issue. Thanks! in advance
The condition task simply sets a property; it doesn't contain nested build logic. The property that it sets can later be used to control which targets are executed.
While you can use antcontrib's extra if, then, and else tasks to accomplish something like what you showed in your example, I'd recommend sticking to the native Ant approach, which relies on target dependencies and uses separate targets to control build logic:
<project name="build" basedir="." default="build">
<target name="build" depends="copy-3.8,copy-3.9" />
<target name="copy-3.8" depends="determine-ae-build" if="copy.old">
<echo>3.8 Robots Config Copied</echo>
</target>
<target name="copy-3.9" depends="determine-ae-build" unless="copy.old">
<echo>3.9 Robots Config Copied</echo>
</target>
<target name="determine-ae-build">
<condition property="copy.old">
<equals arg1="${ApplicationName}" arg2="old"/>
</condition>
</target>
</project>
With the above script, you would run ant build (possibly with -DApplicationName=old). The build target depends on both copy targets, both of which depend on determine-ae-build. The determine-ae-build target will therefore run first. If ApplicationName is set to "old" (either from a properties file that has been loaded, or from being provided in command line with -DApplicationName=old) then the property copy.old will be set to true. Otherwise it will remain unset.
Then copy-3.8 and copy-3.9 will be called. If copy.old is is true, copy-3.8 will run. Otherwise, it will be skipped. copy-3.9 has no condition so it will run no matter what.
Lastly, the build target will execute because it was the original target called from the command line, but it contains no actual steps so the build will finish.
<target name="prepare-copy" description="copy file based on condition" depends="determine-ae-build, prepare-copy-old, prepare-copy-new, prepare-copy-default">
<sleep seconds="10"/> --To read the results
</target>
<target name="prepare-copy-old" description="copy file based on condition" if="copy.old">
<echo>Old File Copied </echo>
</target>
<target name="prepare-copy-new" description="copy file based on condition" if="copy.new">
<echo>New File Copied</echo>
</target>
<target name="prepare-copy-default" description="copy file based on false condition" if="copy.default">
<echo>Default File Coping</echo>
</target>
<target name="determine-ae-build">
<condition property="copy.old">
<equals arg1="${ApplicationName}" arg2="old"/>
</condition>
<condition property="copy.new">
<equals arg1="${ApplicationName}" arg2="new"/>
</condition>
<condition property="copy.default">
<not>
<or>
<equals arg1="${ApplicationName}" arg2="new"/>
<equals arg1="${ApplicationName}" arg2="old"/>
</or>
</not>
</condition>
</target>
Explanation: Calling way "ant -Dcopy.old = true prepare-copy". Here we are passing to copy old file hence, "Old File Copied" will copied. If you call it like "ant prepare-copy" it'll call "Default File Coping".
Kindly Accept my answer if it is answered your question.Thankyou!

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)

How to fail an ant build if a property is not empty

I have an ANT build file which has the line-
<java classname="arq.sparql" fork="true" outputproperty="javaresult" errorproperty="javaerror">
Now I want add the condition to fail the build of the property 'javaerror' is not empty.
So I have the condition written like this :
<fail message="${javaerror}">
<condition>
<not>
<equals javaerror=""/>
</not>
</condition>
</fail>
But this did not work, can you please help.
Kind regards
Som
Your equals condition has the wrong syntax, it will work like that :
<fail message="${javaerror}">
<condition>
<not>
<equals arg1="${javaerror}" arg2=""/>
</not>
</condition>
</fail>
see Ant manual conditions for details
-- EDIT --
Alternatively you could use the new if/unless feature introduced with Ant 1.9.1 but you should use Ant 1.9.3 because of bugs in Ant 1.9.1 see this answer for details
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
<property name="javaerror" value="whatever"/>
<fail message="${javaerror}" unless:blank="${javaerror}"/>
</project>
You're looking for
<fail message="failed" if="javaerror"/>
Fail ant task doc

Use pure Ant to implement if else condition (check command line input)

I am a newbie in Ant. My ant script receives a user input variable named "env" from command line:
e.g. ant doIt -Denv=test
The user input value could be "test","dev" or "prod".
I also have the "doIt" target:
<target name="doIt">
//What to do here?
</target>
In my target, I would like to create the following if else condition for my ant script:
if(env == "test")
echo "test"
else if(env == "prod")
echo "prod"
else if(env == "dev")
echo "dev"
else
echo "You have to input env"
That's to check which value user has inputted from command line, then, print a message accordingly.
I know with ant-Contrib, I can write ant script with <if> <else> . But for my project, I would like to use pure Ant to implement if else condition. Probably, I should use <condition> ?? But I am not sure how to use <condition> for my logic. Could some one help me please?
You can create few targets and use if/unless tags.
<project name="if.test" default="doIt">
<target name="doIt" depends="-doIt.init, -test, -prod, -dev, -else"></target>
<target name="-doIt.init">
<condition property="do.test">
<equals arg1="${env}" arg2="test" />
</condition>
<condition property="do.prod">
<equals arg1="${env}" arg2="prod" />
</condition>
<condition property="do.dev">
<equals arg1="${env}" arg2="dev" />
</condition>
<condition property="do.else">
<not>
<or>
<equals arg1="${env}" arg2="test" />
<equals arg1="${env}" arg2="prod" />
<equals arg1="${env}" arg2="dev" />
</or>
</not>
</condition>
</target>
<target name="-test" if="do.test">
<echo>this target will be called only when property $${do.test} is set</echo>
</target>
<target name="-prod" if="do.prod">
<echo>this target will be called only when property $${do.prod} is set</echo>
</target>
<target name="-dev" if="do.dev">
<echo>this target will be called only when property $${do.dev} is set</echo>
</target>
<target name="-else" if="do.else">
<echo>this target will be called only when property $${env} does not equal test/prod/dev</echo>
</target>
</project>
Targets with - prefix are private so user won't be able to run them from command line.
If any of you require a plain if/else condition (without elseif); then use the below:
Here I am dependent on a env variable DMAPM_BUILD_VER, but it may happen that this variable is not set in the env. So I need to have mechanism to default to a local value.
<!-- Read build.version value from env variable DMAPM_BUILD_VER. If it is not set, take default.build.version. -->
<property name="default.build.version" value="0.1.0.0" />
<condition property="build.version" value="${env.DMAPM_BUILD_VER}" else="${default.build.version}">
<isset property="env.DMAPM_BUILD_VER"/>
</condition>

Can I make the Ant copy task OS-specific?

I have an Ant script that performs a copy operation using the 'copy' task. It was written for Windows, and has a hardcoded C:\ path as the 'todir' argument. I see the 'exec' task has an OS argument, is there a similar way to branch a copy based on OS?
I would recommend putting the path in a property, then setting the property conditionally based on the current OS.
<condition property="foo.path" value="C:\Foo\Dir">
<os family="windows"/>
</condition>
<condition property="foo.path" value="/home/foo/dir">
<os family="unix"/>
</condition>
<fail unless="foo.path">No foo.path set for this OS!</fail>
As a side benefit, once it is in a property you can override it without editing the Ant script.
The previously posted suggestions of an OS specific variable will work, but many times you can simply omit the "C:" prefix and use forward slashes (Unix style) file paths and it will work on both Windows and Unix systems.
So, if you want to copy files to "C:/tmp" on Windows and "/tmp" on Unix, you could use something like:
<copy todir="/tmp" overwrite="true" >
<fileset dir="${lib.dir}">
<include name="*.jar" />
</fileset>
</copy>
If you do want/need to set a conditional path based on OS, it can be simplified as:
<condition property="root.drive" value="C:/" else="/">
<os family="windows" />
</condition>
<copy todir="${root.drive}tmp" overwrite="true" >
<fileset dir="${lib.dir}">
<include name="*.jar" />
</fileset>
</copy>
You could use the condition task to branch to different copy tasks... from the ant manual:
<condition property="isMacOsButNotMacOsX">
<and>
<os family="mac"/>
<not>
<os family="unix"/>
</not>
</and>
Declare a variable that is the root folder of your operation. Prefix your folders with that variable, including in the copy task.
Set the variable based on the OS using a conditional, or pass it as an argument to the Ant script.
You can't use a variable and assign it depending on the type? You could put it in a build.properties file. Or you could assign it using a condition.
Ant-contrib has the <osfamily /> task. This will expose the family of the os to a property (that you specify the name of). This could be of some benefit.

Resources