Use a testing framework (JUnit)
Ant has these characteristics:
Every Java programmer should at least be familiar with Ant.
Using Ant, a build file is made up of tasks, which perform operations commonly needed for builds. The list of tasks is extensive:
<project name="test-ant-builds" default='all' basedir="." > <description> Demonstrate the use of the Ant build tool with a simple Java project. </description> <!-- First define properties, datatypes, and default tasks; then define targets. Any Ant tasks placed outside of any target are always executed first. --> <!-- Override default property values with an external properties file, if present. --> <property file='build.properties'/> <!-- Default property values, if not overridden elsewhere: --> <property name='build' location='build' /> <property name='app.version' value='1.0'/> <property name='app.name' value='Example App'/> <property name='distro-name' value='example-app-${app.version}'/> <tstamp><format property='build.time' pattern='yyyy-MM-dd HH:mm:ss'/></tstamp> <path id='compile.classpath'> <fileset dir='lib'> <include name='*.jar'/> </fileset> </path> <!-- Simply extends the compile.classpath with your own compiled classes. --> <path id='run.classpath'> <path refid='compile.classpath'/> <path location='src'/> </path> <fileset id='class.files' dir='src'> <include name='**/*.class'/> </fileset> <fileset id='files.for.jar' dir='src'> <exclude name='**/*.java'/> <exclude name='**/doc-files/'/> </fileset> <fileset id='test.classes' dir='src'> <include name='**/TEST*.java'/> </fileset> <!-- Text files using Ant's '@' syntax are here called template files. --> <fileset id='template.files' dir='.'> <include name='**/*_template.*'/> </fileset> <!-- Inspect the environment, to see if a deployment host is currently running. --> <condition property='deployment.server.running' value='true' else='false'> <socket port='8081' server='127.0.0.1' /> </condition> <!-- A connection to this URL is used when building javadoc. --> <condition property='jdk.javadoc.visible' value='true' else='false'> <http url='http://java.sun.com/javase/6/docs/api/' /> </condition> <echo> Application: ${app.name} ${app.version} Build File : ${ant.file} Run Date : ${build.time} Run by : ${user.name} Build Dir : ${build} Base Dir : ${basedir} Java Home : ${java.home} Deployment host running: ${deployment.server.running} Connected to the web : ${jdk.javadoc.visible} </echo> <echo message='Create build directory, and its subdirectories.'/> <mkdir dir="${build}/javadoc"/> <mkdir dir="${build}/dist"/> <mkdir dir="${build}/templates"/> <!-- Now define the targets, which use the properties and datatypes defined above. --> <target name='clean' description="Delete all build artifacts." > <delete dir='${build}'/> <delete> <fileset refid='class.files'/> </delete> <mkdir dir="${build}/javadoc"/> <mkdir dir="${build}/dist"/> <mkdir dir="${build}/templates"/> </target> <target name='compile' description='Compile source files and place beside source.'> <javac srcdir="src"> <classpath refid='compile.classpath'/> </javac> <!-- Here's a simple way of debugging a path, fileset, or patternset, using its refid: --> <echo>Classpath: ${toString:compile.classpath}</echo> </target> <target name='test' description='Run all JUnit tests.' depends='compile'> <junit haltonfailure='false'> <classpath> <pathelement location="src"/> </classpath> <batchtest> <fileset refid='test.classes'/> </batchtest> <formatter type='brief' usefile='no'/> </junit> </target> <target name='launch' description='Build and run the program.' depends='compile, test'> <java classname='hirondelle.ante.Launcher' classpathref='run.classpath' failonerror='true'> <arg value="Solar System"/> </java> </target> <target name='jar' description='Create a jar file for distribution.' depends='compile'> <jar destfile='${build}/dist/${distro-name}.jar' manifest='MANIFEST.MF' duplicate='preserve'> <fileset refid='files.for.jar'/> <!-- The static manifest.mf file is merged with additional dynamic items, specified here : --> <manifest> <attribute name='Specification-Version' value='${app.version}'/> <attribute name='Specification-Title' value='${app.name}' /> <attribute name='Implementation-Version' value='${app.version}'/> <attribute name='Implementation-Title' value='${app.name}' /> </manifest> </jar> </target> <target name='javadoc' description='Generate javadoc.' > <javadoc use='true' author='true' version='true' overview='overview.html' access='package' sourcepath='src' packagenames='*.*' destdir='${build}/javadoc' windowtitle='${app.name} ${app.version}' noqualifier='java.*:javax.*:com.sun.*' linksource='true' > <classpath refid='compile.classpath'/> <link href='http://java.sun.com/javase/6/docs/api/'/> <header><![CDATA[<h1>${app.name} ${app.version}</h1>]]></header> </javadoc> </target> <target name='text-templates' description='Process template files, and assign values to @ variables.'> <copy overwrite='true' todir='${build}/templates'> <fileset refid='template.files'/> <!-- New files have 'template' removed from their name : --> <globmapper from='*_template.txt' to='*.txt'/> <filterset> <filter token='app.name' value='${app.name}'/> <filter token='app.version' value='${app.version}'/> <filter token='build.time' value='${build.time}'/> </filterset> </copy> </target> <target name='distro-binary' description='Create zip file with executable jar, docs.' depends='jar, javadoc, text-templates'> <zip destfile='${build}/dist/${distro-name}-binary.zip' duplicate='preserve'> <zipfileset dir='${build}/dist/' includes='${distro-name}.jar'/> <zipfileset dir='${build}/javadoc' prefix='javadoc' /> <zipfileset dir='${build}/templates' includes='README.txt'/> </zip> </target> <target name='distro-source' description='Create zip file with project source code.'> <zip destfile='${build}/dist/${distro-name}-src.zip' duplicate='preserve' > <!-- exclude items specific to the author's IDE setup: --> <zipfileset dir='.' excludes='.classpath, .project'/> </zip> </target> <!-- Add mail.jar and activation.jar to your ANT_HOME/lib! --> <!-- Please edit, using values appropriate to your environment. --> <target name='email' > <mail mailhost='smtp.blah.com' mailport='25' user='blah@blah.com' password='blah' messageMimeType='text/html' tolist='blah@whatever.com' from='blah@blah.com' subject='Build completed.' > <message> <![CDATA[ Test email. <P><a href='http://www.google.com'>link</a> ]]> </message> </mail> </target> <target name='all' description='Create all build artifacts.' depends='clean, compile, test, jar, javadoc, distro-binary, distro-source'> <echo>Finished creating all build artifacts.</echo> </target> </project>Example of running the above build script:
C:\\johanley\\Projects\\ant-test>ant -file build.xml all Buildfile: build.xml [echo] [echo] Application: Example Appl 1.1 [echo] Build File : C:\\johanley\\Projects\\ant-test\\build.xml [echo] Run Date : 2010-07-21 19:14:11 [echo] Run by : John [echo] Build Dir : C:\\@build [echo] Base Dir : C:\\johanley\\Projects\\ant-test [echo] Java Home : C:\\jdk1.5.0\\jre [echo] Deployment host running: true [echo] Connected to the web : true [echo] [echo] Create build directory, and its subdirectories. [mkdir] Created dir: C:\\@build\\javadoc [mkdir] Created dir: C:\\@build\\dist [mkdir] Created dir: C:\\@build\\templates clean: [delete] Deleting directory C:\\@build [delete] Deleting 3 files from C:\\johanley\\Projects\\ant-test\\src [mkdir] Created dir: C:\\@build\\javadoc [mkdir] Created dir: C:\\@build\\dist [mkdir] Created dir: C:\\@build\\templates compile: [javac] Compiling 5 source files [echo] Classpath: C:\\johanley\\Projects\\ant-test\\lib\\junit.jar test: [junit] Testsuite: hirondelle.ante.TESTLauncher [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec jar: [jar] Building jar: C:\\@build\\dist\\example-app-1.1.jar javadoc: [javadoc] Generating Javadoc [javadoc] Javadoc execution [javadoc] Loading source files for package hirondelle.ante... [javadoc] Loading source files for package hirondelle.ante.deluvian... [javadoc] Constructing Javadoc information... [javadoc] Standard Doclet version 1.5.0_07 [javadoc] Building tree for all the packages and classes... [javadoc] Generating C:\\@build\\javadoc\\hirondelle/ante/\\package-summary.html... [javadoc] Copying file C:\\johanley\\Projects\\ant-test\\src\\hirondelle\\ante\\doc-files\\VersionHistory.html to directory C:\\@build\\javadoc\\hirondelle\\ante\\doc-files... [javadoc] Building index for all the packages and classes... [javadoc] Building index for all classes... text-templates: [copy] Copying 1 file to C:\\@build\\templates distro-binary: [zip] Building zip: C:\\@build\\dist\\example-app-1.1-binary.zip distro-source: [zip] Building zip: C:\\@build\\dist\\example-app-1.1-src.zip all: [echo] Finished creating all build artifacts. BUILD SUCCESSFUL Total time: 6 seconds
(<javac>
, for example), and inspect file timestamp information.
on/true/yes
means true, and all other values are false.
PATH
and CLASSPATH
excludes
override includes
<defaultexcludes>
task controls the list of default excludes
<property>
tasks
<property>
task
ANT_OPTS
environment variable
ant -Dx=y
, or ant -propertfile blah.properties
. This style can never be overidden by other settings.
user.name
, user.home
, etc.)
ant.project.name
ant.file
ant.home
ant.java.version
ant.version
basedir
${xyz}
syntax when used with <property>
, but NOT when used with -propertyfile
on the Ant command line.
<property name='x' value='y'>
since the location
attribute isn't used, this isn't
recommended for files and directories, since this will not resolve relative references.
If you do specify a location in a properties file, then it should be absolute, not relative. In addition, you'll
need to escape backslashes.
# example properties file app.version = 1.0 # This style also works, and it's not sensitive to order # of appearance in this file # Thus, the contents of this file is manipulated somewhat # after being loaded. # This does NOT work when using 'ant -propertyfile' app.name = My Wonderful App ${app.version} # you need to escape backslashes build.dir = C:\\\\@build
ant -Dx=y
, or ant -propertfile blah.properties
.
ant -propertyfile blah.properties
doesn't resolve ${xyz}
style references within properties files.
ant -projecthelp
lists all targets having a description. It also tests the general syntax of your build file.
@
placeholder, ensure overwrite='yes'
.
fork='true'
can often fix problems.
like-this
location
attribute, not value
antcall
; to specify order, use the order of dependencies instead
<property file='build.properties'>
in your build file, to let users easily override values.
The build file must work without the build.properties file being present.
<defaultexcludes>
task; you
should usually only extend the default file types.
<property environment='env'/>
to force ant properties and system properties into different namespaces.
$CVSIGNORE
environment variable, or place a .cvsignore
file in their home directory.
duplicate='preserve'
is usually desirable.