Calling depends targets from parent build.xml inside includes xml - ant

Is it possible for xml files that are part of 'includes' inside build.xml to have depends on targets from that build.xml (backwards dependency)? Or do I need to create a chain of only forward dependencies, and having "depends" on includedFile.target down? If this is possible, how do I call these parent targets?
I am trying to extract several targets outside of a very long build.xml file, in a situation like this:
build.xml defines a very common target, buildMe used throughout the build.xml file. It also defines a target runTasks. It includes someTasks.xml. runTasks depends on buildMe and someTasks.groupOfTasks.
someTasks.xml define targets groupOfTasks, task0, task1, task2. groupOfTasks depends on task0, task1 and task2. Now can task0 task1 or task2 depend on buildMe from build.xml, or some other target defined in build.xml?

This works for me: In the main project file the target default depends on a target from commontasks.xml which depends on a target from the main project file:
<project name="main" default="default">
<import file="commontasks.xml" as="common" />
<target name="default" depends="common.hello" description="the main project">
</target>
<target name="initMain">
<echo>initializing main</echo>
<property name="aValue" value="MAIN" />
</target>
<project name="commontasks" >
<target name="hello" depends="initMain">
<echo>hello from common tasks</echo>
<echo>aValue: ${aValue}</echo>
</target>
When I run the ant build, I get:
initMain:
[echo] initializing main
common.hello:
[echo] hello from common tasks
[echo] aValue: MAIN
default:
BUILD SUCCESSFUL
The dependency is target default depends on hello depends on initMain and hello can use properties defined in initMain.

Related

How to use one target in multiple targets' 'depends' property in ANT build?

I am using ANT build for deployment process. For that, I followed the below points,
Created five targets in ANT named 'initiate.deploy' (to initiate
deployment), 'svn.checkout' (checkout source from SVN into
workspace) , 'generate.ear' (EAR generation) and 'deploy.ear'
(deploy EAR into Server), 'clean.workspace' (Cleaning workspace
dirtory).
The target 'initiate.deploy' is my default target.
I need to clean the workspace directory before 'svn.checkout' target
and after 'deploy.ear' target.
I put 'clean.workspace' target in 'depends' property of
'svn.checkout' target and in 'initiate.deploy' target.
My Code:
<target name="initiate.deploy" description="Initiate deployment" depends="svn.checkout, generate.ear, deploy.ear, clean.workspace">
..........................
</target>
<target name="svn.checkout" description="SVN checkout" depends ="clean.workspace">
..........................
</target>
But the target 'clean.workspace' is executed only once before 'svn.checkout' but not after 'deploy.ear' target.
Build sequence is created as follows.
Build sequence for target(s) 'initiate.deploy' is [clean.workspace,
svn.checkout, check.workSpace, update.property.file, generate.ear,
deploy.ear, initiate.deploy]
How to use one target in multiple targets' 'depends' property in ANT build?
As explained in the Ant documentation:
In a chain of dependencies stretching back from a given target such as
D above, each target gets executed only once, even when more than one
target depends on it.
My understanding is that this is designed to avoid cycles in the dependencies graph.
Due to this, you need to modify your targets, for example by removing clean.workspace from the dependencies of initiate.deploy and invoking it explicitely via the antcall task:
<target name="initiate.deploy" description="Initiate deployment" depends="svn.checkout, generate.ear, deploy.ear">
..........................
<antcall target="clean.workspace" />
</target>
<target name="svn.checkout" description="SVN checkout" depends ="clean.workspace">
..........................
</target>
Update:
As mentioned in the comments, the antcall task will start the invoked target in a new Ant project, which can create an undesirable overhead. To avoid this behavior, it is possible to wrap the target as a macrodef and invoke it as a task in any other target. You may then change the invoked target such that it calls the new macrodef, in order to keep it available as a dependency of other tasks:
<target name="initiate.deploy" description="Initiate deployment" depends="svn.checkout, generate.ear, deploy.ear">
..........................
<clean.workspace.macro />
</target>
<target name="svn.checkout" description="SVN checkout" depends ="clean.workspace">
..........................
</target>
<target name="clean.workspace">
<clean.workspace.macro />
</target>
<macrodef name="clean.workspace.macro">
<sequential>
<!-- do the workspace cleanup -->
..........................
</sequential>
</macrodef>

Using "antcall" in included ant files

