Number of parameters passed in a Ant command line - ant

I would know if it's possible using an Ant task to know the number of parameters passed to an Ant target ? For example, with the following command :
ant myTarget -Darg1="arg1" -Darg2="arg2"
I would like to be able, inside the "myTarget" target, to get that the user passed exactly 2 arguments.
I have built this condition:
<condition property="params.set">
<and>
<isset property="arg1"/>
<isset property="arg2"/>
</and>
</condition>
but I would like to add in it a check on the number of passed parameters.
Or perhaps is it possible to get the same information using a groovy task in the "myTarget" target ? I think getting the whole command line would be enough (but how to do this ?) because I can then count the number of " -D" tokens.
Thanks in advance.

Personally, I would recommend checking for specific properties that the user should not be setting, as opposed to simply counting them and assuming any extras are unwanted. That could make the script rather annoying to deal with if someone is modifying or debugging it later on.
This would be my approach:
<fail>
<condition>
<or>
<not>
<or>
<isset property="arg1" />
<isset property="arg2" />
</or>
</not>
<isset property="doNotSet1" />
<isset property="doNotSet2" />
<isset property="doNotSet3" />
</or>
</condition>
</fail>
However, if you're dead-set on doing it the way you described, it should technically be possible. Ant stores any properties defined by the initial command in a propertyset named "commandline". However, this set includes more than just user properties defined with -D.... It will also contain generated properties such as ant.file that are set automatically. The number of these properties can vary depending on how your script is configured (for example specifying a default target in the root element), so those will need to be filtered out. Fortunately, these generated properties all begin with ant.file or ant.project, so they're relatively simple to identify.
<fail>
<condition>
<or>
<not>
<or>
<isset property="arg1" />
<isset property="arg2" />
</or>
</not>
<resourcecount when="ne" count="2">
<intersect>
<propertyset>
<propertyref builtin="commandline" />
</propertyset>
<propertyset>
<propertyref regex="^(?!ant\.(?:file|project))" />
</propertyset>
</intersect>
</resourcecount>
</or>
</condition>
</fail>

I finally used:
<resourcecount when="ne" count="2">
<difference>
<propertyset>
<propertyref builtin="commandline"/>
</propertyset>
<union>
<propertyset>
<propertyref prefix="ant.file"/>
</propertyset>
<propertyset>
<propertyref prefix="ant.project"/>
</propertyset>
</union>
</difference>
</resourcecount>
with also:
<condition>
<or>
<equals arg1="${library.name}" arg2=""/>
<equals arg1="${suffix}" arg2=""/>
</or>
</condition>
and it works well. Thanks again for your answers containing very interesting trails.

Related

How to check if Ant is executed under certain path?

How can I use Ant to verify that the current working directory is located (arbitrarily deeply nested) under a certain path? For example, I want to execute a target only if the current directory is part of /some/dir/, for example if Ant is executed in directory /some/dir/to/my/project/.
The best I could come up with is a String contains condition:
<if>
<contains string="${basedir}" substring="/some/dir/"/>
<then>
<echo>Execute!</echo>
</then>
<else>
<echo>Skip.</echo>
</else>
</if>
This works for my current purpose but I'm afraid it might break some time in the future... for example when a build is executed in path /not/some/dir/ which is also contains the specified directory string.
Are there any more robust solutions like a startsWith comparison or even better a file system based check...?
There is no specific startswith condition in native Ant, but there is a matches condition that takes regular expressions.
As a side note, ant-contrib is rarely necessary for most build scripts, and will often lead to unreliable code. I would strongly recommend avoiding it.
Here's a sample script to illustrate how you can use the matches condition with native Ant. The test target is, of course, just for demonstration.
<property name="pattern" value="^/some/dir" />
<target name="init">
<condition property="basedir.starts.with">
<matches pattern="${pattern}" string="${basedir}" />
</condition>
</target>
<target name="execute" depends="init" if="basedir.starts.with">
<echo message="Executing" />
</target>
<target name="test">
<condition property="dir1.starts.with">
<matches pattern="${pattern}" string="/some/dir/" />
</condition>
<condition property="dir2.starts.with">
<matches pattern="${pattern}" string="/some/dir/to/my/project/" />
</condition>
<condition property="dir3.starts.with">
<matches pattern="${pattern}" string="/not/some/dir/" />
</condition>
<echo message="${dir1.starts.with}" />
<echo message="${dir2.starts.with}" />
<echo message="${dir3.starts.with}" />
</target>

