How do I prevent a dependency from executing in Ant? - ant

When debugging a build.xml file, or an Ant task, I often want to execute one task without executing its dependencies. Is there a way to do this from the command line?
For example, with this build.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<target name="A" />
<target name="B" depends="A" />
</project>
is there a command that will execute task B but not task A?

You can make execution of any target conditional on a property using if or unless.
<project default="B">
<target name="A" unless="no.a">
<echo>in A</echo>
</target>
<target name="B" depends="A" >
<echo>in B</echo>
</target>
</project>
Output with no condition specified:
$ ant
Buildfile: C:\Users\sudocode\tmp\ant\build.xml
A:
[echo] in A
B:
[echo] in B
BUILD SUCCESSFUL
Total time: 0 seconds
Output with condition specified on command line:
$ ant -Dno.a=any
Buildfile: C:\Users\sudocode\tmp\ant\build.xml
A:
B:
[echo] in B
BUILD SUCCESSFUL
Total time: 0 seconds
Notes:
Ant console output will show that the target was "hit" even if entry was blocked by the condition.
The if and unless conditions do not do boolean check. They just check whether the property is defined or not.

You will have to restructure your Ant script to achieve this:
<target name="B">
<if>
<isset property="some.property"/>
<then>
<antcall target="A">
</then>
</if>
<!-- execute task B here -->
</target>
If some.property is set, then it will first execute A followed by B. Otherwise, it will skip task A and execute B by itself.

Related

Ant calling targets several times

I set up a simple Ant script to understand why my dependency targets are being called several times when I specified several targets to execute (in Eclipse):
<project name="test">
<macrodef name="mkjar" description="Build a jar from 'tgt'">
<attribute name="tgt" />
<sequential>
<echo message="mkjar #{tgt}" level="info" />
</sequential>
</macrodef>
<target name="Common">
<mkjar tgt="Common" />
</target>
<target name="Net" depends="Common">
<mkjar tgt="Net" />
</target>
<target name="DB" depends="Common">
<mkjar tgt="DB" />
</target>
<target name="FooBar" depends="Common,DB">
<mkjar tgt="FooBar" />
</target>
<target name="FooBar2" depends="Common,Net,DB">
<mkjar tgt="FooBar2" />
</target>
</project>
Output:
Buildfile: buildtest.xml
Common:
[echo] mkjar Common
Net:
[echo] mkjar Net
DB:
[echo] mkjar DB
FooBar2:
[echo] mkjar FooBar2
Common:
[echo] mkjar Common
DB:
[echo] mkjar DB
FooBar:
[echo] mkjar FooBar
BUILD SUCCESSFUL
Total time: 283 milliseconds
Why is Ant going twice into targets Common and DB? I thought macrodef would be executed inside the same Ant flow and project scope. I tried uglier things with antcall
<target name="mkjar" unless="jar-${tgt}">
<property name="jar-${tgt}" value="true" />
...
</target>
But it's not better (it's even creating several jar-<tgt> properties!).
I thought macrodef would be executed inside the same Ant flow and project scope
It does. When you invoke ant FooBar2 FooBar, both targets are executed in the same Ant project. But in this case, Ant does not "track" that a dependency target has already executed when it is also a dependency for the second target.
A dependency target is invoked only once when it is in the same chain of dependencies of only one target, for example:
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
When running ant D, the following chain of targets is run: A --> B --> C --> D.
See https://ant.apache.org/manual/targets.html for more info.
One way to solve the issue here is to add a condition on the target to skip running it when a property is set:
<target name="Common" unless="common.already.executed">
<mkjar tgt="Common" />
<property name="common.already.executed" value="true" />
</target>

Ant depends attribute leading to errant behavior

I have two Ant tasks. If I run them, one after the other, from the command line -- no problems.
But if I include them in the depends attribute of another task like this depends='taskA,taskB' I get errant results.
Are the depends being run in series instead of in sequence? Without going into the specifics of the ant tasks -- any ideas?
ANT only executes dependent tasks once... The example below illustrates this strange behaviour.
This falls into the category of feature rather than bug. It's just the way ANT works. The thing to bear in mind is that ANT is not designed as a procedural programming language.
If your sub task is procedural in nature it would be best invoked as a macrodef (or better again create a re-usable antlib of build functions).
Example
$ ant
Buildfile: /path/to/my/home/build.xml
subtask1:
[echo] hello world
subtask2:
[echo] hello world
build1:
[echo] hello world
build2:
[echo] hello world
build:
BUILD SUCCESSFUL
build.xml
<project name="demo" default="build">
<target name="build" depends="build1,build2"/>
<target name="build1" depends="subtask1,subtask2">
<echo message="hello world"/>
</target>
<target name="build2" depends="subtask1,subtask2">
<echo message="hello world"/>
</target>
<target name="subtask1">
<echo message="hello world"/>
</target>
<target name="subtask2">
<echo message="hello world"/>
</target>
</project>

