Inleiding
Voor Ant bestaan er op de Ant homepage prima tutorials. Op deze pagina vind je een voorbeeld build.xml uitgewerkt voor standaard taken zoals compileren, javadoc, junittesten en checkstyle. Verder is er een voorbeeld opgenomen van de samenwerking tussen Ant en Ivy
Properties
Om zoveel mogelijk harde paden te vermijden starten we met het definieren van een aantal properties:
<property name="dirs.source" value="${basedir}/src" /> <property name="dirs.test" value="${basedir}/test" /> <property name="dirs.build" value="${basedir}/build" /> <property name="dirs.dist" value="${basedir}/dist" /> <property name="dirs.config" value="${basedir}/toolconfigs" /> <property name="dirs.libs" value="${basedir}/libs" /> <property name="dirs.reports" value="${basedir}/reports" /> <property name="dirs.javadoc" value="${basedir}/reports/javadoc" /> <property name="dirs.junit" value="${basedir}/reports/junit" /> <property name="dirs.checkstyle" value="${basedir}/reports/checkstyle" />
Een van de meest opvallende properties is dirs.libs waarmee verwezen wordt naar een pad waar jars opgenomen kunnen worden waarna gerefereerd wordt vanuit de source code. Een alternatief voor het zelf opnemen van deze dependencies is het gebruik van een dependency manager zoals Maven of Ivy. In het lib-path van dit voorbeeld zijn de jars opgenomen van checkstyle en junit.
Compileren
Om te kunnen compileren is het praktisch een classpath op te zetten en eventuele andere plichtplegingen zoals het aanmaken van verschillende directories. Hiervoor gebruiken we twee aparte targets, namelijk init en compile, daarnaast definieren we een path voor het classpath:
<path id="base.classpath"> <pathelement location="${dirs.build}" /> <pathelement path="${java.class.path}" /> <fileset dir="libs"> <include name="**/*.jar" /> </fileset> </path> <target name="init"> <echo>Initializing timestamp, creating dirs</echo> <tstamp /> <mkdir dir="${dirs.build}" /> </target> <target name="compile" depends="init" description="Compile all of the source code"> <echo>Compiling all the code</echo> <javac srcdir="${dirs.source};${dirs.test}" destdir="${dirs.build}" > <classpath refid="base.classpath"/> </javac> </target>
Door het classpath als path te definieren kan in verschillende targets de definitie gebruikt worden via het refid.
Javadoc
Het uitdraaien van javadoc is betrekkelijk eenvoudig. Indien er veel externe dependencies zijn is het praktisch ook het classpath te koppelen aan dit target:
<target name="javadoc"> <mkdir dir="${dirs.javadoc}" /> <echo>Generate javadoc</echo> <javadoc sourcepath="${dirs.source}" destdir="${dirs.javadoc}" packagenames="*.*" /> </target>
Unittesten
Voor het gebruik van JUnit heeft Ant een specifieke taak om de testcases te runnen. Vervolgens zijn er nog andere tasks nodig om tot een opgemaakt report te komen:
<target name="junittests" depends="compile" description="Executing JUnit tests"> <echo>Testing, testing, testing ... </echo> <mkdir dir="${dirs.junit}" /> <junit haltonfailure="no" printsummary="yes" showoutput="yes"> <classpath refid="base.classpath" /> <formatter type="xml" /> <batchtest todir="${dirs.junit}"> <fileset dir="${dirs.build}"> <include name="**/*Test.class" /> </fileset> </batchtest> </junit> <junitreport todir="${dirs.junit}"> <fileset dir="${dirs.junit}"> <include name="TEST-*.xml" /> </fileset> <report format="frames" todir="${dirs.junit}"> </report> </junitreport> </target>
Checkstyle
Het handmatig nalopen of je code voldoet aan de afgesproken codingguidelines is vervelend werk. Gelukkig is er Checkstyle die je handig aan je build-file kunt hangen:
<target name="checkstyle" description="Report of code convention violations"> <mkdir dir="${dirs.checkstyle}" /> <checkstyle config="${dirs.config}/ddoa_checks.xml"> <fileset dir="${dirs.source}"> <exclude name="**/*Test.java" /> <include name="**/*.java" /> </fileset> <formatter type="xml" tofile="${dirs.checkstyle}/checkstyle_report.xml" /> </checkstyle> <xslt in="${dirs.checkstyle}/checkstyle_report.xml" out="${dirs.checkstyle}/index.checkstyle.html" style="${dirs.config}/checkstyle-noframes-sorted.xsl" /> </target>
Ivy
Vooral als je Maven lastig vindt of als je Ant wilt blijven gebruiken zonder je eigen lib-map te moeten administreren, is Ivy een handig hulpmiddel. Vooral in projecten waarbij Groovy of Grails gebruikt wordt steekt Ivy de kop op als dependency manager. Om Ivy te gebruiken zijn er verschillende files:
- build.xml
- ivy.xml
- ivysettings.xml
Ivy - build.xml
Om Ivy in je Ant build file te gebruiken kun je Ivy installeren, maar ook Ant de laatste versie van Ivy laten downloaden (je hebt toch een internetverbinding nodig voor het downloaden van de dependencies):
<target name="download-ivy" unless="offline"> <available file="${ivy.jar.file}" property="ivy.available"/> <antcall target="-download-ivy"/> </target> <target name="-download-ivy" unless="ivy.available"> <mkdir dir="${ivy.jar.dir}"/> <!-- download Ivy from web site so that it can be used even without any special installation --> <get src="http://www.apache.org/dist/ant/ivy/${ivy.install.version}/apache-ivy-${ivy.install.version}-bin.zip" dest="${ivy.home}/ivy.zip" usetimestamp="true" verbose="true"/> <unzip src="${ivy.home}/ivy.zip" dest="${ivy.jar.dir}"> <patternset> <include name="**/*.jar"/> </patternset> <mapper type="flatten"/> </unzip> </target> <target name="init-ivy" depends="download-ivy" unless="ivy.lib.path"> <path id="ivy.lib.path"> <fileset dir="${ivy.jar.dir}" includes="*.jar"/> </path> <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/> </target> <property name="lib.dir" value="${basedir}/lib"/> <target name="-resolve" description="--> Retrieve dependencies with ivy" depends="init-ivy"> <ivy:retrieve pattern="${lib.dir}/[conf]/[artifact]-[revision].[ext]"/> </target>
Maak je eigen targets afhanjelijk van de -resolve target en definieer je exacte dependencies in ivy.xml.
Ivy - ivy.xml
Deze file bevat de lijst met dependencies:
<ivy-module version="2.0"> <info organisation="org.example" module="MrMatching"/> <configurations defaultconfmapping="build->default;compile->compile(*),master(*);test,runtime->runtime(*),master(*)"> <conf name="build"/> <conf name="compile"/> <conf name="test" extends="compile"/> <conf name="runtime" extends="compile"/> </configurations> <dependencies> <dependency org="org.grails" name="grails-bootstrap" rev="1.1.2" conf="build"/> <dependency org="org.grails" name="grails-scripts" rev="1.1.2" conf="build"/> <dependency org="org.grails" name="grails-gorm" rev="1.1.2" conf="compile"/> <dependency org="org.grails" name="grails-web" rev="1.1.2" conf="compile"/> <dependency org="org.grails" name="grails-test" rev="1.1.2" conf="test"/> <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.5.5" conf="runtime"/> <dependency org="opensymphony" name="oscache" rev="2.4" conf="runtime"> <exclude org="javax.jms" module="jms" name="*" type="*" ext="*" conf="" matcher="exact"/> <exclude org="commons-logging" module="commons-logging" name="*" type="*" ext="*" conf="" matcher="exact"/> <exclude org="javax.servlet" module="servlet-api" name="*" type="*" ext="*" conf="" matcher="exact"/> </dependency> <dependency org="org.tmatesoft.svnkit" name="svnkit" rev="1.2.3.5521" conf="build"/> <dependency org="hsqldb" name="hsqldb" rev="1.8.0.5" conf="runtime"/> <dependency org="net.sf.ehcache" name="ehcache" rev="1.5.0" conf="runtime"/> </dependencies> </ivy-module>
Ivy - ivysettings.xml
Ivy moet nog wel even weten waar alle dependencies vandaan moeten komen, hiervoor is de ivysettings.xml:
<ivysettings>
<settings defaultResolver="codehaus-plus"/>
<include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-main-chain.xml"/>
<resolvers>
<chain name="codehaus-plus" dual="true">
<ibiblio name="codehaus-snapshots" root="http://snapshots.repository.codehaus.org" m2compatible="true"
changingPattern=".*SNAPSHOT"/>
<ibiblio name="codehaus" root="http://repository.codehaus.org" m2compatible="true"/>
<ibiblio name="javanet" root="http://download.java.net/maven/2/" m2compatible="true"/>
<resolver ref="public"/>
</chain>
</resolvers>
</ivysettings>