31 октября 2012 г.

Основные операции в ant-скрипте

В предыдущей заметке мы рассмотрели основные принципы написания ant-скриптов. А сейчас рассмотрим реальный скрипт, в котором используется большинство основных операций.

Итак, ant-скрипт представляет собой xml-файл, обычно называемый build.xml. Этот файл обычно лежит в корневой директории java-проекта. Но все эти параметры можно переопределить в командной строке при запуске ant.
<project name="ant.tutorial" default="compile">
<property file="build.properties" />
Даём проекту имя и указываем, что по умолчанию для него следует вызывать цель compile, которая будет определена ниже. Далее подгружаем параметры из файла свойств build.properties. Вот его примерное содержимое:
lib.dir=lib
project.dir=.
project.src.dir=${project.dir}/src
build.dir=build
build.jar.name=simple-proj.jar
build.jar.mainclass=org.test.SimpleMain
dist.name=simple-proj
dist.dir=distribution
dist.lib.dir=lib
host=10.1.2.31
username=root
password=123456
archive.name=${dist.name}-distr.zip
Все эти параметры будут использоваться в нашем ant-скрипте. Обратите внимание, что в качестве значения параметра может использоваться другой параметр. Обращение к значению параметра как в файле свойств, так и в ant-скрипте производится при помощи конструкции вида ${имя_параметра}.
<target name="clean">
<delete dir="${build.dir}" />
<delete dir="${dist.dir}" />
</target>
Определяем цель по имени clean для очистки директорий, в которые мы будем складывать бинарные файлы.
<target name="make.build.dirs" depends="clean">
<mkdir dir="${build.dir}" />
<mkdir dir="${build.dir}/class" />
</target>
Определяем цель, в которой создаётся директории для бинарников (если они ещё не были созданы). Здесь имеется зависимость от предыдущей цели clean. Если необходимо создать несколько директорий, вложенных одна в другую, это можно сделать одной командой.
<target name="compile" description="compile java" depends="make.build.dirs">
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"
excludes="**/*javadoc*.jar,**/*sources*.jar" />
</path>
Определяем цель для компиляции проекта из исходников. Затем задаём объект classpath. В этом объекте содержится набор путей до каждой из библиотек, которые нужны для сборки проекта. Обратите внимание на параметры includes (включаем в classpath пути до всех jar-файлов) и excludes (исключаем из classpath jar-файлы, которые содержат в своём имени строки "javadoc" и "sources").
<pathconvert property="compile.classpath" refid="classpath" />
<echo>CLASSPATH: ${compile.classpath}</echo>
Создаём тектовое представление объекта classpath в виде свойства и выводим значение этого свойства в консоль при помощи уже знакомой нам команды echo.
<javac destdir="${build.dir}/class" includeantruntime="false"
source="1.6" target="1.6">
<src path="${project.src.dir}" />
<classpath refid="classpath" />
</javac>
</target>
Вызываем компилятор бинарный файлов javac и задаём для него необходимые параметры. Source и target определяют, какая версия jdk использовалась при написании кода и для какой jre следует компилировать бинарные файлы соответственно (хотя это и не обязательно указывать). Также указываем путь до исходников и пути до библиотек. На этой цель compile завершается.
<target name="make.dist.dirs" description="Make dirs for distribution">
<mkdir dir="${dist.dir}/${dist.name}" />
<mkdir dir="${dist.dir}/${dist.name}/${dist.lib.dir}" />
</target>
Определяем цель для создания директорий, в которых будет располагаться дистрибутив.
<target name="dist.lib.copy" depends="make.dist.dirs">
<copy todir="${dist.dir}/${dist.name}/${dist.lib.dir}" flatten="true">
<path refid="classpath" />
</copy>
</target>
Копируем необходимые библиотеки в папку дистрибутива. Пути берутся из classpath.
<target name="make.jar" description="Make jar file" depends="compile,dist.lib.copy">
<pathconvert property="dist.classpath" pathsep=" " refid="classpath">
<mapper>
<chainedmapper>
<flattenmapper />
<globmapper from="*" to="${dist.lib.dir}/*" />
</chainedmapper>
</mapper>
</pathconvert>
Создаём цель, которая формирует конечный jar-архив для нашего проекта. Здесь указывается зависимость от двух других целей. Конвертируем classpath в формат Class-Path, который используется в файле MANIFEST.MF внутри jar-архива. Также конвертируем пути до библиотек в пути относительно каталогов дистрибутива. Необходимость этих манипуляций Вам должна быть понятна, т.к. ранее мы уже рассматривали сборку проекта вручную.
<echo>Class-Path: ${dist.classpath}</echo>
<jar destfile="${dist.dir}/${dist.name}/${build.jar.name}">
<manifest>
<attribute name="Main-Class" value="${build.jar.mainclass}" />
<attribute name="Class-Path" value="${dist.classpath}" />
</manifest>
<fileset dir="${build.dir}/class">
<include name="**/*.class" />
</fileset>
<fileset dir="${project.src.dir}">
<include name="log4j.xml" />
</fileset>
</jar>
</target>
Выводим на экран полученный Class-Path для файла MANIFEST.MF. Затем формируем jar-файл, в который включаем созданный тут же MANIFEST.MF и бинарные class-файлы. Также добавляем дополнительные конфигурационные файлы (если необходимо). На этом цель завершается. Написав такую цель один раз, это избавляет вас от рутинных операций по сборке jar-файлов, которые вам приходилось бы делать всякий раз при ручной сборке.
<target name="javadoc">
<javadoc sourcepath="${project.src.dir}" defaultexcludes="yes"
destdir="${dist.dir}/${dist.name}/api" author="true" version="true"
use="true" windowtitle="Simple Project API" charset="UTF-8">
<doctitle><![CDATA[<h1>Simple Project API</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright &#169; 2012. All Rights Reserved.</i>]]></bottom>
</javadoc>
</target>
Дополнительная цель - создание javadoc файлов на основе специально оформленных комментариев в исходном коде. Одна цель - а на выходе вы получаете целую документацию по вашему проекту в виде html-файлов!
<target name="dist" description="Creating a distribution"
depends="make.jar, dist.lib.copy, javadoc">
<delete file="${dist.dir}/${archive.name}" />
<zip destfile="${dist.dir}/${archive.name}" basedir="${dist.dir}" />
</target>
Упаковываем дистрибутив в zip-архив. Это очень удобно при копировании на удалённый сервер. В архив войдут jar-файл, все необходимые библиотека, а также документация.
<target name="remote.copy" description="Copy to a remote server"
depends="dist">
<scp file="${dist.dir}/${archive.name}" todir="${username}@${host}:/root"
password="${password}" />
<sshexec host="${host}" username="${username}" password="${password}"
command="unzip -o ${archive.name}; rm -rf ${archive.name}" />
</target>
</project>
Ну и наконец пример цели, в которой происходит копирование по ssh на удалённый сервер - эту рутинную операцию вы тоже можете автоматизировать! Затем на удалённом сервере выполняется команда по распаковке архива дистрибутива. Для корректной работы этой цели вам потребуется библиотека для работы с ssh под названием jsch. Скачать можно здесь. Скопируйте её в папку ".ant/lib" в вашей домашней директории.

На этом наш ant-скрипт заканчивается. Он построен таким образом, что при вызове цели remote.copy будут выполнены все остальные цели в этом проекте. Минимально необходимая цель для получения дистрибутива - make.jar. Если вам нужен полный дистрибутив без копирования на удалённый сервер - вызывайте цель dist.

Возможно, ant-скрипт выглядит несколько многословным, но он действительно позволяет автоматизировать очень многие рутинные операции при сборке проекта. Поэтому желательно для любого проекта писать подобные скрипты, чтобы не зависеть от средств сборок, встроенных в IDE.

Комментариев нет:

Отправить комментарий