Java ant help, differing fileset to be used for different targets - java

I'm new to Ant, so I'm looking for ideas here.
I'm looking for a way to use a different fileset per ANT target, and I'm not finding any luck reading the ANT documentation. To be concrete, here is what I have:
<fileset id="MY-FILESET-ONE" dir="..." />
<include name="**/*.java />
</fileset>
<fileset id="MY-FILESET-TWO" dir="..." />
<include name="**/*.other />
</fileset>
<target name="BASETARGET" depends="...">
<fileset refid="MY-FILESET-ONE" />
</target>
<target name="ANT-TARGET-ONE" depends="BASETARGET">
<fileset refid="MY-FILESET-ONE" />
</target>
<target name="ANT-TARGET-TWO" depends="BASETARGET" />
<fileset refid="MY-FILESET-TWO" />
</target>
What I want to do is have the fileset that the target BASETARGET uses be different depending on which target is invoked. If ANT-TARGET-ONE is invoked, use a different fileset, than if ANT-TARGET-TWO is invoked.
Here's something like I envision:
<target name="BASETARGET" depend="...">
<fileset refid="${myvar} />
</target>
<target name="ANT-TARGET-ONE" depends="BASETARGET">
<var name="myvar" value="MY-FILESET-ONE" />
</target>
<target name="ANT-TARGET-TWO">
<var name="myvar" value="MY-FILESET-ONE" />
</target>
How can I achieve this using ant? Basically I want to control which sets of my unit-tests get run depending on the target being invoked? I know properties can only be set once, so I don't think that could possibly work. I looked at the var here: http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html
however, trying to get the value out of 'myvar' like this:
<fileset refid="${myvar} />
results in a error, I'm unsure how to achieve this!

"What I want to do is have the fileset that the target BASETARGET uses be different depending on which target is invoked."
Here's a small example for that: you simply create the filesets with a given ID and refer them in your base target.
<project name="test" basedir=".">
<target name="base">
<copy todir="out">
<fileset refid="files-to-copy"/>
</copy>
</target>
<target name="def-fs-1" >
<fileset id="files-to-copy" dir="in">
<include name="a.txt" />
</fileset>
</target>
<target name="def-fs-2" >
<fileset id="files-to-copy" dir="in">
<include name="b.txt" />
</fileset>
</target>
<target name="t1" depends="def-fs-1,base" />
<target name="t2" depends="def-fs-2,base" />
</project>

Related

Ant Junit task throws java.lang.ClassNotFoundException

