Глава 21. Использование Ant из Gradle.

Gradle предоставляет отличную интеграцию с Ant. Вы можете использовать индивидуальные задачи Ant или полностью сборки Ant в ваших сборках Gradle. Фактически, вы найдете более легким и мощным использование задач Ant в сборочном скрипте Gradle, чем в формате XML Ant. Вы даже можете использовать Gradle просто как мощный инструмент в работы с задачами Ant.

Ant может быть разделен на два слоя. Первый слой - язык Ant. Он предоставляет синтаксис для build.xml, обрабатывает цели, специальные конструкции, типа macrodef и так далее. Другими словами, всё, за исключением задач Ant и типом. Gradle понимает этот язык и позволяет вам импортировать ваш Ant build.xml прямо в проект Gradle. Вы затем можете использовать цели вашей сборки Ant, как если бы они были задачами Gradle.

Второй слой - это множество задач и типов Ant, наподобие javac, copy или jar. Для этого слоя Gradle предоставляет интеграцию просто полагаясь на Groovy и фантастический AntBuilder.

Наконец, так как сборочные скрипты - это скрипты Groovy, вы всегда можете выполнить сборку Ant как внешний процесс. Ваш сборочный скрипт может содержать такие инструкции: 'ant clean compile'.execute().

Вы можете использовать интеграцию Gradle с Ant как путь для перехода вашей сборки с Ant на Gradle. Например, вы можете начать с импортирования существующей сборки Ant. Затем можете переместить объявления зависимостей из скрипта Ant в ваш сборочный файл. Наконец, можете переместить задачи в ваш сборочный файл или заменить их какими-либо плагинами Gradle. Этот процесс можно делать по частям со временем и у вас будет рабочая сборка Gradle во время всего процесса.

21.1. Использование задач и типов Ant в вашей сборке.

В вашем сборочном скрипте Gradle предоставляет свойство ant. Это ссылка на экземпляр AntBuilder. Он используется для получения доступа к задачам, типам и свойствам Ant из вашего сборочного скрипта. Есть очень простое отображение из формата build.xml Ant в Groove, которое объясняется ниже.

Для выполнения задачи Ant вы вызываете метод у экземпляра AntBuilder. Для этого вы используете имя задачи в качестве имени метода. Например, вы выполняете задачу echo, вызывая метод ant.echo(). Атрибуты задачи Ant передаются в виде Map параметров в метод. Ниже пример задачи echo. Обратите внимание, чтобы вы можете смешивать код Groovy и язык разметки задачи Ant. Это дает большие возможности.

Пример 21.1. Использование задачи Ant

build.gradle

task hello {
    doLast {
        String greeting = 'hello from Ant'
        ant.echo(message: greeting)
    }
}
	  

Вывод команды gradle hello

> gradle hello
:hello
[ant:echo] hello from Ant

BUILD SUCCESSFUL

Total time: 1 secs
	  

Вы можете передавать вложенный текст в задачу Ant в качестве параметра метода. В этом примере, мы передаем сообщение для задачи echo как вложенный текст:

Пример 21.2. Использование задачи Ant

build.gradle

task hello {
    doLast {
        ant.echo('hello from Ant')
    }
}
	  

Вывод команды gradle hello

> gradle hello
:hello
[ant:echo] hello from Ant

BUILD SUCCESSFUL

Total time: 1 secs
	  

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

Пример 21.3. Использование задачи Ant

build.gradle

task zip {
    doLast {
        ant.zip(destfile: 'archive.zip') {
            fileset(dir: 'src') {
                include(name: '**.xml')
                exclude(name: '**.java')
            }
        }
    }
}
	  

Получить доступ к типам Ant можно таким же образом как и к задачам, используя имя типа в качестве имени метода. Вызов метода возвращает тип данных Ant, который затем вы можете использовать в вашем сборочном скрипте. В следующем примере, мы создаем Ant объект типа path, затем последовательно проходим по его содержимому.

Пример 21.4. Использование типа Ant

build.gradle

task list {
    doLast {
        def path = ant.path {
            fileset(dir: 'libs', includes: '*.jar')
        }
        path.list().each {
            println it
        }
    }
}
	  

Больше информации о AntBuilder можно найти в 'Groovy in Action' 8.4 или сайте Groovy Wiki.

21.1.1. Использование пользовательских задач Ant в вашей сборке

Чтобы сделать пользовательские задачи доступными в вашей сборке, вы можете использовать taskdef (обычно легче) или typedef задачи Ant, как вы бы их использовали в файле build.xml. Затем вы можете ссылаться на пользовательские задачи Ant как на встроенные в него задачи.