'make -n' equivalent for ant

According to the man page of make, -n option does the following job:
Print the commands that would be executed, but do not execute them.
I am looking for an option which acts the same in Apache Ant.
Horrific, but here it is. We can hack the targets at runtime using some code inside a <script> tag*. The code in do-dry-run below sets an unless attribute on each of your targets, and then sets that property so that none of them executes. Ant still prints out the names of targets that are not executed because of an unless attribute.
*(JavaScript script tags seem to be supported in Ant 1.8+ using the Oracle, OpenJDK and IBM versions of Java.)
<?xml version="1.0" encoding="UTF-8"?>
<project default="build">
<target name="targetA"/>
<target name="targetB" depends="targetA">
<echo message="DON'T RUN ME"/>
</target>
<target name="targetC" depends="targetB"/>
<target name="build" depends="targetB"/>
<target name="dry-run">
<do-dry-run target="build"/>
</target>
<macrodef name="do-dry-run">
<attribute name="target"/>
<sequential>
<script language="javascript"><![CDATA[
var targs = project.getTargets().elements();
while( targs.hasMoreElements() ) {
var targ = targs.nextElement();
targ.setUnless( "DRY.RUN" );
}
project.setProperty( "DRY.RUN", "1" );
project.executeTarget( "#{target}" );
]]></script>
</sequential>
</macrodef>
</project>
When I run this normally, the echo happens:
$ ant
Buildfile: build.xml
targetA:
targetB:
[echo] DON'T RUN ME
build:
BUILD SUCCESSFUL
Total time: 0 seconds
But when I run dry-run, it doesn't:
$ ant dry-run
Buildfile: build.xml
dry-run:
targetA:
targetB:
build:
BUILD SUCCESSFUL
Total time: 0 seconds
Ant has no dry-run option as make or maven have. But you could run the ant file step by step it in debugging mode under eclipse.
No I belive. There is no such way by default in Ant. And many unstisfying attempts you would find on google. But I have searched once and was unsuccessful.
It would be a useful feature, but not easily implemented.
Make and ANT are architecturally quite different. ANT doesn't run external OS commands, instead, most ANT "tasks" execute within the same Java thread.
It would be possible to emulate a "dry run" as follows:
<project name="Dry run" default="step3">
<target name="step1" unless="dry.run">
<echo>1) hello world</echo>
</target>
<target name="step2" depends="step1" unless="dry.run">
<echo>2) hello world</echo>
</target>
<target name="step3" depends="step2" unless="dry.run">
<echo>3) hello world</echo>
</target>
</project>
Running ANT as follows will print the target name but won't execute the enclosed tasks:
$ ant -Ddry.run=1
Buildfile: build.xml
step1:
step2:
step3:
BUILD SUCCESSFUL
Total time: 0 seconds
Create a special target in your buildscript that does some echoing only i.e. to check whether properties, path .. are resolved correctly.
see https://stackoverflow.com/a/6724412/130683 for a similar question answered.
For checking the details of your ant installation use ant -diagnostics

How do I pass an argument to an Ant task?

