Running ANT within ANT under a different JVM |
|
| Written by Mark Bools |
| Thursday, 24 March 2011 06:00 |
|
Problem You have set up a continuous integration build using CruiseControl. The build loop initiates your build using an ANT script mainBuild.xml. This mainBuild.xml needs to invoke several other build files, but (and here’s the catch) you want the sub-builds to use a different JDK. Using the ant task will invoke the sub-build using the [...]
ProblemYou have set up a continuous integration build using CruiseControl. The build loop initiates your build using an ANT script mainBuild.xml. This mainBuild.xml needs to invoke several other build files, but (and here’s the catch) you want the sub-builds to use a different JDK. Using the ant task will invoke the sub-build using the same context as the calling script. Changing JAVA_HOME will have no effect on the Java used by the sub-build. How then, can you invoke the sub-builds with the correct Java context? SolutionsOne obvious solution is to create wrapper scripts (bat or sh, for example) that set the context for you and then invoke the ‘real’ ANT script. This will work, but lacks elegance and means adding in the wrapper scripts — more maintenance work. A better, more elegant, solution is to invoke ANT directly from the mainBuild.xml using the java task. The listing below shows a macro that wraps the direct invocation of ANT to provide simplify calling ANT this way. Note: This macro requires ant-contrib.
<macrodef name="runAntWithJVM">
<attribute name="buildFile"/>
<attribute name="buildDir"/>
<attribute name="target"/>
<attribute name="cmdLineArgs" default=""/>
<attribute name="javaHome" default="${JAVA_HOME}"/>
<attribute name="timeout" default="4000000"/>
<attribute name="maxMemory" default="512m"/>
<sequential>
<var name="l.javaresult" unset="true"/>
<var name="l.javaoutput" unset="true"/>
<var name="l.level" value="info"/>
<java classname="org.apache.tools.ant.launch.Launcher"
jvm="@{javaHome}/bin/java"
fork="true"
failonerror="false"
resultproperty="l.javaresult"
outputproperty="l.javaoutput"
dir="@{buildDir}"
timeout="@{timeout}"
maxmemory="@{maxMemory}"
taskname="startAnt">
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
</classpath>
<arg value="-buildfile"/>
<arg file="@{buildDir}/@{buildFile}"/>
<arg value="-DJAVA_HOME=@{javaHome}"/>
<arg line="@{cmdLineArgs}"/>
<arg value="@{target}"/>
</java>
<if>
<not>
<equals arg1="${l.javaresult}" arg2="0"/>
</not>
<then>
<var name="l.level" value="error"/>
</then>
</if>
<echo level="${l.level}">System build output:
${l.javaoutput}
Returned status:${l.javaresult}</echo>
<fail>
<condition>
<not>
<equals arg1="${l.javaresult}" arg2="0"/>
</not>
</condition>
</fail>
</sequential>
</macrodef>
Line 01 declares the macro and lines 02-08 setup the macro’s attributes. Lines 09-12 set up some local properties that are used to capture output from the sub-build ANT file so that it can be reported back as part of the mainBuild.xml output. Lines 13-31 are the real meat of this macro. Lines 13-22 set up the java task, lines 23-25 simply put the ant-launcher.jar onto the classpath (it is the ant-launcher that is used to run ANT in the new context). Lines 26-30 are the command line arguments to be passed to the new JVM initiated by the java task. Notice that the JAVA_HOME is set explicitly here and will match the JVM invoked for the sub-build. Returning to lines 13-22. Line 13 provides the entry point class into ant-launcher. Line 14 is the one that does the magic, it tells the java task to use a specific JVM to run. Line 15 ensures that a new JVM is used (fork is not true then the jvm setting is ignored and the sub-build will run in the same JVM as mainBuild.xml). Line 16 ensures that any failure of the sub-build will not bring down the mainBuild.xml. We need this so that output from the sub-build can be properly reported before mainBuild.xml fails gracefully. Line 17 collects the return status of the sub-build and is used to decide if the mainBuild.xml should fail after reporting the output of the sub-build. Line 18 collects all the output from the sub-build into a property. Line 19 sets a default working directory. In this case it is set to the sub-build directory provided by the caller. Line 20 sets a timeout (in milliseconds) that we are willing to have the java task run for. This is a backstop that prevents our build hanging indefinitely. Line 21 sets a maxMemory for the forked JVM (you may not need to set it this high, or you may need to make it higher, all depends on your sub-build requirements). Line 22 changes the task name reported in logging information (it’s just a bit clearer than seeing [Java] all the way through the log. The remainder of the macro just marshals the output of the sub-build, reports it and then decides whether to throw a fatal error if the sub-build failed. Using the macroJust invoke it with a command like the following.
<runAntWithJVM buildDir="${basedir}/subBuild"
buildFile="bulid.xml"
target="all"
javaHome="C:/Program Files/java/jdk1.6.15_05">
This will run the subBuild/build.xml hitting the target all using the 1.6.15_05 JDK, no matter which JVM the original build file was invoked using. Filed under: ANT, Plain Old Blog, Tools 'n' Tips Tagged: ANT, Java, JDK
Set as favorite
Bookmark
Email this
Hits: 267 Trackback(0)Comments (0)
|