I have a shared ant script b.ant which internally use antcall. It calculates a property that the client scripts use. I use include instead of import client scripts to avoid unintentional overwriting of targets, but this gives me a problem with the antcall.
When using include all targets in b are prefixes, and depends attributes in b are updated accordingly. This is however not true for antcall. Is there a there are way to handle this, i.e. make antcall always call the "local" ant target?
I can workaround this by using import, but then I'll get all the overwrite problems. It is not possible to use depends instead of antcall.
Example files
I have two files:
a.ant
<project>
<include file="b.ant" as="b" />
<target name="test-depends" depends="b.depend">
<echo>${calculated-property}</echo>
</target>
<target name="test-call" depends="b.call">
<echo>${calculated-property}</echo>
</target>
</project>
b.ant
<project>
<target name="depend" depends="some-target">
<property name="calculated-property" value="Hello World"/>
</target>
<target name="call">
<antcall target="some-target" inheritrefs="true"/>
<property name="calculated-property" value="Hello World"/>
</target>
<target name="some-target"/>
</project>
Example output
Calling test-depend works as expected but test-call fails with this output:
b.call:
BUILD FAILED
D:\ws\rambo2\ws-dobshl\ant-test\b.ant:6: The following error occurred while executing this line:
Target "some-target" does not exist in the project "null".
Total time: 258 milliseconds
Ant is a dependency matrix specification language. Usually a bunch of <antcall/>, <ant/>, <include/> and <import/> is a sign of a poorly written build script. It's a developer trying to force Ant to act like a programming language.
For developer, it makes sense to break up a program into smaller files. Even Python and Perl scripts can benefit from this. However, breaking up an Ant build script usually causes problems. We had a developer who went through every project and broke up all the build.xml files into six or seven separate build files in order to improve the process. It basically broke the whole Ant dependency mechanism. To fix it, he then tossed in a bunch of <ant/> calls and <include> tasks. In the end, it meant that each target was called between 12 to 20 times.
Not using <import/> and <antcall/> isn't a hard and fast rule. But, I've been using Ant for years and rarely ever used these mechanisms. When I do, it's usually for a shared build file that multiple projects will use (which sounds like what you have) but instead of defining targets in my shared build file, I define macros. This eliminates the target namespace issues that you are having, and the macros work better because they act more like Ant tasks. This is especially true with the introduction of <local/> in Ant 1.8.
See if you can restructure the shared build file into using <macrodef/> instead of targets. It will make it much easier to include your shared build file.
Give a name to the <project> in b.ant and then change the target of the <antcall>:
<project name="b"> <!-- Give the project a name -->
<target name="depend" depends="some-target">
<property name="calculated-property" value="In b.depend"/>
</target>
<target name="call">
<!-- Specify the name of the project containing the target -->
<antcall target="b.some-target" inheritrefs="true"/>
<property name="calculated-property" value="In b.call"/>
</target>
<target name="some-target"/>
</project>
The result of ant -f a.ant test-call:
b.call:
b.some-target:
test-call:
[echo] In b.call
BUILD SUCCESSFUL
With the changes to b.ant, the <include> in a.ant can be simplified by removing the as attribute:
<include file="b.ant" />

running specific target in different ant scripts in different directories

We have a large amount of apps. They all have a build.xml file located in the projects base directory. I am trying to create an ant script that will go through and call a specific target on each of the build.xml files in all the projects.
Here are the issues:
Some of the projects are in deeper directories than others.
Only some of the projects need to be built at a time.
I was trying to use subant + antfile and defining a CSV of file paths in a properties file, but this did not work. Below is what i have and the error i am getting.
If there is a better way to do this or you know what my problem is, please let me know! Thanks!
This is the property defined in a property file. I am wanting the person running the script to add the file paths in here that are relative to the current location of the script they are running.
projects.to.build=
This is the subant task i am trying to use in the main build script.
<filelist
id="projectNames"
dir="${basedir}"
files="${projects.to.build}"
/>
<target name="debugAll" description="Builds all the projects listed in the projectNames.properties file.">
<subant target="debug" antfile="${projects.to.build}">
</subant>
</target>
Here is the error i get when i try to run the build script when there are projects defined in the properties file. I am using the relative path. For example: ..\Apps\AnApp1\build.xml,..\Apps\AnApp2\build.xml,..\OtherApps\foo\AnotherApp1\build.xml
"No Build Path Specified" (at my subant task)
You specified the antfile attribute, so ANT was expecting to a single build.xml file.
The subant documentation describes how you can use a fileset as child parameter.
Here's an example:
<project name="Subant demo" default="run-debug-target">
<target name="run-debug-target">
<subant target="debug">
<fileset dir="." includes="**/build.xml" excludes="build.xml"/>
</subant>
</target>
</project>
Update
Alternatively a filelist could be used:
<project name="Dry run" default="run">
<target name="run">
<subant target="test">
<filelist dir="projects" files="one/build.xml,two/build.xml,three/build.xml,four/build.xml"/>
</subant>
</target>
</project>
Processing the following build files:
projects/one/build.xml
projects/two/build.xml
projects/three/build.xml
projects/four/build.xml
Is it possible to run the target in the all the build files concurrently ?
E.g.
<project name="Dry run" default="run">
<target name="run">
<subant target="test">
<filelist dir="projects" files="one/build.xml,two/build.xml,three/build.xml,four/build.xml"/>
</subant>
</target>
</project>
In this example, is there any way to run target "test" present in all the build files (one/build.xml,two/build.xml,three/build.xml,four/build.xml) concurrently ?

