Creating Ant classpath out of project names - ant

In an ant build script I have a list of projects we are depending on. I need to create a classpath for compilation.
I have:
included.projects=ProjectA, ProjectB
and I need:
included.project.classpath=../ProjectA/bin, ../ProjectB/bin
current code:
<echo message="${included.projects}" />
<pathconvert property="included.projects.classpath" dirsep="," >
<map from="" to="../"/>
<path location="${included.projects}"/>
</pathconvert>
<echo message="${included.projects.classpath}" />
<javac srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false" source="1.6">
<classpath>
<pathelement path="${classpath}" />
<dirset includes="${included.projects.classpath}" />
</classpath>
</javac>
I've tried it with explicit declaration too, but didn't work:
<path id="modules.classpath">
<fileset dir="../ModuleA/bin" />
<fileset dir="../ModuleB/bin"/>
</path>
<path id="libraries.classpath">
<fileset dir="lib" includes="*.jar"/>
</path>
<javac srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false" source="1.6">
<classpath refid="libraries.classpath" />
<classpath refid="modules.classpath" />
</javac>
I'm curious, what is the problem with explicit declaration code, and is it possible to solve with the comma-separated-string to classpath solution.

I think it would be simpler to explicity declare the classpath at the top of your build as follows:
<path id="compile.path">
<fileset dir="../ProjectA/bin" includes="*.jar"/>
<fileset dir="../ProjectB/bin" includes="*.jar"/>
</path>
Used as follows:
<javac srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false" source="1.6">
<classpath>
<path refid="compile.path"/>
<pathelement path="${classpath}" />
</classpath>
</javac>
Note:
I read your question again and just realised that you're not using jar files built by the other projects, are you? .... Not a great idea....

Related

ant multiple source directories with copied resources

Consider minimal build.xml fragment which builds jar from sources and includes all non-java resources:
<property name="src.dir" value="src" />
<target name="build">
<javac destdir="bin">
<src path="${src.dir}" />
</javac>
<copy includeemptydirs="false" todir="bin">
<fileset dir="${src.dir}">
<exclude name="**/*.java" />
</fileset>
</copy>
<jar destfile="dist/foo.jar" basedir="bin"/>
</target>
Now imagine that I need to support a list of source directories:
<property name="src.dirs" value="src;src-gen" />
How can i modify above script to make it happen ?
javac will happily take list of directories but for copy I need to transform string into list of filesets with exclusions or find some other way.
Normally, you simply list them all together:
<javac destdir="bin">
<src path="${src.dir}"/>
<src path="${src2.dir}"/>
<src path="${src3.dir}"/>
</javac>
You can try the <sourcepath/> attribute. I've never used it, but I believe you can use it to define a path of various source files, and use that:
<path id="source.path">
<pathelement path="${src.dir}"/>
<pathelement path="${src2.dir}"/>
<pathelement path="${src4.dir}"/>
</path>
<javac destdir="bin">
srcpathref="source.path"/>
The first will work, but not 100% sure about the second.
I'm not sure of a way to do it with built-in Ant tasks but you could use an ant-contrib <for> task
<path id="src.path">
<pathelement location="src" />
<pathelement location="src-gen" />
</path>
<target name="build">
<javac destdir="bin">
<src refid="src.path" />
</javac>
<for param="dir">
<path refid="src.path" />
<sequential>
<copy includeemptydirs="false" todir="bin">
<fileset dir="#{dir}">
<exclude name="**/*.java" />
</fileset>
</copy>
</sequential>
</for>
<jar destfile="dist/foo.jar" basedir="bin"/>
</target>
The simple solution is to just specify multiple filesets, in the same manner as the javac task supports multiple "src" attributes:
<target name="build" depends="init" description="Create the package">
<javac destdir="${classes.dir}" includeantruntime="false">
<src path="src/main1/java"/>
<src path="src/main2/java"/>
</javac>
<copy todir="${classes.dir}" includeemptydirs="false">
<fileset dir="src/main1" excludes="**/*.java"/>
<fileset dir="src/main2" excludes="**/*.java"/>
<flattenmapper/>
</copy>
</target>
This of course assumes that the number of source code locations is fixed, which is not unreasonable to expect.
If you want to drive this using a list property you must resort to embedding a script within your build to process this list (I can't endorse ant-contrib):
<project name="demo" default="build">
<property name="src.dirs" value="src/main1,src/main2"/>
<property name="build.dir" location="build"/>
<property name="classes.dir" location="${build.dir}/classes"/>
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.6/groovy-all-2.1.6.jar"/>
</target>
<target name="init">
<mkdir dir="${classes.dir}"/>
</target>
<target name="build" depends="init" description="Create the package">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
def srcDirs = properties["src.dirs"].split(",")
ant.javac(destdir:properties["classes.dir"], includeantruntime:false) {
srcDirs.each {
src(path:"${it}/java")
}
}
ant.copy(todir:properties["classes.dir"], includeemptydirs:false) {
srcDirs.each {
fileset(dir:it, excludes:"**/*.java")
}
flattenmapper()
}
</groovy>
</target>
<target name="clean" description="Cleanup build dirs">
<delete dir="${build.dir}"/>
</target>
</project>
Notes:
Compare the "build" targets. You'll notice that the groovy solution calls ANT in the same manner. This is why I really like groovy's integration with ANT.
Example also includes a "bootstrap" target to download the groovy jar dependency from Maven Central. You could alternatively use ivy to manage your build's dependencies.
A simple solution without ant-contrib tasks or embedded scripts:
<property name="src.dirs" value="src,src-gen" />
<path id="src.path">
<multirootfileset type="dir" basedirs="${src.dirs}"/>
</path>
<target name="build">
<javac destdir="bin">
<src refid="src.path"/>
</javac>
<copy todir="bin">
<multirootfileset type="file" basedirs="${src.dirs}">
<exclude name="**/*.java"/>
</multirootfileset>
</copy>
<jar destfile="dist/foo.jar" basedir="bin"/>
</target>
multirootfileset to the rescue! ;-) Needs Ant 1.9.4 or higher.