I'm not very good with Ant, but we're using it as a build tool. Right now, we can run "ant test" and it'll run through all the unit tests.
However, I'd love to be able to do something like ant test some_module and have it accept some_module as a parameter, and only test that.
I haven't been able to find how to pass command line args to Ant - any ideas?
One solution might be as follows. (I have a project that does this.)
Have a separate target similar to test with a fileset that restricts the test to one class only. Then pass the name of that class using -D at the ant command line:
ant -Dtest.module=MyClassUnderTest single_test
In the build.xml (highly reduced):
<target name="single_test" depends="compile" description="Run one unit test">
<junit>
<batchtest>
<fileset dir="${test.dir}" includes="**/${test.module}.class" />
</batchtest>
</junit>
</target>
You can also define a property with an optional default value that can be replaced via command line, e.g.
<target name="test">
<property name="moduleName" value="default-module" />
<echo message="Testing Module: ${moduleName}"/>
....
</target>
and run it as:
ant test -DmoduleName=ModuleX
What about using some conditional in your test target and the specifying -Dcondition=true?
<target name="test" depends="_test, _test_if_true>
...
</target>
<target name="_test_if_true" if="condition">
...
</target>
<target name="_test" unless="condition">
...
</target>
Adapted a bit from the ant faq.
You can define a property on commandline when invoking ant:
ant -Dtest.module=mymodulename
Then you can use it as any other ant property:
...
<fileset dir="${test.dir}" includes="**/${test.module}.class" />
...
Have a look at Ant's manual.
I tried the solutions posted here for the very same original question. Yes just use ant -D<arg_name>. THe -D is a "keyword" I guess. I'm no ant expert and have not read the manuals in detail. Then inside the ant XML files can be accessed like: ${arg_name}
For instance you can have an argument name like: arg.myarg, so in XML ${arg.myarg}.
Ant really doesn't have parameters_ for the build file. I can think of a few ways to do this:
Use a special target to specify the tests. You can use the <for/> task from AntContrib to allow you to specify multiple tests. You'll need to download the Ant-Contrib jar file. I recommend placing it inside your project under the `${basedir}/antlib/antcontrib" directory. That way, when others checkout your project, they get the needed Ant-Contrib jar file.
<property name="antlib.dir" value="${basedir}/antlib"/>
<property name="antcontrib.dir" value="${antlib}/antcontrib"/>
<!-- Set up the ant contrib tasks for your use -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${antcontrib.dir}"/>
</classpath>
</taskdef>
<target name="select-test"
description="Select the tests to run"
depends="test-compile"
if="junit-tests">
<for parameter="module"
list="${junit-tests}"
delimiter=" ">
<sequential>
<junit
fork="true"
...>
<batchtest todir="$target/unit-tests">
<fileset dir="${test.destdir}">
<include name="**/#{module}.class"/>
</fileset>
</junit>
</sequential>
</for>
</target>
You cab now run multiple tests like this:
$ ant -D"test-one test-two test-three" select-test
You could try this to access one target at a time. Add these lines to your build.xml file :
<project name="whatever" default="default">
<input message="Please select module:" addproperty="mod" />
<target name="default" depends="${mod}/>
...
</project>
This allows you to enter the module you want to execute and execute that itself instead of running the whole build.xml
You might need to make a few more changes to your build.xml for this to work perfectly.
For the arguments , there is Facility called property. You need to set the property. As in ANT plain arguments is taken as target name.
Lest say you have two modules in your project ModuleX and ModuleY where ModuleX has 2 testcases to run and ModuleY with 10 testcases.
You could do something like this :
ant runTestsOnModule -Dtestmodule="ModuleX"
OR to test all modules by calling
ant tests
<target name="runTestsOnModule">
<antCall target="testcase${testmodule}"/>
</target>'
<! -- run single module -->
<target name="runTestsOnModule">
<antCall target="testcase${testmodule}"/>
</target>
<!--run all tests-->
<target name="tests">
<antcall target="testcaseModuleX">
<antcall target="testCaseModuleY">
</target>
<target name="testcaseModuleX">
..run junit task to call 2 testcase
</target>
<target name="testcaseModuleY">
....run junit task to call 10 testcase
</target>

Is there a way to guarantee that an ant dependency is run only once?

