Ant - Run a Build.xml for all subdirectories - ant

I have a build.xml sitting at the top level and I want the script to run a target for each subdirectory and pass in the subdirectory name as a parameter to the ANT target.
Can you help ?/??
Thanks

Take a look at the subant task. From that page:
<project name="subant" default="subant1">
<property name="build.dir" value="subant.build"/>
<target name="subant1">
<subant target="">
<property name="build.dir" value="subant1.build"/>
<property name="not.overloaded" value="not.overloaded"/>
<fileset dir="." includes="*/build.xml"/>
</subant>
</target>
</project>
this snippet build file will run ant in each subdirectory of the project directory, where a file called build.xml can be found. The property build.dir will have the value subant1.build in the ant projects called by subant.

this is might be what you looking for,
put this as one of your target in your parent build.xml
<target name="executeChildBuild">
<ant antfile="sub1/build.xml" target="build" />
<ant antfile="sub2/build.xml" target="build" />
</target>

If you would like to do it in ant build file, you could use Ant Contrib's for task to iterate over list of subdirectories and execute ant task for each of them.
<for param="subdir">
<dirset dir="${build.dir}">
<include name="./**"/>
</dirset>
<sequential>
<subant target="${target}">
<property name="subdir.name" value="#{subdir}"/>
</subant>
</sequential>
</for>
I didn't test this code since don't have ant installed, but it is close to what you're trying to do I suppose.

If I read the question correctly, this may be what you are looking for instead.
So for your example...
<target name="do-all">
<antcall target="do-first">
<param name="dir-name" value="first"/>
<param name="intented-target" value="init"/>
</antcall>
<antcall target="do-first">
<param name="dir-name" value="second"/>
<param name="intented-target" value="build"/>
</antcall>
<antcall target="do-first">
<param name="dir-name" value="third"/>
<param name="intented-target" value="compile"/>
</antcall>
</target>
<target name="do-first">
<echo>Hello from ${dir-name} ${intented-target}</echo>
<ant antfile="${dir-name}/build.xml" target="${intented-target}"/>
</target>
When you are calling this from Ant, you would enter this at the command line:
ant do-all
and your output should look like this:
do-all:
do-first:
[echo] Hello from first init
do-first:
[echo] Hello from second build
do-first:
[echo] Hello from third compile
BUILD SUCCESSFUL
Total time: 1 second
You will of course need to make sure that the directory name that you are using as a param actually exists, or the build will fail.
You can also always feed the variable that you want to use by adding the value to the build.properties file.

Related

Ant: How to prevent the properties from being passed down to its descendant calls?

build.xml
<target name="main">
<ant antfile="build-foo.xml" dir="${basedir}" target="foo"
inheritAll="false" useNativeBasedir="true">
<property name="messages" value="NOT_FOO_BAR"/>
</ant>
</target>
build-foo.xml
<target name="foo">
<property name="messages" value="FOO"/>
<ant antfile="build-bar.xml" dir="${basedir}" target="bar"
inheritAll="false" useNativeBasedir="true">
</ant>
</target>
build-bar.xml
<target name="bar">
<property name="messages" value="BAR"/>
<echo message="messages = ${messages}"/>
</target>
Tried:
ant -buildfile build-foo.xml foo
the messages is BAR, as expected.
ant -buildfile build.xml main
the messages is NOT_FOO_BAR.
The properties from main is passed multi-level down, even if it is not desired in build-foo.xml: inheritAll=false.
How to prevent the properties from being passed down to its descendant calls? Thanks.
From ant manual ant task :
You can also set properties in the new project from the old project by
using nested property tags. These properties are always passed to
the new project and any project created in that project regardless
of the setting of inheritAll. This allows you to parameterize your
subprojects.
instead :
<target name="main">
<ant antfile="build-foo.xml" dir="${basedir}" target="foo"
inheritAll="false" useNativeBasedir="true"/>
<property name="messages" value="NOT_FOO_BAR"/>
</target>
meets your expections.

