Не ant-ом единым…

Рубрика: Development, Groovy, Java | 10 August 2007, 08:52 | Vadim Voituk

… или гибкая сборка проекта с помощью Groovy

English version of this article

Предположим, что в пrроцессе сборки вам нужно собрать под 30-40 билдов с разными параметрами.
Или внедрить в приложение статистические данные удаленных серверов.
Или нетривиальным образом заполнить тестовую базу перед началом модульного/функционального тестирования
Ко всем прочему не хотелось в итоге вместо сценария сборки, получить кучу “хаков” больше похожих на лапшу из псевдо-кода и Ant-xml, не поддающихся модификации.

Тут на помощь может прийти Groovy.
Не в полной мере понимаю зачем, но разработчики Groovy решили включить в него Ant со всеми стандартными task-ами и plugin-ами. Доступ к этим возможностям можно получить через встроенный класс AntBuilder.

Напишем каркас небольшого helper-класс для сборок проекта:
[java]

class GroovyBuilder {

	// Application entry point
	static void main(args) {
		if (args.length <= 0) {
			println "Usage: groovy GroovyBuilder.groovy "
			System.exit(0);
		}
		def target = args[0] // Имя переменной уже немного забегает вперед
		GroovyBuilder build = new GroovyBuilder()
		build."$target"(args)
	}
}

[/java]
Из кода несложно увидеть что при запуске скрипта будет запускаться метод класса GroovyBuilder, указанный в первом параметре – в принципе ничего особенного, как и и ничего относящегося к процессу сборки проекта.
Создадим экземпляр AntBuilder в конструкторе класса:
[java]

// Constructor
def GroovyBuilder() {
	ant = new AntBuilder()
}

[/java]
и добавим несколько методов по аналогии со списком target-ов в в файле build.xml
[java]

// INIT
void init(args) {
	ant.mkdir(dir: basedir + "/bin")
	ant.mkdir(dir: basedir + "/build")
}
// BUILD
void build(args) {
	init() // `build` target depends of `init` target
	ant.buildnumber()
	ant.javac(srcdir:basedir+"/src", destdir:basedir+"/bin",)
}
// RUN
void run(args) {
	build() // `run` target depends of `build` target
	ant.java(classpath:basedir+"/bin",classname: "Test")
}
// JAR
void jar(args) {
	build();
	ant.jar(
		destfile:"build/my-test-proj.${ant.project.properties['build.number']}.jar",
		basedir:basedir+"/bin"
	)
}
// CLEAR
void clear(args) {
	ant.delete(dir: basedir + "/bin", failonerror:false)
	ant.delete(dir: basedir + "/build", failonerror:false)
}

[/java]
IMHO это как раз тот случай когда проще показать на примере, чем углубляться в первопричины и теорию.
Пробуем запустить таким образом:

E:\my\workspace\GG>groovy GroovyBuilder.groovy build
[mkdir] Created dir: E:\my\workspace\GG\bin
[mkdir] Created dir: E:\my\workspace\GG\build
[javac] Compiling 1 source file to E:\my\workspace\GG\bin

В результате получаем собранное приложение.

Внимательный читатель заметит, что названия методов обьекта ant (класса AntBuilder) и их параметров полностью совпадают с именами task-ов и их параметров, указываемых в build.xml
В результате мы имеем тот же build.xml, записанный в ином стиле: в него легко внедрить flow-логику и формирование build workspace.
В книге “Groovy in Action” для примера приводился build.xml, который не должен выполнять сборку приложения на JDK версии ниже 1.5. Там же на Groovy подобная проверка занимала ровно одну строку.

Использовать или не использовать сборку проекта с помощью Groovy – зависит от ситуации и от политики принятой в проекте. Лично я уже видел с десяток build.xml-файлов, где этот подход сэкономил бы время разработчика на написание пару сотен строк xml-я и нескольких самописных Ant task-ов.

Пример приложения, которое собирается таким образом можно загрузить тут (5Кб).
Там же находится полный листинг описанного тут каркаса GroovyBuilder.
Небольшая вводная статья с примерами по AntBuilder на сайте Groovy.

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

2 Responses to “Не ant-ом единым…”

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

  1. Ya

    [QUOTE]Не в полной мере понимаю зачем, но разработчики Groovy решили включить в него Ant со всеми стандартными task-ами и plugin-ами. [QUOTE]Ну вот в вашей статье примерно и объясняется, “зачем”))

  2. Vadim Voituk

    Но это скорее это не причина а следствие :)

Leave a Reply