По дорозі java, linux і open source основи використання системи збирання apache ant

Основи використання системи збирання Apache Ant

Коли ведеться розробка програмного продукту, він може складатися з безлічі вихідних частин. Наприклад, розробка може вестися декількома людьми практично незалежно один від одного, а файли з вихідним кодом, за який вони відповідають, можуть знаходиться в абсолютно різних місцях файлової системи і навіть на різних машинах. Крім файлів вихідного коду, в проекті можуть використовуватися також і готові бібліотеки від сторонніх розробників (наприклад, файли jar, dll або so), файли конфігурації, різні картинки і іконки, звукові файли і купа всього іншого. Всі ці штуки можуть так само змінюватися в ході розробки проекту іншими людьми.

А тепер уявіть, що з усього цього неподобства необхідно зібрати всього один файл стиснутого архіву, який користувач міг би завантажити з вашого сайту, распакавать і відразу ж запустити ваш продукт. Вам потрібно буде зібрати разом всі файли з вихідним кодом Java і скомпілювати їх, прогнати тести, щоб переконатися що проект ніхто не поламав, отримані class-файли упакувати в JAR (або кілька JAR'ов), для якого ще потрібно згенерувати правильний маніфест, що містить CLASSPATH, ім'я головного класу, номер версії і т.п. потім зібрати разом всі інші файли на зразок бібліотек, картинок і конфігов, розіпхати це все в правильні каталоги, згенерувати документацію, створити з усього цього архів і залити його на ваш веб-сервер, а все, що відбулося записати в лог і зберегти його в базі даних, яка зберігає інформацію про різні збірках. Робити все це руками досить сумно, та й не повинен психічно здорова людина цим займатися.

Системи збирання, такі як Apache Ant. були створені для того, щоб автоматизувати весь цей часом досить складний і рутинний процес по збірці проекту. Причому, у випадку з Apache Ant проект не обов'язково повинен бути на Java, і не обов'язково повинен бути взагалі програмним забезпеченням. Це може бути що завгодно, хоча орієнтований він, звичайно ж, в першу чергу на Java. У даній статті я хочу на дуже простому прикладі показати, як можна полегшити собі життя за допомогою Apache Ant.

Мінімальні знання про використання Apache Ant

Про те, як збирати проект, ant дізнається зі спеціального xml-файлу, в якому розробник описує всі кроки, необхідні для збірки. Зазвичай цей файл носить ім'я build.xml. але воно може бути і іншим. Просто при запуску ant сам шукає файл build.xml в каталозі з якого він запущений, а при використанні нестандартного імені необхідно передати його програмі ant як параметр.

Якщо терміни "Мета" і "Завдання" заплутують вас, то спробуйте міркувати як-небудь так: "Для того щоб досягти будь-яку мету, потрібно виконати певні завдання". Наприклад, щоб досягти мети "Скомпілювати проект", необхідно виконати завдання: "Створити каталог для скомпільованих файлів", "Запустити компілятор javac" і "Створити JAR".

Крім цілей, завдань і ресурсів є властивості. До властивостей можна відноситься як до змінних, а точніше констант. У властивості є ім'я і значення у вигляді рядка. Значення властивості встановлюється один раз і будь-яка спроба змінити це значення ігнорується. Властивості зазвичай використовуються в атрибутах завдань. Установка значення може відбуватися в самому файлі build.xml або в зовнішньому properties-файлі, що дуже зручно і дозволяє змінювати процес збірки не змінюючи build.xml.

У файлі build.xml значення властивості може бути встановлено за допомогою елемента property. Цей елемент може використовуватися як всередині кореневого елемента project, так і всередині target'ов:

Як вже було сказано, властивості можуть бути визначені і в зовнішньому файлі properties. Записи властивостей в цьому файлі можуть виглядати так:
Щоб властивості, записані в файлі, стали доступні в сценарії збирання, потрібно його підключити:

Для отримання доступу до значення властивості використовується конструкція $. Наступний код виводить на екран значення властивості з ім'ям myProp:

Прикладом ресурсів можуть бути, наприклад, елементи file і url:

Думаю, що тут все зрозуміло без зайвих слів.

Однак, частіше зручніше користуватися не окремими ресурсами, а колекціями ресурсів - елементами, які представляють групу схожих ресурсів. Наприклад, елемент fileset представляє групу файлів, які можуть бути описані безліччю різних способів.

У цьому прикладі в fileset увійдуть всі файли java з каталогу src і його підкаталогів, крім файлів, в імені яких є слово Test з урахуванням регістру.

Крім описаних видів ресурсів, також існують, так звані, path-like структури. Не знаю, чи варто відносити їх до колекцій ресурсів, але краще місця для них я не придумав, тому згадаю ці структури тут. З назви, думаю, зрозуміло, що це елементи які описують такі речі як шляху (PATH). Їх наповненням можуть бути різні ресурси і їх колекції.

Зверніть увагу, що в даному прикладі так само використовуються властивості mylib.dir і extlib.dir, значенням яких є шляхи до каталогів з власними і внешнімім бібліотеками, відповідно.

В описаних path-like структурах, Ant буде автоматично використовувати правильний символ сепаратора для поділу ресурсів, відповідний операційній системі, на якій він виконується.

Дуже зручною можливістю в path-like структурах є можливість однієї структури посилатися на іншу, використовуючи атрибути id і refid:

Більш докладно про ресурсах можна почитати тут.

Завдання представляють дії, які можуть здійснюватися з будь-якими ресурсами або без їх участі. Найбільш часто зустрічаються завдання представлені в таблиці.

Часто використовувані завдання


Нижче приведу найпростіші приклади використання задач.

Компіляція файлів з кодом java:

Іноді для виконання деяких завдань вистачає лише вказівки правильних атрибутів, але крім цього всередині тега завдання можуть перебувати і вкладені елементи, які, наприклад, можуть описувати ресурси з якими необхідно працювати задачі. Більш цікаве застосування різних завдань буде продемонструвати пізніше на простому прикладі збірки проекту.

Повний список завдань представлений тут.

Отже, ми підійшли до мети :) На цілях будується весь сценарій збірки. Ви ставите цілі і досягаєте їх за допомогою виконання завдань і використання ресурсів. Навіщо використовувати цілі, якщо всі завдання можна писати прямо в кореневому елементі project? А потім, що цілі дозволяють розділити сценарій збірки на окремі закінчені логічні етапи, які можуть бути залежними один від одного. Тобто одна мета може бути позначена як залежна від іншої мети, і для її досягнення необхідно, щоб спочатку була досягнута мета від якої вона залежить.