Пример 21.5. Использование пользовательской задачи Ant

build.gradle

task check {
    doLast {
        ant.taskdef(resource: 'checkstyletask.properties') {
            classpath {
                fileset(dir: 'libs', includes: '*.jar')
            }
        }
        ant.checkstyle(config: 'checkstyle.xml') {
            fileset(dir: 'src')
        }
    }
}
	  

Вы можете использовать управление зависимостями Gradle для компоновки пути к классам для использования для пользовательских задач. Чтобы сделать это, вам надо определить пользовательскую конфигурацию для пути к классам, затем добавить несколько зависимостей в нее. Более детально этот процесс описан в Секции 25.4 Как объявить ваши зависимости.

Пример 21.6. Объявление пути к классам для пользовательской задачи Ant

build.gradle

configurations {
    pmd
}

dependencies {
    pmd group: 'pmd', name: 'pmd', version: '4.2.5'
}
	  

Для использования конфигурации пути к классам, пользуйтесь свойством asPath пользовательской конфигурации.

Пример 21.7. Использование пользовательской задачи Ant и управления зависимостями вместе

build.gradle

task check {
    doLast {
        ant.taskdef(name: 'pmd',
                    classname: 'net.sourceforge.pmd.ant.PMDTask',
                    classpath: configurations.pmd.asPath)
        ant.pmd(shortFilenames: 'true',
                failonruleviolation: 'true',
                rulesetfiles: file('pmd-rules.xml').toURI().toString()) {
            formatter(type: 'text', toConsole: 'true')
            fileset(dir: 'src')
        }
    }
}
	  

21.2. Импортирование сборки Ant.

Вы можете использовать метод ant.importBuild() для импорта сборки Ant в ваш проект Gradle. Когда вы импортируете сборку Ant, каждая цель Ant рассматривается как задача Gradle. Это означает, что вы можете управлять и выполнять цели Ant таким же образом как и задачи Gradle.

Пример 21.8. Импортирование сборки Ant

build.gradle

ant.importBuild 'build.xml'
	  

build.xml

<project>
    <target name="hello">
        <echo>Hello, from Ant</echo>
    </target>
</project>
	  

Вывод команды gradle hello

> gradle hello
:hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL

Total time: 1 secs
	  

Вы можете добавлять задачи, которые зависят от целей Ant:

Пример 21.9. Задача, которая зависит от цели Ant

build.gradle

ant.importBuild 'build.xml'

task intro(dependsOn: hello) {
    doLast {
        println 'Hello, from Gradle'
    }
}
	  

Вывод команды gradle intro

> gradle intro
:hello
[ant:echo] Hello, from Ant
:intro
Hello, from Gradle

BUILD SUCCESSFUL

Total time: 1 secs
	  

Или можете добавлять поведение к цели Ant:

Пример 21.10. Добавление поведения к цели Ant

build.gradle

ant.importBuild 'build.xml'

hello {
    doLast {
        println 'Hello, from Gradle'
    }
}
	  

Вывод команды gradle hello

> gradle hello
:hello
[ant:echo] Hello, from Ant
Hello, from Gradle

BUILD SUCCESSFUL

Total time: 1 secs
	  

Также есть возможность указать зависимость цели Ant от задачи Gradle:

Пример 21.11. Цель Ant, которая зависит от задачи Gradle

build.gradle

ant.importBuild 'build.xml'

task intro {
    doLast {
        println 'Hello, from Gradle'
    }
}
	  

build.xml

<project>
    <target name="hello" depends="intro">
        <echo>Hello, from Ant</echo>
    </target>
</project>
	  

Вывод команды gradle hello

> gradle hello
:intro
Hello, from Gradle
:hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL

Total time: 1 secs
	  

Иногда есть необходимость 'переименовать' задачу сгенерированную для цели Ant, чтобы избежать совпадения с именем существующей задачи Gradle. Для этого используйте метод AntBuilder.importBuild(java.lang.Object, org.gradle.api.Transformer).

Пример 21.12. Переименование импортируемых целей Ant

build.gradle

ant.importBuild('build.xml') { antTargetName ->
    'a-' + antTargetName
}
	  

build.xml

<project>
    <target name="hello" depends="intro">
        <echo>Hello, from Ant</echo>
    </target>
</project>
	  

Вывод команды gradle a-hello

> gradle a-hello
:a-hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL

Total time: 1 secs
	  

Обратите внимание, что хотя второй аргумент в этот метод должен быть Transformer, когда мы программируем на Groovy, можно просто использовать замыкание вместо анонимного внутреннего класса (или чего-то похожего) благодаря поддержки Groovy автоматического преобразования замыкания в типы, имеющие одиночный абстрактный метод.