I have a simple Junit test that keeps throwing a java.lang.ClassNotFoundException. Below is the folder structure
project:
|__build.xml
|__hamcrest-core-1.3.jar
|__junit.jar
|__src:
| |__Simple.java
|__bin:
|__Simple.class
Simple.java
import org.junit.Test;
public class Simple {
#Test
public void check() {
assert (true);
}
}
build.xml
<?xml version="1.0"?>
<project name="Ant-Test" default="main">
<target name="main">
<junit printsummary="yes" fork="yes" haltonfailure="no">
<classpath path="hamcrest-core-1.3.jar" />
<classpath path="junit.jar" />
<formatter type="plain" />
<batchtest fork="yes" todir="docs">
<fileset dir="bin">
<include name="**.class" />
</fileset>
</batchtest>
</junit>
</target>
</project>
Error:
Testsuite: Simple
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0 sec
Caused an ERROR
Simple
java.lang.ClassNotFoundException: Simple
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:292)
Please help me find the reason for why this error occurs. The script is able to find the test case but at the end an error is thrown.
Add the required resources to the test classpath:
<pathelement path="${classpath}"/>
that in your case will be:
<classpath>
<pathelement path="bin" />
<pathelement location="hamcrest-core-1.3.jar" />
<pathelement location="junit.jar" />
</classpath>
As explained here
To make things a bit more flexible, we add one extra feature, which makes it possible to match multiple directory levels. This can be used to match a complete directory tree, or a file anywhere in the directory tree. To do this, "" must be used as the name of a directory. When ** is used as the name of a directory in the pattern, it matches zero or more directories. For example: /test/ matches all files/directories under /test/, such as /test/x.java, or /test/foo/bar/xyz.html, but not /xyz.xml.
'**' must be used to match folders, and not as wildcard to select partial file names.
Change your ant with:
<fileset dir="bin">
<include name="*.class" />
</fileset>
If you want to select all '*.class' files under every directory under bin/ then use:
<fileset dir="bin">
<include name="**/*.class" />
</fileset>
You will have now an error cause by the test report writer. You need to create a docs folder and everything will work.
The final build.xml will be:
<?xml version="1.0"?>
<project name="Ant-Test" default="main">
<target name="main">
<mkdir dir="docs"/>
<junit printsummary="yes" fork="yes" haltonfailure="no">
<classpath location="hamcrest-core-1.3.jar" />
<classpath location="junit-4.12.jar" />
<classpath path="bin/" />
<formatter type="plain" />
<batchtest fork="yes" todir="docs">
<fileset dir="bin">
<include name="**/*.class" />
</fileset>
</batchtest>
</junit>
</target>
</project>
Please try with following fileset tag:
<fileset dir="bin">
<include name="**.java" />
</fileset>
I'm not sure if junit task admits more than one classpath node, but anyway, it is a good practice to have just one. Moreover, your classpath is missing the classes directory. The right declaration would be like this:
<junit ...>
<classpath>
<pathelement path="bin"/>
<pathelement location="hamcrest-core-1.3.jar"/>
<pathelement location="junit.jar"/>
</classpath>
...
</junit>

running android project with multiple external jars and sources

I am trying to compile an adroid project using ant which contains multiple sources and external 3rd party jars.
It works fine with eclipse but i require it to run through command line using ant.
my custom_rules.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?> <project name="CustomRules">
<target name="-pre-build" >
<copy todir="tmp-src" >
<fileset dir="src" includes="**" />
<fileset dir="talkAndroid" includes="**" />
<fileset dir="commonAndroid" includes="**" />
<fileset dir="cocos2dAndroid" includes="**" />
</copy>
<classpath id="classpath" description="The default classpath.">
<pathelement path="${classpath}"/>
<fileset dir="external_libs">
<include name="*.jar"/>
</fileset>
</classpath>
</target>
<target name="-post-build" >
<delete dir="tmp-src" />
</target> </project>
it isn't working for external_libs and unable to find external libraries, if I copy these jars from external_libs to libs folder ... duplicate class found errors are generated!
What should I do?

Ant build - javac task - exclude a dir then include a subdir

I have a tree like this
path/a
path/b
path/c
path/d/da
path/d/db
path/d/dc
Now in my javac task i want to
Compile everything in path/
Exclude everything in path/d/
Compile everything in path/d/db/
Like this:
path/a
path/b
path/c
path/d/db
I played with include/exclude and patternset but i couldn't achieve what i need.
Is there a way to do this?
The <difference> and <union> set operations will be handy for what you need.
The following Ant script shows how to combine several <fileset> elements into one:
<project name="ant-javac-include-and-exclude" default="run" basedir=".">
<target name="run">
<fileset id="all-files" dir="path">
<include name="**"/>
</fileset>
<fileset id="files-under-d" dir="path">
<include name="d/**"/>
</fileset>
<fileset id="files-under-d-db" dir="path">
<include name="d/db/**"/>
</fileset>
<!-- Matches all files under a, b, c -->
<difference id="all-files-NOT-under-d">
<fileset refid="all-files"/>
<fileset refid="files-under-d"/>
</difference>
<!-- Combine all files under a, b, c and under d/db -->
<union id="files-to-compile">
<difference refid="all-files-NOT-under-d"/>
<fileset refid="files-under-d-db"/>
</union>
<!-- Convert the absolute paths in "files-to-compile" to relative-->
<!-- paths. Also, "includes" of <javac> requires a comma-separated -->
<!-- list of files. -->
<pathconvert property="union-path" pathsep=",">
<union refid="files-to-compile"/>
<map from="${basedir}/" to=""/>
</pathconvert>
<javac
srcdir="."
includes="${union-path}"
includeantruntime="false"
/>
</target>
</project>
The above steps can be combined into the following:
<pathconvert property="union-path" pathsep=",">
<union>
<difference>
<fileset dir="path">
<include name="**"/>
</fileset>
<fileset dir="path">
<include name="d/**"/>
</fileset>
</difference>
<fileset dir="path">
<include name="d/db/**"/>
</fileset>
</union>
<map from="${basedir}/" to=""/>
</pathconvert>
<javac
srcdir="."
includes="${union-path}"
includeantruntime="false"
/>