У разі, якщо завдання розташовані в кореневому елементі project, то ant, проходячи по файлу build.xml, послідовно їх виконує. При такому підході ви можете визначити для себе тільки один варіант виконання збірки. При використанні цілей можна вказати ant'у яку мету необхідно досягти, а він уже сам перевірить її залежності і виконає спочатку цілі від яких залежить головна.

У наведеному прикладі описані цілком реальні цілі, тільки замість елементів echo в них повинні бути більш корисні завдання. В елементі project встановлено значення атрибута default рівне compile, яке означає, що за замовчуванням ant буде виконувати мета compile, яка залежить від мети make.build.dirs, тому спочатку буде виконана мета make.build.dirs, а потім compile. Якщо ж ant'у при запуску вказати мету dist, яка залежить одночасно від двох цілей compile і make.dist.dirs, то спочатку буде виконано етап описаний вище, потім make.dist.dirs, а вже потім dist:
Крім цього в прикладі також є мета clean, яка не залежить ні від жодних інших цілей, і також немає мети яка залежала б від clean, тому дана мета може бути тільки явно викликана ant'ом: ant clean.

На додаток до залежностей мети від мети, для управлінням процесом складання існує залежність цілі від властивості, точніше в термінах ant'а це називається умовами. Суть умов полягає в тому, що мета може виконуватися або виконуватися, в залежності від того, чи встановлено значення якої-небудь властивості чи ні.

В даному прикладі мета build.full буде виконуватися тільки, якщо встановлено значення совйства full, в іншому ж випадку буде виконуватися build.simple. Абсолютно неважливо яке значення встановлено в властивість full, це може бути і true, і false, і будь-яка інша рядок, навіть порожня.

Приклад складання проекту за допомогою Apache Ant

Тепер розберемо відносно простий процес складання маленького проекту.

Для впевненості в тому, що сценарій збірки, наведений нижче, збирає дійсно робочий та самодостатній проект, я написав дуже маленьку програму, код якої я наводити не буду, тому що це в даному випадку не потрібно. Програма складається з трьох файлів java: ValuesGenerator.java, Statistic.java і Main.java. У ValuesGenerator.java описаний метод для генерації випадкового набору даних, в Statistic.java методи для знаходження мінімального, середнього і максимального значень масиву, а в Main.java знаходиться метод main (), в якому відбувається виклик методів класів ValuesGenerator і Statistic. Клас Statistic використовує для розрахунку значень бібліотеку Apache Commons Math, а вся робота програми пишеться в лог-файл за допомогою бібліотеки log4j. Також в каталозі з проектом є невеликий файл readme.txt з описом програми.

Завдання полягає в тому, щоб мати можливість автоматично створювати zip-файл з дистрибутивом програми.

Цілі make.build.dirs і make.dist.dirs вам повинні бути вже гранично зрозумілі. Вони не роблять нічого розумного, а тільки створюють каталоги. Єдине, що можна відзначити, в даному випадку зовсім не обов'язково було прописувати в них по два завдання mkdir, а можна було б обійтися однією, тому що mkdir може створювати цілий ланцюжок каталогів відразу.

Мета compile містить завдання, необхідні для компіляції вихідного коду. Перед викликом компілятора відбувається створення елемента path, в якому будуть міститися шляху до файлів бібліотек, використовуваних в нашій програмі. Файли визначаються за допомогою елемента fileset, крім якого в path могли б міститися і інші елементи колекції ресурсів, наприклад, dirset, що містить шляху до каталогів зі скомпільованими java-класами або інший елемент path. Оскільки створений елемент path вдає із себе необхідний для компіляції CLASSPATH, йому встановлюється відповідний атрибут id, для того щоб пізніше можна було на це path послатися. Після створення path, його текстове представлення записується в властивість за допомогою елемента pathconvert і виводиться на екран. Мета compile вказана в елементі project, як мета за замовчуванням, тому якщо ant'у не вказувати мету для виконання, він буде виконувати саме її. Дана мета залежить від виконання тільки однієї мети make.build.dirs.

Мета javadoc здійснює генерацію документації javadoc. Її докладно я описувати не буду, просто привів для демонстрації.

Мета clean також проста до неподобства і просто робить видалення результатів попередніх збірок.