Example (which also shows the use of Ant's echo task)
<?xml version="1.0" encoding="utf-8"?> <project name="myproject" default="test" basedir="."> <target name="compile" description="This task compiles the project's source files."> <echo message="Now compiling source code..." /> </target> <target name="dist" description="This task creates the project's jar file." depends="compile"> <echo message="Now creating jar file..." /> </target> <target name="test" description="This task invokes the project's JUnit test cases." depends="dist"> <echo message="Now performing unit tests..." /> </target> <target name="clean" description="This task removes all files generated by this build file."> <echo message="Now removing generated files..." /> </target> </project>
These descriptions are then displayed when the user invokes ant with the -projecthelp flag:
$ ant -projecthelp Buildfile: build.xml Main targets: clean This task removes all files generated by this build file. compile This task compiles the project's source files. dist This task creates the project's jar file. test This task invokes the project's JUnit test cases. Default target: test
Ant comes with a number of built-in properties that can be useful in developing build files
Property Name | Description |
---|---|
basedir | the absolute path of the project's basedir (as set with the basedir attribute of <project>) |
ant.file | the absolute path of the buildfile |
ant.version | the version of Ant executing the build file |
ant.project.name | the name of the project that is currently executing; it is set in the name attribute of <project> |
ant.java.version | the JVM version Ant detected; currently it can hold the values "1.1", "1.2", "1.3", "1.4" and "1.5" |
All Java system properties | See the documentation of System.getProperties for details |
As they are pre-defined, your build file can simply reference them:
<?xml version="1.0" encoding="utf-8"?> <project name="myproject" default="test.ant" basedir="."> <target name="test.ant" description="A simple build file to test ant."> <echo message="basedir : ${basedir}" /> <echo message="ant.file : ${ant.file}" /> <echo message="ant.version : ${ant.version}" /> <echo message="ant.project.name: ${ant.project.name}" /> <echo message="ant.java.version: ${ant.java.version}" /> <echo message="java.version : ${java.version}" /> <echo message="java.vendor : ${java.vendor}" /> <echo message="os.name : ${os.name}" /> <echo message="os.arch : ${os.arch}" /> <echo message="os.version : ${os.version}" /> <echo message="user.name : ${user.name}" /> <echo message="user.home : ${user.home}" /> <echo message="user.dir : ${user.dir}" /> </target> </project>
The latter technique is especially helpful since it can help you from having to hard code paths into a build file. Take for example this excerpt of a build file that I used for my Metis research project:
<?xml version="1.0" encoding="utf-8"?> <project name="metis" default="dist" basedir="."> <!-- initialize user-specific properties --> <!-- Note: metis.properties must define the following properties --> <!-- tomcat.dir : location of tomcat installation --> <!-- http.host : URL used to access tomcat webserver --> <property file="metis.properties" /> <!-- tomcat-related properties --> <property name="webapp.dir" value="${tomcat.dir}/webapps/metis"/> <property name="webinf.dir" value="${webapp.dir}/WEB-INF"/> <property name="weblib.dir" value="${webinf.dir}/lib"/> <property name="repo.dir" value="${webinf.dir}/repo"/> …
The first property definition includes properties from an external file. That file looks like this:
tomcat.dir:/Users/kena/java/tomcat4 smtp.host:localhost http.host:http://localhost:8080/
tomcat.dir
and if you look in the Metis build file, it uses this location to define a property called webapp.dir
that is then used to create other properties. By placing this path in an external properties file, it is no longer hardcoded into the build file and multiple users can each use the build file without modification by simply creating their own metis.properties
file. Another way in which properties can be defined is by the execution of tasks. One task in particular, <tstamp />, makes it easy to create timestamps and insert them into the output products of your build file. When <tstamp> is executed it defines two properties TSTAMP and DSTAMP. TSTAMP includes the current time with the format "hhmm" and DSTAMP includes the current date with the format "yyyyMMdd". The build file below:
<?xml version="1.0" encoding="utf-8"?> <project name="myproject" default="test.ant" basedir="."> <target name="test.ant" description="A simple build file to test ant."> <tstamp /> <echo message="DSTAMP : ${DSTAMP}" /> <echo message="TSTAMP : ${TSTAMP}" /> </target> </project>
produced the following output when I ran it yesterday afternoon:
Buildfile: build2.xml test.ant: [echo] DSTAMP : 20061001 [echo] TSTAMP : 1442 BUILD SUCCESSFUL Total time: 0 seconds
if
or unless
attributeif
the target will execute if the referenced property existsunless
the target will execute if the referenced property does NOT existif
and unless
attributes only enable or disable the target to which they are attached. They do not control whether or not targets that a conditional target depends upon get executed. In fact, they do not even get evaluated until the target is about to be executed, and all its predecessors have already run.Example (taken from Extreme Programming with Ant by Glenn Niemeyer and Jeremy Poteet):
<target name ="backupAdvanced" depends="backupTar" description="Moves backup files to remote server"> <input message="Please enter ftp user id:" addproperty="ftpUserId" /> <condition property="noFTPUserId"> <equals arg1="" arg2="${ftpUserId}" /> </condition> <fail if="noFTPUserId">You did not enter your ftp user id.</fail> <input message="Please enter ftp password:" addproperty="ftpPassword" /> <condition property="noFTPPassword"> <equals arg1="" arg2="${ftpPassword}" /> </condition> <fail if="noFTPPassword">You did not enter your ftp password.</fail> <ftp server="127.0.0.1" remotedir="ftpFiles" userid="${ftpUserId}" password="${ftpPassword}"> <fileset dir="${dirs.backup}" /> </ftp> <delete dir="${dirs.backup}" /> </target>
In the example above, the input task is used to query the user and store his/her response in a property. The condition task is used to make sure that the entered property is non-empty. If the value is empty a new property is defined which is then caught by the fail task which exits the build file gracefully with an appropriate error message. If both required properties are defined then the target completes by invoking the ftp task to transfer the specified files and then deleting the transferred files on the local computer.
<fileset dir="${server.src}" casesensitive="yes"> <include name="**/*.java"/> <exclude name="**/*Test*"/> </fileset>
<dirset dir="${build.dir}"> <include name="apps/**/classes"/> <exclude name="apps/**/*Test*"/> </dirset>
<classpath> <pathelement path="${classpath}"/> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> <pathelement location="classes"/> <dirset dir="${build.dir}"> <include name="apps/**/classes"/> <exclude name="apps/**/*Test*"/> </dirset> </classpath>