Refresh doesn't work before creating a war with Ant on Eclipse

On Eclipse I create war files by using ant.
The issue is that in the war file isn't included the right mypropfile.properties.
The file is properly copied, but also if I use <eclipse.refreshLocal resource="projectdir" depth="infinite"/> the old file is included. I have to refresh manually the project.
For Ant I use the "Run in the same JRE as the workspace" option.
<?xml version="1.0" encoding="UTF-8"?>
<project name="MyProject" basedir=".">
<description>
My Project
</description>
<property name="workspace.dir" value="${basedir}/../../"/>
<property name="src" value="${basedir}/../src"/>
<property name="build" value="${basedir}/../build"/>
<property name="build.classes" value="${basedir}/../build/classes"/>
<property name="lib.dir" value="${basedir}/WEB-INF/lib"/>
<property name="web.dir" value="${basedir}/WEB-INF"/>
<property environment="env"/>
<property name="real.dir" value="${basedir}/real"/>
<property name="real2.dir" value="${basedir}/real2"/>
<path id="classpath.server">
<fileset dir="${env.CATALINA_HOME}/lib" includes="*.jar"/>
<pathelement path="${build.classes}"/>
</path>
<path id="classpath.app">
<fileset dir="${lib.dir}" includes="*.jar"/>
</path>
<target name="refreshResource" if="eclipse.refreshLocal">
<eclipse.refreshLocal resource="projectdir" depth="infinite"/>
</target>
<target name="clean">
<delete dir="${build}/classes"/>
<delete dir="${build}"/>
</target>
<target name="init" depends="clean, refreshResource">
<tstamp/>
<mkdir dir="${build}"/>
<mkdir dir="${build}/classes"/>
</target>
<target name="compile" depends="init">
<javac encoding="UTF8" srcdir="${src}" destdir="${build}/classes" includeantruntime="false">
<compilerarg value="-Xlint:unchecked"/>
<classpath>
<path refid="classpath.server.bin"/>
</classpath>
<classpath>
<path refid="classpath.server"/>
</classpath>
<classpath>
<path refid="classpath.app"/>
<fileset dir="${lib.dir}" includes="*.jar"/>
</classpath>
</javac>
</target>
<target name="deleteConfig">
<delete file="${src}/mypropfile.properties"/>
</target>
<target name="real" depends="deleteConfig">
<copy file="${real.dir}/realprop.properties" tofile="${src}/mypropfile.properties"/>
</target>
<target name="real2" depends="deleteConfig">
<copy file="${real2.dir}/real2prop.properties" tofile="${src}/mypropfile.properties"/>
</target>
<target name="war-real" depends="real, compile">
<input message="Warname (without .war):" addproperty="warname"/>
<war destfile="${workspace.dir}/${warname}.war" webxml="${web.dir}/web.xml">
<fileset dir="${basedir}">
<include name="**/*.*"/>
</fileset>
<classes dir="${build.classes}"/>
</war>
</target>
<target name="war-real2" depends="real2, compile">
<input message="Warname (without .war):" addproperty="warname"/>
<war destfile="${workspace.dir}/${warname}.war" webxml="${web.dir}/web.xml">
<fileset dir="${basedir}">
<include name="**/*.*"/>
</fileset>
<classes dir="${build.classes}"/>
</war>
</target>
EDIT
The target clean was wrong, so I've corrected it, but now build failed with error
BUILD FAILED ... Reference classpath.server.bin not found.
Ant doesn't care if Eclipse has refreshed the file or not. eclipse.refreshLocal is only relevant for editors and compilers inside of the IDE.
When you run the Ant build.xml, Ant copies the file in question in the real target into the source folder and compile copies it into ${build}/classes (at least it should do that). So before you create the WAR, you must make sure the compile step has done its work (i.e. look into each file to make sure that a change is visible in each copy).
What worries my is that you use different ways to access the classes:
${build}/classes
${build.classes}
${basedir}/../build/classes
So the first step should be to define a single way to locate the folder and then use this pattern everywhere.
If that doesn't solve your problem, you need to make sure Ant notices that the file has changed. Old filesystems like FAT support only timestamps which have second resolution. If you use an USB stick for your sources, it's possible to change the file and run Ant so fast that Ant thinks the file hasn't changed.
Lastly, you need to check your classpath. If one of the JAR dependencies also contains a file called mypropfile.properties, then Java resource loading can find either version.
This and other problems made me use a different solution to configure WAR files: I pass a system property with the absolute path of the config file. That way, the WAR file doesn't change when the config changes and I have full control over which config file is loaded.