having several directories for libs in ant

How can I show Ant that libraries exist in two different directories?
Right now I have
<property name="lib" value="C:/apache-ant-1.8.4/lib" />
<target name="compile" depends="init">
<javac source="1.6" srcdir="${src}" fork="true" destdir="${bin}" encoding="UTF-8" >
<classpath>
<pathelement path="${bin}">
</pathelement>
<fileset dir="${lib}">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
It's fine if I copy all the libs to the ant \lib folder. How can I show Ant that there are two directories with libraries?
Just add another fileset:
<property name="lib" value="C:/apache-ant-1.8.4/lib" />
<property name="otherLib" value="C:/somePath/lib" />
<target name="compile" depends="init">
<javac source="1.6" srcdir="${src}" fork="true" destdir="${bin}" encoding="UTF-8" >
<classpath>
<pathelement path="${bin}" />
<fileset dir="${lib}">
<include name="**/*.jar" />
</fileset>
<fileset dir="${otherLib}">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>

Cobertura generates my reports for code coverage, but the coverage shows as 0%

All of my reports get generated, but my coverage shows as 0%. I even created one dummy test to make sure it wasn't the way my tests were written, and it doesn't show for the one dummy class I'm covering. Here is my Ant build for this:
<?xml version="1.0" encoding="UTF-8" ?>
<project name="My Project Name" default="run.cobertura" basedir=".">
<description>My Description</description>
<!-- target: init -->
<target name="init">
<!-- create properties and directory structure -->
<property name="src.path" value="${basedir}/src" />
<property name="lib.path" value="${basedir}/lib" />
<property name="output.path" value="${basedir}/bin" />
<property name="testcase-unit-only.path" value="${basedir}/testcase-unit-only" />
<property name="testcase-unit-only.output.path" value="${basedir}/test-classes" />
<property name="cobertura.lib.path" value="${basedir}/lib-cobertura" />
<property name="cobertura.path" value="${basedir}/cobertura" />
<property name="cobertura.output.path" value="${cobertura.path}/bin" />
<property name="cobertura.reports.path" value="${cobertura.path}/reports" />
<property name="cobertura.data.file" value="${cobertura.path}/cobertura.ser" />
<delete dir="${testcase-unit-only.output.path}" />
<delete dir="${cobertura.path}"/>
<mkdir dir="${testcase-unit-only.output.path}"/>
<mkdir dir="${cobertura.path}"/>
<mkdir dir="${cobertura.output.path}"/>
<!-- define classpath references -->
<path id="cp.lib.path">
<fileset dir="${lib.path}">
<include name="*.jar"/>
</fileset>
</path>
<path id="cp.classes.path">
<pathelement path="${output.path}" />
</path>
<path id="cp.classes.test.path">
<pathelement path="${testcase-unit-only.output.path}" />
</path>
<path id="cp.lib.cobertura.path">
<fileset dir="${cobertura.lib.path}">
<include name="*.jar"/>
</fileset>
</path>
<path id="cp.all.path">
<path refid="cp.lib.path"/>
<path refid="cp.classes.path"/>
<path refid="cp.lib.cobertura.path"/>
</path>
</target>
<!-- target: run.cobertura-instrument -->
<target name="run.cobertura-instrument">
<taskdef classpathref="cp.lib.cobertura.path" resource="tasks.properties"/>
<cobertura-instrument todir="${cobertura.output.path}" datafile="${cobertura.data.file}">
<fileset dir="${output.path}">
<include name="**/*.class" />
</fileset>
</cobertura-instrument>
</target>
<!-- target: compile.classes -->
<target name="compile.classes">
<javac srcdir="${src.path}" destdir="${output.path}">
<classpath refid="cp.lib.path"/>
</javac>
</target>
<!-- target: compile.tests -->
<target name="compile.tests">
<javac srcdir="${testcase-unit-only.path}" destdir="${testcase-unit-only.output.path}">
<classpath refid="cp.all.path"/>
</javac>
</target>
<!-- target: run.junit -->
<target name="run.junit">
<junit fork="true" dir="${basedir}" failureProperty="test.failed">
<classpath location="${cobertura.output.path}"/>
<classpath location="${output.path}"/>
<sysproperty key="net.sourceforge.cobertura.datafile" file="${cobertura.data.file}" />
<classpath refid="cp.lib.path"/>
<classpath refid="cp.classes.test.path"/>
<classpath refid="cp.lib.cobertura.path"/>
<formatter type="xml" />
<!-- <formatter type="brief" usefile="false"/> -->
<batchtest todir="${testcase-unit-only.output.path}" unless="testcase">
<fileset dir="${testcase-unit-only.output.path}">
<include name="**/*UnitTest.java"/>
</fileset>
</batchtest>
</junit>
</target>
<!-- target: run.cobertura -->
<target name="run.cobertura" depends="init,run.cobertura-instrument,compile.classes,compile.tests,run.junit">
<cobertura-report srcdir="src" destdir="${cobertura.reports.path}" datafile="${cobertura.data.file}"/>
</target>
</project>
One thing I notice is that in the depends list for the run.cobertura target you instrument the compiled classes before you compile them. That might work if you run twice, assuming the compiled classes from the first run are not cleared down, but doesn't seem quite right. On the first run if there are no instrumented classes, your report would be empty.
I had the same ant build scripts. It worked on my local workstation, but didn't on jenkins server.
But server had jdk 7 and workstation jdk6. After changing jdk on jenkins server to jdk6, code coverage generates without any problem.
you must set debug on when you compile java
<javac **debug="on"** srcdir="${testcase-unit-only.path}" destdir="${testcase-unit-only.output.path}">