Ant: "Duplicated project name in import" with imported build file

I have several build files which all import the same base build file, like this:
base.xml:
<project name="base">
<!-- does not define a 'build' target -->
</project>
buildA.xml:
<project name="buildA">
<import file="base.xml" />
<target name="build">
<ant antfile="buildB.xml" target="build"
inheritall="false" inheritrefs="false" />
</target>
</project>
buildB.xml:
<project name="buildB">
<import file="base.xml" />
<target name="build">
...snip...
</target>
</project>
(Module A depends on module B.)
Now, the above calling of B's build target from buildA.xml gives the following error:
Duplicated project name in import. Project base defined first in buildA.xml and again in buildB.xml
Since both buildA.xml and buildB.xml inherit the same base.xml, this seems unavoidable.
How could I get rid of this error?
Based on sudocode's answer, I solved the problem. Because the absolute path to base.xml is different in both cases, Ant does not recognize it as the same file. Even though inheritAll is set to false, the context of the calling task is preserved and this causes the name clash.
To solve this, one can omit the name attribute from base.xml. Since Ant 1.8, the import task has an attribute as, which can be used to reference base targets when the base project is nameless. If you don't override any targets, you can use include instead of import. I'm on 1.7, so that does not help me.
For previous versions of Ant, you can go through an exec call to prevent proliferation of the Ant context entirely (then you get two running Ant instances). Better yet, find a way to import the exact same base.xml (with the same absolute path) in both files.
Are you using Ant 1.6? This resolved Ant bug looks like the same issue.
EDIT
I tried to reproduce the dir structure you refer to in your recent comment.
./base.xml
./buildA
./buildA/buildA.xml
./buildB
./buildB/buildB.xml
And amended the build files accordingly, e.g.
<project name="buildA">
<import file="../base.xml"/>
<target name="build">
<ant antfile="../buildB/buildB.xml" target="build" inheritall="false" inheritrefs="false"/>
</target>
</project>
I still get no build error for the following with ant 1.8.2 or 1.7.1:
ant -f buildA/buildA.xml build

How can I run all the targets in an Ant buildfile?

I would like to execute all targets instead of specifying each one.
For example:
<?xml version="1.0"?>
<project name="Kte" default="all" basedir="/home/Kte">
<target name="target1">
</target>
<target name="target2">
</target>
</project>
Currently I have use:
$ ant target1
$ ant target2
I'd like to use:
$ ant
and have both targets get built (this is just an example. Reality I have a long ever changing Ant buildfile with sub-ant files so would be very handy to have an "all" feature.
You could create an ant task all, which depends on all the specific targets that you have...
<target name="all" depends="target1, target2, ... ">
</target>
ant all
You can also set up a default task that will run when you just type ant. The default attribute is in the project element.
<project name="foo" default="all">
<target name="all" depends="target1, target2"/>
<target name="target1">
...
</target>
<target name="target2">
...
</target>
</project>
$ ant
Because Ant is declarative it doesn't do this sort of thing nicely. You might consider a script task though.
Ant buildfiles have an implicit un-named target that 'holds' all the tasks that are not part of named targets. So this, placed at the top-level, would do what you describe.
<script language="javascript"><![CDATA[
importClass( java.util.Vector );
vec = new Vector( project.getTargets().keySet() );
vec.setSize( vec.size( ) - 1 );
project.executeTargets( vec );
]]>
</script>
(The implicit target appears at the end of the list, hence the size adjustment to prevent recursion.)
If you put that script in a 'runner' target - which would execute all other targets in the buildfile - you would need to remove the 'runner' from the Vector (and the implicit target-with-no-name) to prevent recursion.

Resources