Dependent targets executed twice if two targets in command line - ant

I have an Ant build file with dependencies as follow:
<target name="resolve">
....
</target>
<target name="compile" depends="resolve">
....
</target>
<target name="ship" depends="compile">
....
</target>
When invoking only the ship target with ant ship, only needed target are executed in the right order: [resolve>compile>ship].
The issue is when directly invoking two targets on the command line.
By executing ant compile ship, the output is [resolve > compile > resolve > compile > ship]. I cannot understand the logic chosen to execute some dependencies twice.
How can I force Ant to never execute a target twice ? With a very complex build file, I cannot always run the intended command with a single target.

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>

Checking inputs before running dependent tasks

I've got a Ant build script which I need to compile part of my project (it links into a third-party build system for the JavaScript libraries we use).
I want to wrap Gradle around this, so I've imported the Ant build, and I can successfully invoke the Ant targets via Gradle. I've even added input and output checking to the targets, so that they won't run if they don't need to
The Ant targets have setup work that they do - mostly importing configurations and settings. They do this via a dependency on an init target, which takes about 4-5 seconds to run. What I would like to do is prevent that init target running if the inputs on the main task have been satisfied.
Any suggestions?
Example Ant build script (build.xml):
<?xml version="1.0" encoding="utf-8"?>
<project name="MyProject" default="build">
<target name="init" />
<target name="build" depends="init">
<echo message="hello" file="output.txt" />
</target>
</project>
Example Gradle script to go with it (build.gradle):
ant.importBuild 'build.xml'
build {
inputs.dir file('src')
outputs.file file('output.txt')
}
Ideally, when I run gradle build, I don't want init to run if build is up-to-date.
Any suggestions?
The up-to-date check for build will only happen after init has run. What you can do is to declare the same inputs for init, and if it has no file outputs, outputs.upToDateWhen { true }. Perhaps this meets your needs.

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 task to generate mutiple targets in different project

i have ant target which invokes simultaneously other 3 projects ant build target for junit. this build target executes all three projects even though any one of the project build fails. Problem here is, if any one of the build fails error message should display after compiling three projects build target but it is not happening, how can i solve it?
<target name="mainbuild">
<antcall target="junit-1">//in different project
<antcall target="junit-2">//in different project
<antcall target="junit-3">//in different project
<junitreport todir="./reports">
<fileset dir="./project-1/reports">
<include name="TEST-*.xml"/>
</fileset>
<fileset dir="./project-2/reports">
<include name="TEST-*.xml"/>
</fileset>
<fileset dir="./project-3/reports">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="./report/html"/>
</junitreport>
</target>
<target name="junit-1">
.... do somethig
</target>
<target name="junit-2">
.... do somethig
</target>
<target name="junit-3">
.... do somethig
</target>
1) main build invokes 3 project,even though build fail in any one of the sub project, build successful message displays at the end, it shouldn't happen
2) if any one the sub project build fails, build report should generate, so that developer can analyze further on his failure.
Since you have clarified that your targets are in different projects, i.e. different build files, you will have to use the ant or subant tasks instead of antcall. The subant task has a parameter called failonerror which you can set to false so that a failure will not stop the top-level build. I don't know if it is possible to pass back to the top-level build the information that a sub-project build has actually failed its tests.
If your targets were all in the same project you could change your junit tasks so that they don't fail if a test fails, but instead set a property to indicate that a failure has occurred:
<junit failureProperty="test.failed"> ... </junit>
Then you can make your mainbuild target fail after generating the JUnit report:
<fail if="test.failed"> ... </fail>
I learned this from the book "Ant in Action".

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