Ant build creates incorrect relative paths to jars when generating manifest

I'm using Ant to build my Java application and to generate the MANIFEST.MF file automatically so it includes all the jars in my lib directory.
This seems to work but the problem is that instead of writing them as lib/some.jar, it includes my Eclipse project's name: MyProject/lib/some.jar.
This is ofcourse incorrect and causes none of the jars to be found when run as a standalone app.
Build.xml (important part is at the end):
<?xml version="1.0"?>
<project name="fidea_migration" default="dist">
<path id="compile.classpath">
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
</path>
<target name="clean" description="cleaning the old deliverables">
<delete includeemptydirs="true">
<fileset dir="bin" includes="**/*"/>
</delete>
<delete includeemptydirs="true">
<fileset dir="_deliverables" includes="**/*"/>
</delete>
</target>
<target name="prepare" description="preparing the deliverables folders">
<mkdir dir="_deliverables/lib"/>
</target>
<path id="jarlib">
<fileset dir="lib/">
<include name="**/*.jar"/>
</fileset>
</path>
<manifestclasspath property="lib.list" jarfile=".">
<classpath refid="jarlib" />
</manifestclasspath>
<target name="compile" depends="clean, prepare" description="compiling java sources">
<mkdir dir="bin"/>
<javac srcdir="src/main/java" destdir="bin">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="dist" depends="compile" description="creating binary distribution">
<copy todir="_deliverables/lib">
<fileset dir="lib"/>
</copy>
<copy todir="_deliverables">
<fileset dir="src/main/resources">
</fileset>
</copy>
<jar jarfile="_deliverables/lib/app.jar" basedir="bin">
<manifest>
<attribute name="Class-Path" value="${lib.list}"/>
</manifest>
</jar>
</target>
</project>
Example of how my Manifest looks:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.4
Class-Path: MyProject/lib/All-MB.jar MyProject/lib/activation.jar MyProject/lib/aspectjrt.jar
Any idea on how to fix this so it just shows xxx.jar instead of MyProject/lib/xxx.jar (so without "MyProject/lib/")?
Cheers,
Bart
manifestclasspath expects the jarfile attribute to point to the location of the JAR file (which probably doesn't exist yet, but that's fine). Since you're creating the JAR file at _deliverables/lib/app.jar and you're also copying all the lib JARs from lib to _deliverables/lib then
<manifestclasspath property="lib.list" jarfile="lib/app.jar">
<classpath refid="jarlib" />
</manifestclasspath>
should do the trick, and will create an eventual Class-Path with the right relative paths, i.e. All-MB.jar activation.jar aspectjrt.jar etc. etc.
You must set your project Dir inside your build.xml as,
<property name="projectDir" value=".." />
After this, you must try to work on everything with relative path. Currently, the reason behind problem is that the absolute path is being used.

Categories

Resources