Ant - If condition / and-or

I was wondering if it was possible to make something like that in Ant (v1.9.4):
if((a=1 or a=2) and (b=3)) then ...
I tried
<ac:if>
<or>
<equals arg1="${aa}" arg2=""/>
<not>
<isset property="a"/>
</not>
</or>
<and>
<contains string="${b}" substring="${c}" casesensitive="false"/>
</and>
<then>
<property name="b" value="true" />
</then>
</ac:if>
But I got than error while running it...
Thanks for your help,
Regards,
Using Ant-contrib, you must have a single condition under the if task as shown below (you cannot have both <or> and <and>). You also don't need to check if the property is set as it is semantically covered when comparing the property to a value with equals:
<if>
<and>
<or>
<equals arg1="${a}" arg2="1" />
<equals arg1="${a}" arg2="2" />
</or>
<equals arg1="${b}" arg2="3" />
</and>
<then>
<!-- do stuff -->
</then>
<else>
<!-- do other stuff -->
</else>
</if>

build.xml ant script condition

Im trying to add a condition in my build.xml script for my deployment process. I basically need to determine the remote.host and based on the host set a variable value.
<condition property="my-prop" value="production">
<based on host=1234>
</condition>
<condition property="my-prop" value="development">
<based on host=5678>
</condition>
any ideas? of how the is suppose to be?
This should do the trick, guessing you will have to tweak a bit based on machine addresses or environment or whatever. Sets the value of my-prop to specified value based on test against the host property.
<!-- <property name="host" value="1234"/> -->
<property name="host" value="5678"/>
<target name="test">
<condition property="my-prop" value="production">
<equals arg1="1234" arg2="${host}"/>
</condition>
<condition property="my-prop" value="development">
<equals arg1="5678" arg2="${host}"/>
</condition>
<echo>${my-prop}</echo>
</target>

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 can I check if file exists, and if not kill the build?

How can I stop a build, and notify the user if a file does not exist? I know I can use the available task to set a property if a file exists, but I'm not sure how I would stop a build and echo something.
I would like to stick with core tasks if possible.
You can use the fail task for all your failing needs. The last example on that page is actually pretty much what you need
<fail message="Files are missing.">
<condition>
<not>
<resourcecount count="2">
<fileset id="fs" dir="." includes="one.txt,two.txt"/>
</resourcecount>
</not>
</condition>
</fail>
A little simpler (I wish it could be made simpler)
<fail message="file ${myfile} not set or missing">
<condition>
<not>
<available file="${myfile}" />
</not>
</condition>
</fail>
Set your property and use the Fail task with the if attribute.
This can be done more compactly (as indicated by Jason Punyon). Specifically, assuming the file you want is in the property file, do:
<available file="${file}" property="file.exists" />
<fail message="File missing: ${file}" unless="file.exists" />
These kind of checks are common, so it might pay off to use a macro.
Here is a macro based on the solution by leonbloy:
<macrodef name="require">
<attribute name="file"/>
<attribute name="message" default="file #{file} not set or missing"/>
<sequential>
<fail message="#{message}">
<condition>
<not>
<available file="#{file}" />
</not>
</condition>
</fail>
</sequential>
</macrodef>
Use like this:
<require file="${myfile}" />
or
<require file="${myfile}" message="my custom message" />

Resources