21.3. Свойства и ссылки Ant.

Есть несколько способов установить свойство Ant, так чтобы задачи Ant могли его использовать. Вы можете установить свойство прямо у экземпляра AntBuilder. Свойства Ant также доступны как ассоциативный массив (Map), который вы можете изменять. Еще вы можете использовать задачу Ant property. Ниже несколько примеров как это сделать.

Пример 21.13. Установка свойства Ant

build.gradle

ant.buildDir = buildDir
ant.properties.buildDir = buildDir
ant.properties['buildDir'] = buildDir
ant.property(name: 'buildDir', location: buildDir)
	  

build.xml

<echo>buildDir = ${buildDir}</echo>
	  

Многие Ant-задачу устанавливают свойства во время выполнения. Есть несколько способов получить значение этих свойств. Вы можете получить свойство прямо у экземеляра AntBuilder. Свойства Ant доступны в виде ассоциативного массива (Map). Ниже несколько примеров.

Пример 21.14. Получение свойства Ant

build.xml

<property name="antProp" value="a property defined in an Ant build"/>
	  

build.gradle

println ant.antProp
println ant.properties.antProp
println ant.properties['antProp']
	  

Есть несколько способов установить ссылку Ant:

Пример 21.15. Установка ссылки Ant

build.gradle

ant.path(id: 'classpath', location: 'libs')
ant.references.classpath = ant.path(location: 'libs')
ant.references['classpath'] = ant.path(location: 'libs')
	  

build.xml

<path refid="classpath"/>
	  

Есть несколько способов получить ссылку Ant:

Пример 21.16. Получение ссылки Ant

build.xml

<path id="antPath" location="libs"/>
	  

build.gradle

println ant.references.antPath
println ant.references['antPath']
	  

21.4. Логгирование Ant.

Gradle отображает приоритеты сообщений Ant на уровни лога, так что сообщения логгируемые из Ant появляются в выводе Gradle. По умолчанию, они отображаются вот так:

Таблица 21.1. Отображение приоритетов сообщений Ant
Приоритет сообщения AntУровень лога Gradle
VERBOSEDEBUG
DEBUGDEBUG
INFOINFO
WARNWARN
ERRORERROR

21.4.1. Тонкая настройка логгирования Ant

Отображение приоритетов сообщения Ant в Gradle по умолчанию может быть проблематичным. Например, нет приоритета сообщения отображаемого точно в уровень лога LIFECYCLE, который по умолчанию у Gradle. Многие задачи Ant логгируют сообщения с приоритетом INFO, это означает, что для вывода таких сообщений из Gradle, сборка должна быть запущена с уровнем лога INFO, потенциально логгирующего намного больше, чем хотелось бы.

Наоборот, если задача Ant логгирует сообщения со слишком высоким уровнем, для их скрытия потребуется запустить сборку с более высоким уровнем лога, таким как QUIET. Однако, это может привести к тому, что желаемый вывод будет скрыт.

Для помощи в такой ситуации, Gradle позволяет пользователю тонкую настраивать логгирование Ant и контролировать отображение приоритетов сообщений в уровень лога Gradle. Это делается установкой приоретета, который должен отображаться в уровень лога по умолчанию для Gradle LIFECYCLE, с использованием метода AntBuilder.setLifecycleLogLevel(java.lang.String). Когда это значение установлено, любое сообщение Ant логгируемое с настроенным приоритетом или выше будет записано в лог как минимум на уровне лога LIFECYCLE. Любое сообщение Ant логгируемое ниже этого приоритета, будет записано в лог как максимум на уровне лога INFO.

Например, в следующем примере отображение изменяется так, что приоритет сообщений Ant INFO выводится на уровне лога LIFECYCLE.

Пример 21.17. Тонкая настройка логгирования Ant

build.gradle

ant.lifecycleLogLevel = "INFO"

task hello {
    doLast {
        ant.echo(level: "info", message: "hello from info priority!")
    }
}
	  

Вывод команды Gradle hello

> gradle hello
:hello
[ant:echo] hello from info priority!

BUILD SUCCESSFUL

Total time: 1 secs
	  

С другой стороны, если lifecycleLogLevel установлено в ERROR, то сообщения Ant логгируемые с приоритетом WARN больше не будут логгироваться на уровне лога WARN. Теперь они будут логгироваться на уровне INFO и по умолчанию будут скрыты.

21.5. API.

Интеграция с Ant предоставляется AntBuilder.