My question is similar to avoiding-re-building-prerequisites-in-ant, except that my need doesn't involve created objects, but processes invoked, so the solutions discussed there won't work for me. At least I think so - but I'm new to ant.
My situation is that I'm writing a set of ant targets, and I need the lets-call-it setup target to be executed once and only once, no matter which target is invoked. Here's a greatly simplified example:
<?xml version="1.0"?>
<project name="Ant_Test" basedir=".">
<target name="setup">
<echo message="In setup" />
</target>
<target name="do.several" depends="setup">
<echo message="In do.several, calling do.first" />
<antcall target="do.first" />
<echo message="In do.several, calling do.second" />
<antcall target="do.second" />
</target>
<target name="do.first" depends="setup">
<echo message="In do.first" />
</target>
<target name="do.second" depends="setup">
<echo message="In do.second" />
</target>
</project>
I need setup to be invoked exactly once, regardless of whether do.several, do.first, or do.second are invoked. With my naive attempt above, invoking do.several results in three calls to setup.
I've thought of setting a property (let's call it setup.has.been.invoked), and using that to conditionally invoke setup from within each target, but it appears that property setting is limited to the scope it's done in, so if in setup, I set setup.has.been.invoked to true, that value only exists within setup.
What am I missing? Is there a section of the tutorials or online documentation I've skipped? Any pointers or hints?
You should remove the antcalls and add do.first and do.second as dependencies of do.several:
<target name="do.several" depends="setup, do.first, do.second">
</target>
This will make sure, that setup is only called once:
setup:
[echo] In setup
do.first:
[echo] In do.first
do.second:
[echo] In do.second
do.several:
BUILD SUCCESSFUL
Total time: 0 seconds
Documentation says why a property set in setup does not work with antcall:
The called target(s) are run in a new project; be aware that this means properties, references, etc. set by called targets will not persist back to the calling project.
I just would like to add another possible way to do this.
<target name="setup" unless="setup.already.executed">
<echo message="In setup" />
<property name="setup.already.executed" value="x" />
</target>
This way you run it only once and then instantly set the flag that it was already executed once. Also it doesn't break the "depends" part of your code, since it only runs targets if it is possible/necessary, but it doesn't break the execution of the target dependent target.
Also this is the least amount of change in your scripts.
Edit:
Explanation of the 'doesn't break the depends part' :
If 'ant do.first do.second' is invoked, it results in setup being called twice even with all targets using setup as a dependency. That would be a problem if setup is doing things like cloning a repo or other time consuming operations. This approach works for both cases - i.e. 'ant do.several' or 'ant do.first do.second' .
An alternative to the answers you've already received is to create a custom task container that makes sure it does not repeat an action. I have such a custom task in my personal Antlib, but there's a whole load of other junk in there that you probably don't want, so maybe you could just copy the source and add it to your own project. It looks something like this:
import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.BuildException;
import java.util.List;
import java.util.LinkedList;
/**
* Task container to ensure that some set of actions is only performed
* once per build. On completion of the actions a property is set that
* prevents subsequent executions.
*/
public class Once extends Task implements TaskContainer
{
private final List<Task> tasks = new LinkedList<Task>();
private String property;
/**
* The name of the property to consult in order to determine whether
* the nested tasks should be performed. This is a required attribute.
*/
public void setProperty(String property)
{
this.property = property;
}
public void addTask(Task task)
{
tasks.add(task);
}
#Override
public void execute() throws BuildException
{
if (property == null || property.length() == 0)
{
throw new BuildException("Property name must be specified.");
}
// If no value is specified, the tasks are performed if the property
// is set to any value. If a value is specified, the tasks are only
// performed if the property matches that value.
if (getProject().getProperty(property) == null)
{
for (Task task : tasks)
{
task.perform();
}
getProject().setProperty(property, "done");
}
}
}
Targets can have an "unless" element that will skip the target if the property referenced by "unless" is set.
See the difference, between include and import in the Ant manual. Also use macrodefs.
I've slightly adapted your example, you'll need several files:
build.xml, common.xml and macrodef_project_setup.xml
build.xml
<?xml version="1.0"?>
<project name="Ant_Test" basedir="." default="init">
<import file="common.xml"/>
<!-- This target overridden by the one in common.xml -->
<target name="common.init"/>
<target name="setup" depends="init"/>
<target name="do.several" depends="common.setup">
<echo message="In do.several, calling do.first" />
<antcall target="do.first" />
<echo message="In do.several, calling do.second" />
<antcall target="do.second" />
</target>
<target name="do.first" depends="common.setup">
<echo message="In do.first" />
</target>
<target name="do.second" depends="common.setup">
<echo message="In do.second" />
</target>
</project>
common.xml
<?xml version="1.0"?>
<project name="common">
<target name="init">
<project_setup option="Stack.Over.Flow"/>
</target>
<target name="setup">
</target>
<import file="macrodef_project_setup.xml"/>
</project>
macrodef
<?xml version="1.0"?>
<project name="project_setup" basedir=".">
<macrodef name="project_setup">
<attribute name="option" default=""/>
<sequential>
<!-- some process -->
<echo>THIS IS MY SETUP OPTION: #{option}</echo>
</sequential>
</macrodef>
</project>
Output:
ant -p
Buildfile: build.xml
Main targets:
Other targets:
common.setup
do.first
do.second
do.several
init
setup
Default target: init
Default target is now init.
ant
Buildfile: build.xml
Ant_Test.init:
[echo] In setup initialization
[echo] THIS IS MY SETUP OPTION: Stack.Over.Flow
But you could still use ant setup.
ant setup
Buildfile: build.xml
Ant_Test.init:
[echo] In setup initialization
[echo] THIS IS MY SETUP OPTION: Stack.Over.Flow
Run it with do.several.
ant do.several
Buildfile: build.xml
Ant_Test.init:
[echo] In setup initialization
[echo] THIS IS MY SETUP OPTION: Stack.Over.Flow
Ant_Test.do.several:
[echo] In do.several, calling do.first
Ant_Test.do.first:
[echo] In do.first
[echo] In do.several, calling do.second
Ant_Test.do.second:
[echo] In do.second

Resources