Сборка Java приложений при помощи Apache Ant, quick start

    О чем эта статья


    Одной из отличительных особенностей платформы Java является ее независимость от используемого инструментария. Вы можете разрабатывать сколь угодно большое Java приложение при помощи блокнота (vi) и командной строки. Понятно что так никто не делает и все используют какую-то IDE. Как следствие независимости от инструментов — IDE для Java много. Все это хорошо но есть одна особенность. Если Ваш коллега делал приложение и для сборки проекта использовал IDE_A то в IDE_B которая стоит у Вас — собрать приложение не получится.
    В общем-то это давно уже не проблема. Хорошей практикой считается использовать систему сборки не зависящую от IDE. Для Java их две это Apache-Ant и Maven (тоже в общем-то Apache). Но тут есть один подводный камень. Если в Delphi или Visual Studio, чтобы создать и собрать приложение надо кликнуть в кнопку new пройтись по шагам визарда и нажать кнопку собрать, то написание ant скрипта для сборки например web приложения, особенно для начинающего разработчика, задача не тривиальная.
    В статье рассматривается сборка и деплой Java web приложения шаг за шагом.

    В целом задачу можно решить как с помощью ant так и с помощью maven, здесь будет рассмотрен ant. Для начинающих он проще и нагляднее.



    Зачем нужен скрипт сборки


    • Независимость проектных задач от окружения.
    • 100% повторяемость любого результата (работает у меня – работает у всех)
    • Исключение человеческого фактора из важных операций
    • Превращение деплоя из сложной операции в рутинную задачу.


    Собираем и деплоим war



    Есть много способов собрать war и есть много способов расположить файлы приложения. В статье дается один способ — может быть не самый лучший но вполне неплохой.

    Структура проекта

    Файлы проекта располагаем вот так.
    +---ant
    |   |   step1.ant.xml
    |   |   step2.ant.xml
    |   |   step3.ant.xml
    |   |   step4.ant.xml
    |   |   step5.ant.xml
    |   |   step6.ant.xml
    |   |
    |   \---env
    |           default.properties
    |           semenych.properties
    |
    +---lib
    |   \---google-gson-1.4
    |           gson-1.4-javadoc.jar
    |           gson-1.4-sources.jar
    |           gson-1.4.jar
    |
    +---src
    |   \---java
    |       \---com
    |           \---dataart
    |               \---ant
    |                   \---demo
    |                           Test.java
    |
    \---web
        \---WEB-INF
            |   web.xml
            |
            \---lib
    

    В реальном проекте вместо stepN.xml будет build.xml. Библиотек будет больше и каждую следует располагать в отдельном каталоге. Имена пакетов выдают что я работаю в компании DataArt.

    Шаг 1: компиляция

    Для начала просто скомпилируем весь код, подключив бибилиотеку GSON. Компилированный код идет в каталог .build. Имя может быть любым, но обычно удобно если имя каталога начинается с точки.
    <project name="step1" default="compile">
    <target name="compile"> <mkdir dir="../.build/classes"/> <javac srcdir="../src/java" destdir="../.build/classes"> <classpath location="../lib/google-gson-1.4/gson-1.4.jar"/> </javac> </target> </project>


    Шаг 2: улучшаем скрипт

    Скрипт шага 1 довольно не гибкий и ряд путей там прописан дав раза. Давайте его улучшим

    <project name="step2" default="compile">
    
        <property name="dir.build" value="../.build"/>
    
        <property name="dir.classes" value="${dir.build}/classes"/>
    
        <property name="dir.src.java" value="../src/java"/>
    
        <target name="clean">
            <delete dir="${dir.build}"/>
        </target>
    
        <target name="mkdirs">
            <mkdir dir="${dir.classes}"/>
        </target>
    
        <target name="compile" depends="mkdirs">
            <javac srcdir="${dir.src.java}" destdir="${dir.classes}">
                <classpath location="../lib/google-gson-1.4/gson-1.4.jar"/>
            </javac>
        </target>
    
    </project>


    Шаг 3: Пути к библиотекам

    Пути к библиотекам прописаны жестко в середине кода. Это не есть хорошо, меняем.

    <project name="step3" default="compile">
    
        <property name="dir.build" value="../.build"/>
    
        <property name="dir.classes" value="${dir.build}/classes"/>
    
        <property name="dir.src.java" value="../src/java"/>
    
        <property name="dir.lib" value="../lib"/>
    
        <path id="libs.gson">
            <fileset dir="${dir.lib}/google-gson-1.4">
                <include name="*.jar"/>
            </fileset>
        </path>
    
        <path id="libs.main.module">
            <path refid="libs.gson"/>
        </path>
    
        <target name="clean">
            <delete dir="${dir.build}"/>
        </target>
    
        <target name="mkdirs">
            <mkdir dir="${dir.classes}"/>
        </target>
    
        <target name="compile" depends="mkdirs">
            <javac srcdir="${dir.src.java}" destdir="${dir.classes}">
                <classpath>
                    <path refid="libs.main.module"/>
                </classpath>
            </javac>
        </target>
    
    </project>
    


    Шаг 4: Управление кофигурациями

    Управление конфигурациями это мега технология о которой меня рассказал матерый американский программер Walden Mathews. Суть в следующем, при сборке вы пишете в файл свойств таймаут или путь до какого-то внешнего каталога или URL какого-то сервиса. На вашей локальной машине он один, на боевом сервере (или на машине коллеги другой). Вопрос — как использовать правильные значения свойств и не поубивать друг друга.
    <project name="step4" default="compile">
    
        <property name="dir.build" value="../.build"/>
    
        <property name="dir.classes" value="${dir.build}/classes"/>
    
        <property name="dir.src.java" value="../src/java"/>
    
        <property name="dir.lib" value="../lib"/>
    
        <property name="dir.env" value="./env"/>
    
        <property name="assembled.properties" value="${dir.build}/assembled.properties"/>
    
        <path id="libs.gson">
            <fileset dir="${dir.lib}/google-gson-1.4">
                <include name="*.jar"/>
            </fileset>
        </path>
    
        <path id="libs.main.module">
            <path refid="libs.gson"/>
        </path>
    
        <target name="clean">
            <delete dir="${dir.build}"/>
        </target>
    
        <target name="mkdirs">
            <mkdir dir="${dir.build}"/>
            <mkdir dir="${dir.classes}"/>
        </target>
    
        <target name="init" depends="mkdirs">
            <property name="env" value="${user.name}"/>
            <echo level="info" message="env=${env}"/>
            <available file="${dir.env}/${env}.properties" property="env.props.available"/>
            <fail unless="env.props.available"
                  message="No such file: ${dir.env}/${env}.properties"/>
            <property file="${dir.env}/${env}.properties"/>
            <property file="${dir.env}/default.properties"/>
            <echoproperties destfile="${assembled.properties}"/>
            <filter filtersfile="${assembled.properties}"/>
        </target>
    
        <target name="compile" depends="init">
            <javac srcdir="${dir.src.java}" destdir="${dir.classes}">
                <classpath>
                    <path refid="libs.main.module"/>
                </classpath>
            </javac>
        </target>
    
    </project>
    


    Здесь в target init читается файл с именем, совпадающим с Вашим именем пользователя. Если такой не находится сборка дальше не идет. А уже потом читаются дефолтные свойства из default. Так как в ant значения свойств переопределять нельзя то в default должны быть все свойства, а в Вашем файле только те значения которых отличаются.

    default.properties

    welcome.file=default.html
    
    tomcat.service.name=tomcat6
    tomcat.home=C:/bin/tomcat6
    


    semenych.properties

    welcome.file=index.html
    
    


    Если Вы хотите собрать проект с файлом свойств имя которого отличается от имени пользователя — пишете так
    ant -Denv=mihalych compile

    Обратите внимание что в команде написано просто mihalych а не mihalych.properties

    Шаг 5: Давайте уже соберем jar и war файл

    Да действительно давайте.
    <project name="step5" default="compile">
    
        <property name="dir.build" value="../.build"/>
    
        <property name="dir.classes" value="${dir.build}/classes"/>
    
        <property name="dir.src.java" value="../src/java"/>
    
        <property name="dir.lib" value="../lib"/>
    
        <property name="dir.env" value="./env"/>
    
        <property name="dir.war.content" value="${dir.build}/war.content"/>
    
        <property name="assembled.properties" value="${dir.build}/assembled.properties"/>
    
        <property name="file.jar" value="${dir.build}/main.module.jar"/>
    
        <property name="name.application" value="demo"/>
    
        <property name="file.war" value="${dir.build}/${name.application}.war"/>
    
        <path id="libs.gson">
            <fileset dir="${dir.lib}/google-gson-1.4">
                <include name="*.jar"/>
            </fileset>
        </path>
    
        <path id="libs.main.module">
            <path refid="libs.gson"/>
        </path>
    
        <target name="clean">
            <delete dir="${dir.build}"/>
        </target>
    
        <target name="mkdirs">
            <mkdir dir="${dir.build}"/>
            <mkdir dir="${dir.classes}"/>
            <mkdir dir="${dir.war.content}"/>
        </target>
    
        <target name="init" depends="mkdirs">
            <property name="env" value="${user.name}"/>
            <echo level="info" message="env=${env}"/>
            <available file="${dir.env}/${env}.properties" property="env.props.available"/>
            <fail unless="env.props.available"
                  message="No such file: ${dir.env}/${env}.properties"/>
            <property file="${dir.env}/${env}.properties"/>
            <property file="${dir.env}/default.properties"/>
            <echoproperties destfile="${assembled.properties}"/>
            <filter filtersfile="${assembled.properties}"/>
        </target>
    
        <target name="compile" depends="init">
            <javac srcdir="${dir.src.java}" destdir="${dir.classes}">
                <classpath>
                    <path refid="libs.main.module"/>
                </classpath>
            </javac>
        </target>
    
        <target name="build.jar" depends="compile">
            <jar destfile="${file.jar}"
                 basedir="${dir.classes}"
                 compress="false"
                 index="true">
            </jar>
        </target>
    
        <target name="build.war.content"
                depends="build.jar">
            <copy todir="${dir.war.content}" preservelastmodified="true" overwrite="true">
                <fileset dir="../web"/>
            </copy>
            <copy todir="${dir.war.content}/WEB-INF/lib" preservelastmodified="true">
                <path refid="libs.main.module"/>
            </copy>
    
            <copy todir="${dir.war.content}/WEB-INF/lib"
                  preservelastmodified="true"
                  file="${file.jar}">
            </copy>
    
            <replace dir="${dir.war.content}/WEB-INF/"
                     propertyfile="${assembled.properties}">
                <include name="*.xml"/>
    
                <replacefilter token="@welcome.file@" property="welcome.file"/>
    
            </replace>
    
        </target>
    
        <target name="build.war" depends="build.war.content">
            <delete file="${file.war}"/>
            <war
                    compress="true"
                    encoding="utf-8"
                    warfile="${file.war}"
                    webxml="${dir.war.content}/WEB-INF/web.xml">
                <fileset dir="${dir.war.content}" excludes="WEB-INF/web.xml"/>
            </war>
        </target>
    
    
    </project>
    


    Один комментарий:

    
            <replace dir="${dir.war.content}/WEB-INF/"
                     propertyfile="${assembled.properties}">
                <include name="*.xml"/>
    
                <replacefilter token="@welcome.file@" property="welcome.file"/>
    
            </replace>
    


    вот эта секция делает замену внутри web.xml при этом web.xml выглядит так:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5"
             xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
        <welcome-file-list>
            <welcome-file>@welcome.file@</welcome-file>
        </welcome-file-list>
    
    </web-app>
    
    


    Шаг 6: war готов, последний штрих, деплой

    Скрипт будет делать так называемый «холодный» деплой т.е. развертывание приложения с остановкой сервера. В ряде случаев «холодный» деплой позволяет избежать ряда проблем связанных с освобождением ресурсов и чисткой кэша.

    <project name="step6" default="compile">
    
        <property name="dir.build" value="../.build"/>
    
        <property name="dir.classes" value="${dir.build}/classes"/>
    
        <property name="dir.src.java" value="../src/java"/>
    
        <property name="dir.lib" value="../lib"/>
    
        <property name="dir.env" value="./env"/>
    
        <property name="dir.war.content" value="${dir.build}/war.content"/>
    
        <property name="assembled.properties" value="${dir.build}/assembled.properties"/>
    
        <property name="file.jar" value="${dir.build}/main.module.jar"/>
    
        <property name="name.application" value="demo"/>
    
        <property name="file.war" value="${dir.build}/${name.application}.war"/>
    
        <path id="libs.gson">
            <fileset dir="${dir.lib}/google-gson-1.4">
                <include name="*.jar"/>
            </fileset>
        </path>
    
        <path id="libs.main.module">
            <path refid="libs.gson"/>
        </path>
    
        <target name="clean">
            <delete dir="${dir.build}"/>
        </target>
    
        <target name="mkdirs">
            <mkdir dir="${dir.build}"/>
            <mkdir dir="${dir.classes}"/>
            <mkdir dir="${dir.war.content}"/>
        </target>
    
        <target name="init" depends="mkdirs">
            <property name="env" value="${user.name}"/>
            <echo level="info" message="env=${env}"/>
            <available file="${dir.env}/${env}.properties" property="env.props.available"/>
            <fail unless="env.props.available"
                  message="No such file: ${dir.env}/${env}.properties"/>
            <property file="${dir.env}/${env}.properties"/>
            <property file="${dir.env}/default.properties"/>
            <echoproperties destfile="${assembled.properties}"/>
            <filter filtersfile="${assembled.properties}"/>
        </target>
    
        <target name="compile" depends="init">
            <javac srcdir="${dir.src.java}" destdir="${dir.classes}">
                <classpath>
                    <path refid="libs.main.module"/>
                </classpath>
            </javac>
        </target>
    
        <target name="build.jar" depends="compile">
            <jar destfile="${file.jar}"
                 basedir="${dir.classes}"
                 compress="false"
                 index="true">
            </jar>
        </target>
    
        <target name="build.war.content"
                depends="build.jar">
            <copy todir="${dir.war.content}" preservelastmodified="true" overwrite="true">
                <fileset dir="../web"/>
            </copy>
            <copy todir="${dir.war.content}/WEB-INF/lib" preservelastmodified="true">
                <path refid="libs.main.module"/>
            </copy>
    
            <copy todir="${dir.war.content}/WEB-INF/lib"
                  preservelastmodified="true"
                  file="${file.jar}">
            </copy>
    
            <replace dir="${dir.war.content}/WEB-INF/"
                     propertyfile="${assembled.properties}">
                <include name="*.xml"/>
    
                <replacefilter token="@welcome.file@" property="welcome.file"/>
    
            </replace>
    
        </target>
    
        <target name="build.war" depends="build.war.content">
            <delete file="${file.war}"/>
            <war
                    compress="true"
                    encoding="utf-8"
                    warfile="${file.war}"
                    webxml="${dir.war.content}/WEB-INF/web.xml">
                <fileset dir="${dir.war.content}" excludes="WEB-INF/web.xml"/>
            </war>
        </target>
    
        <target name="deploy"
                depends="build.war,do.undeploy.war,do.deploy.war">
        </target>
    
        <target name="do.undeploy.war" depends="init">
            <service.stop.win32 service.name="${tomcat.service.name}"/>
            <delete file="${tomcat.home}/webapps/${name.application}.war" failonerror="false"/>
            <delete dir="${tomcat.home}/webapps/${name.application}" failonerror="false"/>
        </target>
    
        <target name="do.deploy.war" depends="init">
            <copy todir="${tomcat.home}/webapps" failonerror="yes">
                <fileset file="${file.war}"/>
            </copy>
            <service.start.win32 service.name="${tomcat.service.name}"/>
        </target>
    
        <!-- macro -->
    
        <macrodef name="service.stop.win32">
            <attribute name="service.name"/>
            <sequential>
                <echo>Stoping service: @{service.name}</echo>
                <exec executable="net" outputproperty="whatsRunning">
                    <arg value="stop"/>
                    <arg value="@{service.name}"/>
                </exec>
            </sequential>
        </macrodef>
    
        <macrodef name="service.start.win32">
            <attribute name="service.name"/>
            <sequential>
                <echo>Starting service: @{service.name}</echo>
                <exec executable="net" failonerror="yes">
                    <arg value="start"/>
                    <arg value="@{service.name}"/>
                </exec>
            </sequential>
        </macrodef>
    
    </project>
    


    Заключение


    Вот собственно и все. Это почти готовый пример взятый из реального проекта. Пользуйтесь на здоровье, не забывайте писать комментарии.

    Ссылки


    Поделиться публикацией

    Похожие публикации

    Комментарии 35

      +7
      Уделив изучению Maven тоже время что и на ant, собирать проекты вы будете намного быстрее. Ant по моему уже устарел.
        +1
        Ant не устарел. Этот же Maven использует ant внутри себя. Просто ant для всеобщих задач. А вот для сборок проектов на Java и существует Maven. Лучше Maven в этом плане ничего нет и не будет. Но и Ant хоронить не надо.
          –7
          Лучше Маven ничего не будет? o_0

          Что одно (ant) что другое (maven) говно. Хороши для приложений уровня hello-world для более сложных проектов абсолютно не подходят. Java билд системы еще ждут своего будущего.

          PS Рекомендую взглянуть на Rake, Buildr, sbt.
            +1
            gradle?
              +2
              Для минусующей школоты — я автор 2 плагинов у первому мавену и одного ко второму. Так что я знаю о чем говорю.

              PS В конце года Гугл должен выпустить свою билд систему ориентированную на большие проекты, это должно быть намного интереснее.
                +1
                А можно по подробнее что не устраивает в Maven 2 для больших проектов?
                  +1
                  Стало еще больше интересно что Вас конкретно не устраивает?
            0
            Спорный вопрос. Особенно насчет времени. У мавена есть один довольно существенный недостаток. Библиотеки он берет из интеренета. Это кончено хорошо. Но:
            1. Нужной библиотеки в доступных репозиториях может банально не быть.
            2. Если Вам надо попатчить Jboss.seam.1.2.jar то патченную библиотеку надо где-то хранить (для всех 6 членов команды сидящих в 3 разных городах)
            3. Если через 3 года вы сделаете checkout проекта из SVN у Вас нет 100% гарантии что все нужные библиотеки будут доступны, а если они будут доступны, что war который будет собран бует точно такой же функционал как тот который Вы собирали 3 года назад.

            Все это конечно решаемо, но если Вам нужен 100% контроль над тем что получается в результате, сил приходится прикладывать заметно больше чем с ant.
              +3
              1. Кроме базового репозитория есть альтернативные. За последние год-два не нашел только одну библиотеку по работе с json. Выбрал другую.
              2. Интересно увидеть выход который предлагаете вы. Решение есть, поднять свой репозитарий и в нем хранить все что вам понадобиться.
              3. Эта проблема организации разработки, мавен поддерживает версионность. Интересно как вас спасет ант в этом случае.

              Я 100% контролирую результат который я получаю с Maven.
                0
                Я не сомневаюсь что у Вас все хорошо. Вопрос в том, сколько времени ушло на обучение, сколько тратится на поддержание состояния — «хорошо».

                По поводу #2 — решение простое берется seam, правится и кладется в svn как и остальный библиотеки. Про свой репозиторий я в курсе, проблема в том, что никто не гарантирует наличия в нем правленного jar-а через пол года.

                Еще раз мавен хорошо. Но правильно использовать его джуниору сложно. Фактически не реально. Ant вполне реально — проверено на живых джуниорах-добровольцах.
                  0
                  Не поверите, ушло около часа на чтение документации и первая сборка была готова. С начала немного непонятно как пользоваться плагинами, но со временем все становится на свои места.

                  Хммм странно, как это никто не гарантирует? Как тогда гарантировать его наличие в svn'е?

                  Возможно, Вы правы. После того как я пересел на maven вся сборка проходит в разы быстрее, можно даже сказать что за меня все делает maven.
                    0
                    ну если коротко maven vs ant:

                    Мавен более декларативный и что важно вл многом сам отслеживает зависимости артефактов. В этом его сила и слабость одновременно.

                    Ант, проще, нагляднее, более процедурный (для студента как правило идея не процедурной системы сборки вообще тяжела) и более стабильный.

                    Дело в том, что svn это понятно всем, все понимают как его бэкапить что с ним делать. Может взять код за архивировать, послать заказчику архив и сказать установи ant и скажи ant build.

                    С мавеном, особенно если у вас свой репозиторий такой трюк не проходит.

                    BTW мавен особенно любим индусами которые обожают строить инфраструктуру из 33 серверов и репозиториев.

                    Можно наверное сказать что мавен хорош для больших и длинных проектов в которых есть мега крутые девелоперы способные все настроить по уму.

                    Ant более всеяден.
                      0
                      Конкренто в моем случае Мавен очень удобен тем, что с ним не надо вкладывать кучу библиотек. У нас есть около 15 довольно схожих по структуре проектов, и почти все используют примерно одинаковый набор библиотек. Так вот передать разработчику в другой город все эти проекты стоит немалого времени (в провинциях интернеты не так быстры, как хоетлось бы), а с Мавеном все проекты из почти гига превращаются буквально в 10-15 Мб.

                      Плюс еще очень легко работать из разных IDE как с нативным для этой IDE проектом — для всех популярных сред есть плагины генерации файлов проектов.
                        +2
                        Небольшое уточнение: maven может использовать локальные репозитории в виде относительного пути к папке(т.е. работает урл не только http:// но и file://). Так что проблем с передачей архива не будет.

                        На нашем проекте так хранятся пропатченные библиотеки.
                +3
                Если в Delphi или Visual Studio, чтобы создать и собрать приложение надо кликнуть в кнопку new пройтись по шагам визарда и нажать кнопку собрать, то написание ant скрипта для сборки например web приложения, особенно для начинающего разработчика, задача не тривиальная.

                В Eclipse можно сгенерить ant для существующего проекта и дальше работать с ним. Делается это так:
                1. Right click по нужному проекту
                2. Из контекстного меню выбираем Export…
                3. В окне экспорта выбираем Ant Builders
                4. Жмем Next и далее следуем подсказкам визарда…
                  0
                  Спасибо я знаю. А Вы пробовали с этим потом работать? Т.е. сказать джуниору — вот скрипт сгенеренный Eclipse — там поменяй в нем пару мест.
                    0
                    Сам я пользуюсь этим в основном для своих личных проектов. А обяснять новичкам приходилось очень редко. Несмотря на то что у нас аплликация большая, новые проекты добавляются редко и при этом просто используются уже существующие скрипты. Среди программеров у нас только 1 — 2 % более-менее плотно знакомы с ant. Остальным это просто не нужно для работы.
                      0
                      В общем-то нормальная ситуация. Просто я последние пол-года столкнулся с необходимостью засетапить где-то десяток новых проектов в которых работают в основном джуниоры. Проекты простые, но увы, это не отменяет необходимости их собирать.
                      Тут то я и понял почему ряд студентов так сильно не любит Яву.
                        +1
                        Ряд студентов не любит все то, чего они не могут или не хотят понять. Пусть они радуются, что вы не заставляете их писать на Common Lisp-e.
                  +7
                  Для Java следует использовать Maven. Ant только в тех случаях, когда Maven уже не может сделать что-то. Тем более, что в Maven есть поддержка плагина, который использует Ant таски. Ant более универсален, но для сборок проектов на Java Maven так заточен, что его сложно переплюнуть.
                    +1
                    для cross-IDE разработки maven удобнее как минимум тем, что позволяет не только собирать, но и создавать IDE-specific project-файлы. Впрочем, в разных IDE качество maven'а сильно различается, в том же eclipse, увы, он весьма хуже IDEA
                      0
                      Это свойство maven по пользе стоит сразу после менеджера зависимостей. А с тех пор как IDEA научилась сама импортировать maven проекты, я всегда начинаю новый проект с настройки под maven.

                      Для новых разработчиков в команде время настройки проекта сократилось до нескольких минут.
                        0
                        это IDEA с мавеном почти идеально работает, а вот с eclipse'ом граблей с костылей куча…
                        что, впрочем, не отменяет его полезности
                          0
                          если учесть, что выбор IDE является почти религиозным, то свойство быть IDE агностиком просто безумно удобно
                      0
                      Для _новичка_ все же лучше Maven. Не более получаса на изучение основ и уже можно собирать проекты. А добавление нового функционала так вообще словно магия, включается несколькими строчками в конфигурацию. Ант клевый, но только тогда когда он _действительно_ необходим.
                        0
                        Проблема в том, что я на 100% уверен что новичка магия строго противопоказана. Наоборот новичок обязан прочувствовать что и как надо делать.
                          0
                          Мне мавен дал быстрый старт. За вышеуказанные полчаса разобрался как нужно организовывать проект, чтобы он стал IDE независим и дистрибутив для _любой_ ревизии менеджер мог собрать сам, без моей помощи. _Правильная_ магия полезна, там новичку сложно выстрелить себе в ногу.
                        0
                        Спрошу в тему :)
                        Имею скрипты на Ant для сборки проектов в production. В скриптах используется replaceregexp. В Ant 1.6.5 — всё было ок. Ant 1.7 — 1.8 — виснет на replaceregexp :(
                        Делаю в WinXP, IDEA.
                          0
                          а standalone ant тоже виснет?
                            0
                            Хм. Проверил щас на 1.8.0 из командной строки — сработало нормально. Видимо что-то в Идее.
                              0
                              ну так добавьте им баг, пусть чинят…
                          +3
                          Я на проекте много лет использовал ант. Проект большой несколько десятков модулей и подпроектов. Антовские скрипты работали как часы, но вот когда надо было подключить новую библиотеку или фреймворк это требовало не мало усилий. А разбираться в километрах xml не каждому хотелось. Вторая проблема не было стандартного подхода в написании этих скриптов в некоторых подпроектах сборка происходила совсем другим собособом и чтоб там что то подправить надо было сидеть и изучать. Вообщем в начале года решил перевести всё на мавен.
                          Почитал восторженые статьи, доки и прикинул что за неделю, полтора управлюсь. В итоге ушло полтора месяца! Это был тихий ужас иногда хотелось лезть на стенку и рвать на голове волосы. Плагины ужасно дырявые, даже стандарные, документации нормальной нет.
                          Мавен это просто набор хороших идей и подходов сваленых в кучу. Если сравнивать с антом то говоря о первом можно представить что ты сидишь за рулём и ведёщь машину, ты сам знаешь когда надо свернуть налево или направо, а где остановиться. С мавеном ты сидишь где то на заднем сиденьи и пишешь на бумажке водителю куда ехать.

                          Вообщем я всё-таки перевёл проект на мавен и не жалею. И всем советую, только надо набраться терпения. Разработка пошла веселее, появились стандарты и требования к сборке проектов и теперь все знают как собирать подпроекты или модули.
                            0
                            Скорее с мавеном вы ведете машину, а с антом регулируете все шестеренки, дабы работали как надо. И здорово, если в выхлопную трубу не выплевывается бензин, а в бак не заливается вода.
                            +1
                            Поняв недостатки Maven, Apache потихоньку переходит на новую систему билдинга проектов, названную Ivy. Основное отличие от Maven2 — это именно интеграция с Ant-ом. Собственно Ivy — это не более чем облегченный менеджер зависимостей, а билдинг модулей осуществляется именно Ant-ом.

                            Основной недостаток Maven состоит в том, что сборка модуля осуществляется только при помощи стандартных плагинов или расширений, которые плохо документированы, и очень не гибкие. Адаптировать сборку для неординатрого случая в Maven бывает очень сложно. В Ivy же можно иметь абсолютно свой сценарий сборки для каждого конкретного случая.

                            P.S. в последнее время стал смотреть в сторону OSGi. OSGi bundles уже внутри прописывают все зависимости. Имеются несколько репозиториев с бандлами.
                              0
                              Когда-то мы использовали Maven первой версии. В проектах кроме Java использовались DSL, так что писали даже свои плагины. Как-то жили, но самой большой проблемой было создание нового рабочего места разработчика. Разные версии Maven, разные версии плагинов — всё это приводило к тому, что некоторые проекты напрочь отказывались собираться свежеустановленным Maven'ом, а у старых разработчиков проблем не было. Выхода второго Maven я не дождался — перевел все проекты на Ant + Ivy. Ant для сборки (прост и стабилен), Ivy для управления зависимостями (гораздо гибче, чем первый Maven).

                              А чтобы не писать build.xml для каждого нового проекта, написал библиотечный build.xml, который делает 99% работы в простых проектах и 90% в сложных. Оставшиеся 10% дописываю в build.xml проекта. Трансляция DSL (JavaCC, Antlr, TreeDL), компиляция Java, создание JavaDoc, тесты, упаковка дистрибутива — из коробки.

                              В качестве бонуса — можно создавать билдеры для трансляции DSL из Eclipse: при изменении исходных файлов запускаются те же Ant'овские цели, что и из консоли.

                              Для сборки любого проекта достаточно установить Ant и достать исходники проекта из svn!

                              Делал для себя, документация минимальна, проект не пиарю, хотя исходники открыты. Но для любопытствующих ссылку дам: BuildBase. И на вопросы отвечу.

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое