Содержание


Практическая автоматизация

Сборка проектов Java с помощью Raven

Попрощайтесь с невыразительностью - используйте Ruby для построения Java-приложений

Comments

Серия контента:

Этот контент является частью # из серии # статей: Практическая автоматизация

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Практическая автоматизация

Следите за выходом новых статей этой серии.

В своем проекте на Java я уже несколько лет тщательно поддерживаю сценарий сборки, написанный на Ant. Мне нравится, что для Ant есть множество задач; однако часто оказывается, что XML-синтаксис сценариев Ant довольно трудоемок для написания. Кроме того, XML-наследие Ant порой вносит ограничения, когда речь заходит о выразительности. В самом деле, когда мне бывает нужна более высокая степень гибкости (например, в условной логике), я часто вынужден написать специальную задачу или встраивать логику в задачу сценария Ant с помощью, например, Groovy.

Долой невыразительность!

Несколько лет назад в стремлении найти более выразительные инструменты для сборки программ я узнал о Rake. Rake - это язык предметной области (DSL) для сборки программ с помощью полнофункционального языка программирования Ruby. Благодаря Rake я получаю требуемую мне выразительность без необходимости совершать акробатические номера. Например, мне не нужно писать специальные задачи, потому что скрипт Rake — это Ruby (в отличие от XML); следовательно, если мне нужна какая-либо условная логика, я легко могу запрограммировать ее там, где она требуется. Более того, Rake использует систему задач на основе зависимостей, подобную той, что есть в Ant и его почтенном прародителе, make. Например, если я напишу rake deploy, Rake вызовет зависимые задачи, которые я указал ранее, такие как компиляция, запуск тестов и т.д. Кроме того, Rake достаточно умен, чтобы запускать зависимые задачи только по одному разу (впрочем, как и Ant).

Сам по себе Rake не так уж и полезен для большинства Java-проектов, однако относительно новый проект, названный Raven, совместил мощь и выразительность Rake с задачами, характерными для создания приложений на Java. В лице Raven Java-разработчики получили действительно жизнеспособную платформу сборки, которая обеспечивает такие специфические для Java возможности, как компиляция с помощью javac и архивирование двоичных файлов утилитами jar и war, а также большую выразительность языка программирования Ruby.

Raven - это Rake, а Rake - это Ruby

Перед началом использования Raven для Java-проектов полезно понять связь между Raven и Rake. На рис. 1 приведена структура Raven, где можно увидеть, что Raven использует Rake, RubyGems и Ruby. Следовательно, родные для Rake задачи также доступны при использовании Raven; вдобавок, вы также можете использовать Ruby в сценариях Raven. RubyGems - это менеджер пакетов, подобный CPAN, RPM или APT, который можно использовать для загрузки необходимых для Ruby пакетов (и jar-файлов Java), а также пакетов, требуемых по зависимостям.

Рис. 1. Структура Raven
Структура Raven

Хотя пока присяжные не определились, является ли Raven лучшей платформой для сборки Java-проектов, я думаю, что многие согласятся с тем, что Raven сочетает в себе простоту и мощь, двигаясь в направлении более естественного языка программирования для сборки ПО. По моему мнению, отсутствие зависимости от XML при сборке Java-проектов - это уже достаточная причина, чтобы взглянуть на Raven.

Raven стоит на пороге

Для установки и настройки Raven есть два подхода: первый — в стиле Ruby, второй - больше в стиле Java благодаря использованию JRuby. Я предпочитаю способ с использованием Java, потому что он значительно проще при настройке. Чтобы получить и запустить Raven, требуются несколько шагов:

  • Скачать дистрибутив Raven/JRuby (см. Ссылки).
  • Распаковать файл в каталог вашей рабочей станции.
  • Создать переменную среды с именем JRUBY_HOME.
  • Добавить JRUBY_HOME/bin к переменной среды PATH.
  • Проверить правильность установки, для чего нужно в командной строке ввести jruby -version. Если все установлено правильно, то будет выведен ответ наподобие ruby 1.8.5 (0) [java].

Здравствуй, Raven

Конечно, загрузка и установка Raven - это не самое интересное. Самая соль этого инструмента — гибкость в создании скриптов сборки. В случае Raven файлы сборки называются Rakefiles, и у них простой формат; на самом деле, если раньше вам уже доводилось программировать на Ruby (или видеть какую-нибудь программу на Ruby), то эти языки покажутся довольно похожими. В этом, между прочим, прелесть Raven: это и есть Ruby — с вкраплениями некоторых специальных слов.

Чтобы быстро начать использовать Raven, я, пожалуй, начал бы с самой основной (и важной) задачи - компиляции. Структура каталогов на рис. 2 представляет схему моего Java‑проекта. Сведения о том, где находятся мои сторонние библиотеки и исходный код, вскоре пригодятся.

Рис. 2. Структура каталогов существующего Java-проекта
Структура каталогов существующего Java-проекта

Обратите внимание на каталог lib на рис. 2. Здесь располагаются сторонние JAR-файлы. Прежде чем приступать к компиляции, нужно создать путь к классам, что очень легко сделать в Raven, потому что он поддерживает возможность создания classpath через задачу dependency (которая на самом деле является просто методом Ruby, предоставляемым Raven и называемым dependency), что проиллюстрировано в листинге 1:

Листинг 1. Создание classpath в Raven
require 'raven'
require 'rake'

dependency 'deps' do | task |
  task.libs = Dir.glob('lib/**/*.*')  
end

Задача поиска зависимостей deps определенная в листинге 1, включает в себя все библиотеки в моем каталоге lib, которые используют класс Dir и метод glob() Можно также использовать задачу поиска зависимостей для загрузки JAR-файлов (с помощью RubyGems) из репозитория (что похоже на механизм управления зависимостями в Maven).

В листинге 1 я специально включил в путь к классам все, что находится в каталоге lib. Я назвал эту задачу deps и, как можно видеть в листинге 2, я могу сделать так, чтобы эта задача выполнялась явно перед попыткой что-нибудь скомпилировать:

Листинг 2. Компиляция — это просто
javac 'compile' => 'deps' do |task|
  task.build_path << "src"
end

Как вы можете увидеть, я выполняю компиляцию через Raven-задачу javac. Задача называется compile, и у нее есть зависимости от задачи deps из листинга 1. Знак => означает, что Raven будет запускать любую задачу (или задачи), указанные справа от этого оператора перед текущей задачей (очень похоже на атрибут depends элемента target в Ant).

Все волшебство происходит между do и end моей задачи javac. По умолчанию задача javac использует "src/main/java" в качестве стандартного значения build_path. Но, поскольку мой Java-проект не следует этому соглашению (помните рис. 2?), то нужно изменить свойство build_path, которое в моем случае равно src, потому что именно там лежит исходный код.

Чтобы протестировать этот скрипт Raven, нужно в командной строке написать rake compile. Полученные в результате компиляции .class‑файлы будут помещены в каталог target/classes, автоматически создаваемый Raven-задачей javac.

Меньше значит больше

В этом месте следует прояснить один момент. Мне не пришлось писать много кода, чтобы запустить компиляцию, потому что Raven некоторые вещи делал «за сценой», как, например, создание каталога target/classes и копирование туда получившихся class-файлов. В самом деле, вы уже, наверное, забыли, как выглядит эквивалентный сценарий Ant для листинга 1 и листинга 2. В качестве напоминания об этом в листинге 3 показана типичная компиляция с помощью сценария сборки Ant:

Листинг 3. Компиляция исходного текста на Java с помощью Ant
<?xml version="1.0" encoding="iso-8859-1"?>
<project name="compile-code" default="all" basedir=".">
...
  <target name="compile-src">
    <mkdir dir="${classes.dir}"/>
    <javac destdir="${classes.dir}" debug="true">
      <src path="${src.dir}" />
      <classpath refid="project.class.path"/>
    </javac>
  </target>
<project>

При сравнении листинга 3 с листингами 1 и 2 обнаруживаются некоторые поразительные различия, не правда ли? Raven не только избавился от XML, но и предполагает некоторые базовые атрибуты, позволяя тем самым задавать меньше параметров при определении задач. Более того, как показывается в листинге 2, при необходимости Raven дает возможность переопределять значения, применяемые Raven по умолчанию.

Хотя листинги 1 и 2, несомненно, интересны с точки зрения сравнения, компиляция — только начало того чуда, которым является создание сценариев сборки. Я покажу еще более интересную возможность: упаковка Web-приложения, написанного на языке Java.

Создание простого war-файла

Файлы Web-архивов (WAR) используются для упаковки web-приложений и содержат различные ресурсы, например, сервлеты, сторонние библиотеки и изображения. В этих архивах используется стандартная схема именования каталогов и считается, что некоторые файлы, например, web.xml (в котором указываются имена сервлетов и другие параметры конфигурации), находятся в каталоге WEB-INF.

Raven делает создание WAR-файла совсем простым. В листинге 4 я использую задачу war с именем 'brewery.war', которая по умолчанию создает WAR-файл с таким же именем. По умолчанию webapp_dir равно src/main/webapp, но так как моя структура каталогов отличается от той, которая принята в Raven по умолчанию, необходимо изменить это с помощью строки task.webapp_dir = 'src/web'.

Листинг 4. Создание WAR для размещения веб-контейнера
war 'brewery.war' => ['clean', 'compile', 'java-doc'] do |task|
  task.webapp_dir = 'src/web'
end

Обратите внимание на инструкцию, указывающую, что перед созданием WAR-файла Raven должен сначала запустить задачу clean, за ней задачу compile, а затем задачу создания документации. После успешного выполнения этих задач Raven может создать архив, для чего, как вы можете увидеть, требуется написать очень немного кода. На самом деле если бы в проекте использовалась стандартная схема каталогов, принятая в Raven, мне бы не потребовалось писать ничего, кроме этих зависимых задач (то есть не нужен был бы текст между do и end!).

Трудно поверить, но это все: — Raven-задача war tсправляется с созданием каталогов, размещением файлов и созданием war-файла. Очень эффективно, не правда ли?

Простой способ создания документации

Создание проектной документации часто оказывается полезным при распространении информации среди членов команды. Если приходится писать каркас программы или используемые другими утилиты, то в конце концов потребуется публиковать Javadoc-документы, которые являются HTML-файлами, описывающими классы, методы и общедоступные переменные, находящиеся в текстах исходных кодов.

Создание документации с помощью механизма Javadoc при использовании Raven выполняется очень просто, как показано в листинге 5:

Листинг 5. Создание документации JavaDoc с помощью Raven
javadoc 'java-doc' => 'deps' do |task|
  task.build_path << "src"
end

Обратите внимание, что из-за того, что мой проект не следует стандартной модели Raven, необходимо изменить свойство build_path задачи javadoc. Кроме того, эта задача зависит от задачи deps (из листинга 1) при включении ссылок на классы.

Теперь должно быть понятно, что если проект следует стандартной схеме Raven, то скрипты сборки будут даже проще, чем мои!

Еще!

Хотя я описал только несколько возможностей Raven, с помощью этой новаторской платформы сборки можно сделать еще очень многое. В частности, в Raven есть обширная поддержка обработки зависимостей при сборке (то есть сторонних библиотек) с помощью RubyGems, механизма автозагрузки версионных двоичных файлов во время сборки, а не поиска по дискам общего доступа. RubyGems работает со сторонними библиотеками аналогично Maven или Ivy.

Кроме RubyGems, Raven может также запускать тесты JUnit, собирать обычные JAR-файлы и чистить каталоги. В таблице 1 перечислены наиболее популярные задачи, предоставляемые Raven для упрощения сборки Java-проектов:

Таблица 1. Популярные (и полезные) задачи Raven
Задача RavenОписание
javacКомпилирует исходные файлы Java и помещает итоговые файлы классов в каталог target/classes (по умолчанию).
jarСоздает JAR-файл, который часто является набором .class-файлов.
warСоздает архив web-приложения, который может разворачиваться в web-контейнер Java .
javadocСоздает документы Javadoc из исходных текстов.
junitВыполняет тесты JUnit
jar_sourceСоздает JAR-файл из исходных файлов на Java.
gem_wrap_instПреобразует JAR-файл в RubyGem, а затем устанавливает файл в репозиторий.

По мере развития Raven список в таблице 1 должен будет расти. Кроме того, если в Raven не хватает чего-то нужного, ничто не мешает написать это самостоятельно!

Заключение

Надеюсь, мне удалось продемонстрировать, что красота Raven состоит в том, что этот язык дает возможность использовать силу и гибкость языка Ruby в скрипте сборки. Не мне решать, станет ли Raven популярным инструментом сборки Java-проектов, но я полагаю, что Raven движет отрасль в правильном направлении. В частности, Raven позволяет управлять задачами с зависимостями с помощью полноценного процедурного языка программирования (а не декларативного, как XML). Попробуйте и увидите, что я имею в виду.


Ресурсы для скачивания


Похожие темы

  • Оригинал статьи (EN)
  • Raven: Scripting Java Builds with Ruby (EN) (Matthieu Riou, Apress, 2007): полное руководство по Raven, написанное его создателем.
  • "Using the Rake Build Language" (EN) (Martin Fowler, martinfowler.com, август 2005): использовать Ruby для создания программного обеспечения — это очень интересно.
  • "Ruby off the Rails" (EN) (Andrew Glover, developerWorks, октябрь 2005): познакомьтесь с Ruby, прежде чем запрыгивать в Rails-вагон (или выпрыгивать из него).
  • "Practically Groovy: Ant scripting with Groovy" (EN) (Andrew Glover, developerWorks, декабрь 2004): Эндрю Гловер представляет утилиту компоновки Groovy, которая значительно облегчает сочетание Groovy с Ant и Maven для создания более выразительных и управляемых сценариев сборки.
  • "What's after Ant?" (EN) (Andrew Glover, thediscoblog.com, апрель 2007): Эндрю Гловер обсуждает будущее скриптовых языков.
  • Raven: загрузить Raven и JRuby.(EN)
  • Ruby: загрузить программу-установщик Ruby.(EN)
  • RubyGems: загрузить систему управления пакетами RubyGems.(EN)
  • Программный код примера: сценарий на Raven из статьи.(EN)
  • Технология Java: сотни статей по каждому аспекту программирования на Java.

Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=349168
ArticleTitle=Практическая автоматизация: Сборка проектов Java с помощью Raven
publish-date=10312008