Multiple property files for different builds

I have a project with 3 targets for different build variants each having their own property file defined like this:
<target name="dev">
<property file="dev.properties" />
<antcall target="build" />
</target>
<target name="test">
<property file="test.properties" />
<antcall target="build" />
</target>
<target name="prod">
<property file="prod.properties" />
<antcall target="build" />
</target>
All property files define the same properties. Now I need to make a target which would build them all, I tried something like:
<target name="all">
<antcall target="dev" />
<antcall target="test" />
<antcall target="prod" />
</target>
But the problem is that ant properties are immutable and I end up with properties from dev.properties for all builds. What's the recommended approach if I want to build all three targets with their own properties?
Wouldn't it be a lot simpler to have a single build script, and then decide it's purpose at run-time?
For example:
ant -propertyfile build-dev.properties
ant -propertyfile build-test.properties
ant -propertyfile build-prod.properties
..
This approach is more flexible when automating your builds using something like Jenkins. It can detect source code changes and run each build type automatically (and in parallel) if that is the desired outcome.

How to pass multiple parameters to a target in Ant?

I have this dummy target:
<mkdir dir="${project.stage}/release
<war destfile="${project.stage}/release/sigma.war">
...
...
</war>
What I want to do is provide two parameters say "abc" & "xyz" which will replace the word release with the values of abc and xyz parameters respectively.
For the first parameter say abc="test", the code above will create a test directory and put the war inside it.Similarly for xyz="production" it will create a folder production and put the war file inside it.
I tried this by using
<antcall target="create.war">
<param name="test" value="${test.param.name}"/>
<param name="production" value="${prod.param.name}"/>
</antcall>
in the target which depends on the dummy target provided above.
Is this the right way to do this.I guess there must be some way to pass multiple parameters and then loop through the parameters one at a time.
unfortunately ant doesn't support iteration like for or foreach loops unless you are refering to files. There is however the ant contrib tasks which solve most if not all of your iteration problems.
You will have to install the .jar first by following the instructions here : http://ant-contrib.sourceforge.net/#install
This should take about 10 seconds. After you can simply use the foreach task to iterate through you custom list. As an example you can follow the below build.xml file :
<project name="test" default="build">
<!--Needed for antcontrib-->
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<!--Iterate through every token and call target with parameter dir-->
<foreach list="${test},${production}" param="dir" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${dir}"/>
</target>
</project>
Output :
build:
create.war:
[echo] My path is : value_1
create.war:
[echo] My path is : value_2
BUILD SUCCESSFUL
Total time: 0 seconds
I hope it helps :)
Second solution without using ant contrib. You could encapsulate all your logic into a macrodef and simply call it twice. In any case you would need to write the two parameters at some point in your build file. I don't think there is any way to iterate through properties without using external .jars or BSF languages.
<project name="test" default="build">
<!--Needed for antcontrib-->
<macrodef name="build.war">
<attribute name="dir"/>
<attribute name="target"/>
<sequential>
<antcall target="#{target}">
<param name="path" value="#{dir}"/>
</antcall>
</sequential>
</macrodef>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<build.war dir="${test}" target="create.war"/>
<build.war dir="${production}" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${path}"/>
</target>
</project>
I admit that I don't understand the question in detail. Is ${project.stage} the same as the xyz and abc parameters? And why are there two parameters xyz and abc mentioned, when only the word "release" should be replaced?
What I know is, that macrodef (docu) is something very versatile and that it might be of good use here:
<project name="Foo" default="create.wars">
<macrodef name="createwar">
<attribute name="stage" />
<sequential>
<echo message="mkdir dir=#{stage}/release " />
<echo message="war destfile=#{stage}/release/sigma.war" />
</sequential>
</macrodef>
<target name="create.wars">
<createwar stage="test" />
<createwar stage="production" />
</target>
</project>
The output will be:
create.wars:
[echo] mkdir dir=test/release
[echo] war destfile=test/release/sigma.war
[echo] mkdir dir=production/release
[echo] war destfile=production/release/sigma.war
Perhaps we can start from here and adapt this example as required.

