О моей пассионарной ненависти к этой штуке можно написать не одну статью, но сегодня я хочу поговорить об одной очень хорошей фиче Мавена — об архетипах. Что это такое можно прочитать в официальной документации, в каждом из туторилов по Мавену на Хабре(1, 2, 3), да и вообще, вы наверняка знаете и сами.
Так вот, архетипы — это круто, и было бы здорово, если бы 1) во многих проектах со стандартной структурой они были. 2) можно было бы их прикрутить к тем, у которых их нет.
Примерно так думал Питер Ледбрук, когда смотрел на полное отсутствие архетапов в Ratpack. Тогда и родился проект Lazybones — инструмент генерации проектов.
В этой статье я расскажу вам как 1) Пользоваться Lazybones для генерации проектов, для которых уже созданы шаблоны. 2) Создавать новые шаблоны для любых проектов.
Использование существующих шаблонов Lazybones
Tут все будет предельно коротко:
- Устанавливаем Lazybones с помощью GVM или скачиваем дистрибутив с Bintray
- Смотрим какие шаблоны существуют с помощью команды
lazybones list(или изучаем репозиторий) - Изучаем информацию о выбраном шаблоне с помощью команды
lazybones info <имя шаблона>(или читаем readme в packag-e шаблона на Бинтрее) - Создаем проект командой
lazybones create <имя шаблона> <версия шаблона> <имя директории в которой создавать>
Всё, спасибо за внимание, все свободны. Хотя нет, сейчас будем делать как раз интересное.
Создание своего шаблона проекта
Поскольку вы все, скорее всего, знакомы с мавеновским архетипом #361 (maven-archetype-quickstart), мы сделаем что-то похожее (воссоздав все фичи, мы опустим некоторые повторы).
Мало того, что вы сможете сравнить количество скаченного интернета для создания обоих проектов, вы еще и сможете сравнить сложность создания самого шаблона, ибо процесс создания архетайпа Мавена прекрасно описан вот тут.
Итак, поехали.
Чего мы хотим добиться:
- Создать базовый pom.xml с выбраными через интерактивную командную строку
groupId,artifactIdи версией - Создать директории src/main/java, src/main/resources (тоже самое для тестов, но мы не будем, для простоты примера)
- Создать класс для примера, прописать в нем выбранный через интерактивную командную строку
packageи положить его в походящую подpackageдиректорию (тоже самое для теста, но мы не будем, для простоты примера) - В классе сгенерить
main, который будет при запуске фазы теста печатать сообщение, выбранное через интерактивную командную строку - Собрать шаблон
- Создать проект по нашему шаблону
- Запустить
mvn test - Профит
- Для сборки шаблона нам понадобится скрипт Gradle и директория с шаблонами. Поскольку нам лень, мы запустим lazybones:
>lazybones create lazybones-project lzb-templates
В результате у нас есть следующее:
│ build.gradle //скрипт сборки шалбонов
│ gradlew //файл запуска скрипта для никсов
│ gradlew.bat //файл запуска скрипта для винды
│ README.md //файл описывающий этот проект
│
├───gradle //вспомогательная директория для скрипта
│
└───templates //пустая директория для наших шаблонов
- Заходим в директорию
templates, создаем в ней под-директорию нашего шаблона, и начинаем ваять. Создаем файл версии. Он называетсяVERSIONи содержит только версию, например 0.1
>mkdir maven-simple
>cd maven simple
>echo 0.1 > VERSION
- Кроме того, нужно создать
readme.md, который будет показан после создания проекта. - Создаем директории
src/main/java,src/main/resources. Вjavaиresourcesиз них кладем по пустому файлу.retain
├───maven-simple
│ │ README.md
│ │ VERSION
│ │
│ └───src
│ └───main
│ ├───java
│ │ .retain
│ │
│ └───resources
│ .retain
- Теперь займемся шаблонами. Начнем с pom.xml:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>${pkg}.App</mainClass>
<arguments>
<argument>${message}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>ААААА!!!!!!!
Так, взяли себя в руки, смотрим. Обратите внимание на всякие${...}. Это то, что мы будем менять на значения, которые нам задаст пользователь во время запускаcreate. По сути, это просто маркеры Groovy Templates. Если вы знакомы с Velocity, Freemarker или любым другим обработчиком шаблонов, вам всё будет знакомо. Но об этом позже.
Адовый ад в<build></build>— это всего лишь запускmain-а классаApp. Обратите внимание, что нам пока нам неизвестныpackageэтого класса и параметр, который мы передаем вmain. - Теперь смотрим на файл
App.java:package ${pkg};
public class App {
public static void main(String[] args) {
System.out.println(args[0]);
}
}
Тут у нас всего одна переменная — опять-же,package. Заодно мы видим, что main печатает аргумент. Значит, что во время запуска мавена, в фазе теста, мы ожидаем увидеть сообщение, которое пользователь выберет, опять-же, во времяcreate.
Итак, теперь мы имеем все директории и шаблоны:
│ App.java
│ lazybones.groovy
│ pom.xml
│ README.md
│ VERSION
│
└───src
└───main
├───java
│ .retain
│
└───resources
.retain
- А вот теперь начинается самое интересное. Нам осталось написать пост-процессор, который будет бежать после распаковывания директорий. Задачи: 1) Узнать всё, что нужно у пользователя, 2) перенести java файл в директорию, соответствующую package, 3) обработать шаблоны.
Поможет нам в этом, конечно, элегантный Груви скрипт:import static org.apache.commons.io.FileUtils.moveFileToDirectory
Map<String,String> props = [:]
//метод ask принимает 2 параметра - сообщение, и значение по умолчанию.
//он показывает сообщение и ждет ввода. Ввод (или значение по умолчанию, если ввод пустой) возвращается.
props.groupId = ask('Выберите groupId [org.example]: ', 'org.example')
props.artifactId = ask('Выберите artifactId [maven-simple]: ', 'maven-simple')
props.version = ask('Выберите версию [1.0-SNAPSHOT]: ', '1.0-SNAPSHOT')
props.pkg = ask("Выберите package для класса [$props.groupId]:", props.groupId)
props.message = ask('Чего печатать в тесте? ', 'Привет, лентяй!')
//метод processTemplates обрабатывает шаблоны, заменяя меаркеры значениями из мапы.
processTemplates 'pom.xml', props
//заменяем точки на слэши
String packageDir = props.pkg.replaceAll(/\./, '/')
//переносим исходник в нужную директорию
moveFileToDirectory(new File(targetDir, 'App.java'), new File(targetDir, "src/main/java/$packageDir"), true)
//обрабатываем шаблон
processTemplates 'src/main/java/**/App.java', props
Надеюсь, комментарии достаточно понятно объясняют, что происходит. Единственное, наверное, что нужно добавить, это то, что методыask()иprocessTemplates()и полеtargetDirпопадают в скрипт из классаuk.co.cacoethes.lazybones.LazybonesScript, который является кастомным супер-классом этого скрипта. - Пора собирать. У Lazybones есть свой плагин для Грейдла, который уже сконфигурирован в скрипте сборки, который мы сгенерировали в пункте 1. Этот плагин определяет task rules для сборки, установки в локальном кэше и деплоймента шаблонов на Бинтрей. Поскольку шаблон у нас не серъезный, на Бинтрей мы его класть не будем, а вот установить в кэш, чтобы попробовать запустить — обязательно. Запускаем сборку:
>gradlew installTemplateMavenSimple:packageTemplateMavenSimple:installTemplateMavenSimpleBUILD SUCCESSFUL
- Тестируем! Создаем новую директорию и в ней создаем проект из шаблона (как мы уже видели):
>lazybones create maven-simple 0.1 maven-simpleCreating project from template maven-simple 0.1 in 'maven-simple'Выберите groupId [org.example]: com.demoВыберите artifactId [maven-simple]:Выберите версию [1.0-SNAPSHOT]: 0.1Выберите package для класса [org.example]:org.simpleЧего печатать в тесте? Привет, Хабр!Шаблон а-ля архетайп---------------------------------Ты создал Мавеновский проект. Может хватит? Грейлд ждет тебя.Project created in maven-simple!Сообщение в конце, приходит, конечно из
readme.md. Обратите внимание, я не указалartifactId, ожидаюmaven-simpleпо умолчанию.
Заходим в директорию maven-simple, и любуемся:
│ pom.xml
│ README.md
│
└───src
└───main
├───java
│ └───org
│ └───simple
│ App.java
│
└───resources
Открываем pom.xml:<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>maven-simple</artifactId>
<version>0.1</version>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.simple.App</mainClass>
<arguments>
<argument>Привет, Хабр!</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Всё как надо. Открываем App.java:package org.simple;
public class App {
public static void main(String[] args) {
System.out.println(args[0]);
}
}
Тоже порядок. Запускаем Мавен:
>mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven-simple 0.1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-simple ---
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ maven-simple ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-simple ---
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ maven-simple ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-simple ---
[INFO] No tests to run.
[INFO]
[INFO] >>> exec-maven-plugin:1.2.1:java (default) @ maven-simple >>>
[INFO]
[INFO] <<< exec-maven-plugin:1.2.1:java (default) @ maven-simple <<<
[INFO]
[INFO] --- exec-maven-plugin:1.2.1:java (default) @ maven-simple ---
Привет, Хабр!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.768s
[INFO] Finished at: Fri Apr 04 02:54:57 IDT 2014
[INFO] Final Memory: 7M/304M
[INFO] ------------------------------------------------------------------------
Вот и всё. Я надеюсь, вы прониклись простотой и изяществом как создания проектов из шаблонов так и созданием самих шаблонов в Lazybones. Мне кажется, за эти простоту и изящество во многом надо благодaрить Груви.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий