Multiple depends in Ant task - ant

If I have three targets, one all, one compile and one jsps, how would I make all depend on the other two?
Would it be:
<target name="all" depends="compile,jsps">
...or would it be:
<target name="all" depends="compile","jsps">
Or maybe something even different?
I tried searching for example ant scripts to base it off of, but I couldn't find one with multiple depends.

The former:
<target name="all" depends="compile,jsps">
This is documented in the Ant Manual.

It's the top one.
Just use the echo tag if you want to quickly see for yourself
<target name="compile"><echo>compile</echo></target>
<target name="jsps"><echo>jsps</echo></target>
<target name="all" depends="compile,jsps"></target>
You can also look at the antcall tag if you want more flexibility on ordering tasks

<target name="all" depends="compile,jsps">
This is documented in the Ant Manual.

An alternate way is to use antcall which is more flexible if you want to run the depending targets in parallel. Assuming compile and jsps can be run in parallel (i.e in any order), all target can be written as:
<target name="all" description="all target, parallel">
<parallel threadCount="2">
<antcall target="compile"/>
<antcall target="jsps"/>
</parallel>
</target>
Note that if targets can not be run in parallel, it is preferable to use the first flavor with depend attribute because antcalls are resolved only when executed and if the called target does not exists, the build will fail only at that point.

Related

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" />

Ant: javac with proc:only from Ant?

Is there any way to enforce javac task to invoke only annotation processing, without compilation. -proc:only javac option is supposed to enforce such behaviour, according to javac documentation.
But the following snippet of ant buildfile:
<target name="apt">
<javac srcdir="src" destdir="bin" includeantruntime="false">
<compilerarg value="-proc:only"/>
</javac>
</target>
Compiles project anyway. I experimented with other <compilerarg> tag versions (e.g. line instead of value) but nothing helped.
Avoid specifying the "destdir" attribute of the task, or use an empty directory as a destination for class files. The Ant "javac" task will then look for the class files either in the base directory (if you leave "destdir" unset) or in the empty directory. Because it will not find the classs files there, it will not exclude the potentially up-to-date sources from the compilation and execute "javac" on the sources from the directory specified in the "srcdir" attribute.
Your code would therefore look like this:
<target name="apt">
<javac srcdir="src" includeantruntime="false">
<compilerarg value="-proc:only" />
</javac>
</target>
or, if you use the empty directory approach, like this:
<target name="apt">
<mkdir dir="empty" />
<javac srcdir="src" destdir="empty" includeantruntime="false">
<compilerarg value="-proc:only" />
</javac>
</target>
The second approach is slightly more complex but a bit more clean. Usually your project will have an output directory where you put compiled classes and packaged jars, so adding an extra empty directory there would not hurt. As of Ant version 1.9.4, I did not find any other way to do annotation processing from Ant independently of compilation, even though a simple "force" attribute in the "javac" task could solve this problem.

Is there a way to call the ant 'ant' target with '-lib' option

I'm developing an ant script which is calling another ant script using the <ant> task. This ant script is an installer a Java product and is to be used by our customers, who will have ant installed separately.
The script being called uses the antlr task <antlr:ant-antlr3>. To do this I must place the ant-antlr3.jar file in the ant lib directory, as well as adding antlr-3.2.jar to the classpath.
But I don't want to have this dependency of having ant-antl3.jar file in the client's own installed version of ant.
Is there a way of providing the equivalent to ant's command-line '-lib' option to specify other paths for jars to be added to antlib using the <ant> task itself?
I've taken a look at the online docs and there doesn't seem to be a way.
Thanks
I believe the accepted way to do this is to manually set up your classpath in the build file rather than implicitly including it via the global ant lib directory. i.e.
<path id="master-classpath">
<fileset dir="${lib}" />
<fileset file="${findbugs-base}/lib/annotations.jar" />
<pathelement location="${build-classes}" />
</path>
You can then use this path element in any task that can accept classpath args such as javac
<javac
destdir="${out}"
source="1.5"
target="1.5"
debug="true">
<src path="${src}" />
<classpath refid="master-classpath" />
</javac>
This way, the global ant set up isn't a dependency, and you can specify any files you might need for any build, as specifically as you need to (down to a given call or target).
Obviously, this is all to be carried out in the build file you're calling from the clients' build file. This way, when you call out to yours, the classpath will be set up exactly as you desire.
Another far less idiomatic possibility would be to literally shell out with the Exec Task and call ant that way. Obviously, with the provision of the Ant task, the developers of ant don't recommend you doing that. It is an option, nonetheless.
Tim's answer gives most of the story, but in order to run Ant and set JVM options, you'd need to invoke it via the java task.
There is an example of running this way in the Ant docs, here slightly modified to include -lib:
<java
classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="${sub.builddir}"
timeout="4000000"
taskname="startAnt"
>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
</classpath>
<arg value="-lib"/>
<arg value="${path.to.your.antlr.jar}"/>
<arg value="-buildfile"/>
<arg file="${sub.buildfile}"/>
<arg value="${sub.target}"/>
</java>

Ant for other ant's

I have several projects, most of them has "test" target, which run tests and store results in property 'test.faulire'.
All projects located in same directory:
big_project / someproject1
big_project / someproject1 / build.xml
big_project / someproject2
big_project / someproject2 / build.xml
So, in root of 'big_project' i want to create one build.xml for:
Running test on all projects
If all test ok, run "deploy" task on each project. It'll be very well
if I could pass some deployment
parameters to each project.
How would you realize this scenario ?
You might have a look at the for task in ant-contrib. With it you could iterate over all directories like that:
<for param="dir">
<path>
<dirset dir="." includes="*"/>
</path>
<sequential>
<ant dir="${dir}" antfile="${dir}/build.xml" target="aTarget" />
</sequential>
</for>
Have a look at the Ant manual page on the 'subant' task. The page contains examples on how to use the task the way you want to.

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>

Resources