overwriting ANT properties file

How can i overwrite some existing property with a newly created properties file?
Here is the required structure:
initially load Master.properties
generate new.properties
load new.properties and master.properties
run master.xml (ANT script)
The idea is that Master.properties generates some product version which should be replaced by new.properties. However, other properties in Master.properties should be kept the same.
Reading this does not help as i do not know how can i load the new.properties file
EDIT Here is ANT Script:
<project name="nightly_build" default="main" basedir="C:\Work\NightlyBuild">
<target name="init1">
<sequential>
<property file="C:/Work/NightlyBuild/master.properties"/>
<exec executable="C:/Work/Searchlatestversion.exe">
<arg line='"/SASE Lab Tools" "${Product_Tip}/RELEASE_"'/>
</exec>
<sleep seconds="10"/>
<property file="C:/Work/new.properties"/>
</sequential>
</target>
<target name="init" depends="init1">
<sequential>
<echo message="The product version is ${Product_Version}"/>
<exec executable="C:/Work/checksnapshot.exe">
<arg line='-NightlyBuild ${Product_Version}-AppsMerge' />
</exec>
<sleep seconds="10"/>
<property file="C:/Work/checksnapshot.properties"/>
<tstamp>
<format property="suffix" pattern="yyyy-MM-dd.HHmm"/>
</tstamp>
</sequential>
</target>
<target name="main" depends="init">
<echo message="loading properties files.." />
<echo message="Backing up folder" />
<move file="C:\NightlyBuild\NightlyBuild" tofile="C:\NightlyBuild\NightlyBuild.${suffix}" failonerror="false" />
<exec executable="C:/Work/sortfolder.exe">
<arg line="6" />
</exec>
<exec executable="C:/Work/NightlyBuild/antc.bat">
</exec>
</target>
</project>
in the above script, <exec executable="C:/Work/NightlyBuild/antc.bat"> will run Master.xml ANT script. This Master.xml will load up Master.properties:
<project name="Master ANT Build" default="main" >
<taskdef name="CFileEdit" classname="com.ANT_Tasks.CFileEdit"/>
<!-- ========================================================== -->
<!-- init: sets global properties -->
<!-- ========================================================== -->
<target name="init">
<property environment="env"/>
<!-- ========================================================== -->
<!-- Set the timestamp format -->
<!-- ========================================================== -->
<property file="Master.properties"/>
...
</project>
You should be able to resolve this by looking at the order in which you load (or otherwise specify) your property values. You probably don't need to override property values at all, which something not supported by core Ant.
Maybe you can split your Master.properties into two files - one loaded before you generate new.properties and one loaded after?
Maybe you don't need to generate new.properties at all.
Could you give some more detail on what you need to do?
Since you eventually fork a new Ant process (exec antc.bat), does that not start a fresh environment anyway? If it just loads Master.properties, those are the only properties it will have.
Not sure what your antc.bat does, but it's pretty unusual to exec Ant from Ant in this way. There are two standard tasks which might be useful - Ant and AntCall.
OK running on from your later comments...
Let's say that instead of doing this:
<exec executable="antc.bat">
you instead did something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${Product_Version}"/>
</ant>
I think that is getting towards what you want. You selectively pass specific values that you have obtained by loading new.properties. See the documentation for the Ant task.
If you still have the problem that you already defined Product_Version before loading new.properties, then I would say get the script you have that produces new.properties to output the version with a different name, e.g. New_Product_Version. Then invoke your master build something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${New_Product_Version}"/>
</ant>
May be this is a old question. Hopefully OP is reading this.
You can just use the ant task "propertyfile". reference
it can read properties from the file and write back updated values to them.

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

Resources