Execute a jar file using Ant

I am trying to create a runnable jar file from java classes using ant. The java classes use external jars. When I execute the build.xml its showing class not found exception while running the java program. Its compiling fine.
Part of My source code:
<path id="project-libpath">
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<path id="project-classpath">
<fileset dir="C:/xmldecode/lib">
<include name="*.jar"/>
</fileset>
</path>
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}" destdir="${classes.dir}">
<classpath refid="project-classpath"/>
</javac>
</target>
<target name="jar" depends="compile">
<copy todir="${classes.dir}">
<fileset dir="C:/xmldecode/lib"/>
</copy>
<pathconvert property="mf.classpath" pathsep=";">
<path refid="project-classpath" />
<flattenmapper />
</pathconvert>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="Class-Path" value="${mf.classpath}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
</java>
Your problem is that the manifest classpath entries are not separated by a ";" character.
The following will work better I think:
<pathconvert property="mf.classpath" pathsep=" ">
<path refid="project-classpath" />
<flattenmapper />
</pathconvert>
Could I suggest using the new ANT task manifestclasspath ?
<manifestclasspath property="mf.classpath" jarfile="${jar.dir}/${ant.project.name}.jar">
<classpath refid="project-classpath" />
</manifestclasspath>
This powerful method will determine paths relative to the jar's location, for example if the jar's dependencies are located in a lib directory

Generate manifest class-path from <classpath> in Ant

In the build file below, the jar target refers to the jar.class.path property for the manifest class-path. The compile target refers to project.class.path
There is redundancy here, because jar.class.path and project.class.path are very similar. They must be both updated when libraries are added, which can be a pain if the list of libraries gets very long. Is there a better way? Any solution must be cross-platform and always use relative paths.
Edit:
It should generate the JAR classpath from a fileset and not the other way around, so I can use wildcards to e.g. include all JAR files in a directory.
<?xml version="1.0"?>
<project name="Higgins" default="jar" basedir=".">
<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>
<path id="project.class.path">
<pathelement location="build"/>
<fileset dir="lib">
<include name="forms-1.2.0.jar"/>
<include name="BrowserLauncher.jar"/>
</fileset>
</path>
<target name="prepare">
<mkdir dir="build"/>
</target>
<target name="compile" depends="prepare" description="Compile core sources">
<javac srcdir="src"
includes="**"
destdir="build"
debug="true"
source="1.5">
<classpath refid="project.class.path"/>
</javac>
</target>
<target name="jar" depends="compile" description="Generates executable jar file">
<jar jarfile="higgins.jar">
<manifest>
<attribute name="Main-Class" value="nl.helixsoft.higgins.Main"/>
<attribute name="Class-Path" value="${jar.class.path}"/>
</manifest>
<fileset dir="build" includes="**/*.class"/>
<fileset dir="src" includes="**/*.properties"/>
</jar>
</target>
</project>
<path id="build.classpath">
<fileset dir="${basedir}">
<include name="lib/*.jar"/>
</fileset>
</path>
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="build.classpath"/>
<mapper>
<chainedmapper>
<flattenmapper/>
<globmapper from="*.jar" to="lib/*.jar"/>
</chainedmapper>
</mapper>
</pathconvert>
<target depends="compile" name="buildjar">
<jar jarfile="${basedir}/${test.jar}">
<fileset dir="${build}" />
<manifest>
<attribute name="Main-Class" value="com.mycompany.TestMain"/>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
</target>
For further information check out this article.
Assuming Ant 1.7 or above, you can use the manifestclasspath task.
<path id="dep.runtime">
<fileset dir="./lib">
<include name="**/*.jar" />
</fileset>
</path>
<property name="dep_cp" value="${toString:dep.runtime}" />
<target name="default">
<manifestclasspath property="manifest_cp" jarfile="myjar.jar">
<classpath refid="dep.runtime" />
</manifestclasspath>
<echo message="Build Classpath: ${dep_cp}" />
<echo message="Manifest Classpath: ${manifest_cp}" />
</target>
If you just want a common subpath shared between two (or more) paths, that is easy to do:
<path id="lib.path>
<fileset dir="lib">
<include name="forms-1.2.0.jar"/>
<include name="BrowserLauncher.jar"/>
</fileset>
</path>
<path id="project.class.path">
<pathelement location="build"/>
<path refid="lib.path"/>
</path>
<property name="jar.class.path" refid="lib.path"/>
EDIT Sorry, I misunderstood the question. Try this:
<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>
<path id="project.class.path">
<pathelement location="build"/>
<fileset dir="." includes="${jar.class.path}"/>
</path>
You can use <pathconvert> to convert a path (which can contain a fileset) into a plain string. You'll likely need to <echo> that string to a file, use either <replace> or <replaceregexp> to chop the leading path bits, then finally use <loadfile> to load the manipulated string into the final property.
Implementation left as an exercise to the reader.

Resources