Если вы пользовались системой сборки Gradle, то, вероятно, уже применяли и извлекали пользу из DSL-возможностей языка Groovy. В этой статье давайте рассмотрим такой пример.
Возьмем следующий фрагмент DSL из конфигурации Gradle.
plugins {
id 'java'
}
В разделе plugins
настраиваются плагины Gradle, используемые в вашей сборке, и упоминаются все плагины, которые вы хотите применить. Давайте разберемся, что происходит под капотом, чтобы добиться работоспособности, с помощью не очень сложного примера.
def plugins (def pluginConfig) {
println "Plugins called"
}
//--------------- DSL
plugins {
id 'java'
}
Когда мы запускаем приведенный выше код, то видим, что в консоли выводится "Plugins called" (вызываемые плагины). Мы понимаем, что plugins
— это метод. Посмотрите на альтернативный способ вызова метода plugins
.
plugins({
id 'java'
})
Теперь понятно, что содержимое внутри '{}' передается в качестве аргумента методу plugins
. Такие блоки кода в Groovy называются closures
. Если последний аргумент вашего метода (он может быть и единственным) является замыканием (closure), Groovy позволяет писать их вне круглых скобок. Таким образом, приведенный выше код можно записать следующим способом.
plugins() {
id 'java'
}
Кроме того, Groovy позволяет опускать круглые скобки, если метод имеет хотя бы один аргумент, что и произошло в данном случае. Таким образом, мы получаем оригинальный код, используемый в нашем DSL.
plugins {
id 'java'
}
Поскольку мы хотим добавить плагины в проект, давайте создадим структуру для хранения информации о нем.
class Project {
List<Plugin> plugins = []
}
import groovy.transform.ToString
@ToString(includePackage = false)
class Plugin {
String id
}
Теперь нам осталось создать экземпляр класса Plugin
и добавить его в plugins Project
. Как вы уже догадались, id 'java'
означает, что мы вызываем метод идентификации с 'java' в качестве аргумента. Давайте добавим этот метод в класс Project
, поскольку он кажется подходящим местом для его размещения.
class Project {
List<Plugin> plugins = []
def id(String pluginId) {
println "Adding plugin $pluginId"
plugins << new Plugin(id: pluginId)
}
}
Давайте обновим наш метод плагинов, чтобы вызвать замыкание на инстансе project
.
def plugins(def pluginConfig) {
Project project = new Project()
println "Plugins called"
project.with pluginConfig
}
В консоли должно появиться сообщение "Adding plugin java" (Добавление плагина java). Здесь мы используем метод with, чтобы обеспечить замыкание, которое мы получили в качестве аргумента, для объекта 'project' (а не для инстанса этого скрипта).
Давайте добавим еще один плагин в наш DSL и убедимся, что он работает так, как ожидалось. Заодно отобразим все плагины из проекта.
def plugins(def pluginConfig) {
Project project = new Project()
println "Plugins called"
project.with pluginConfig
println project.plugins
}
//---------------
plugins{
id 'java'
id 'groovy'
}
На консоли вы должны увидеть следующее:
Plugins called
Adding plugin java
Adding plugin groovy
[Plugin(java), Plugin(groovy)]
Конечно, полноценный DSL будет более сложным. Здесь я попытался передать суть идеи с помощью максимально простых примеров.
В заключение приглашаем всех желающих на открытое занятие «Shared Libraries в Jenkins», которое пройдет завтра в 20:00. На этом уроке посмотрим, как расширять пайплайны в Jenkins с помощью внешних библиотек и научимся их писать. Урок будет особенно полезен DevOps-инженерам и Java-разработчикам, которые хотят научиться создавать и настраивать сборки Java Backend проектов.
UbuRus
Тем временем gradle перешел на Kotlin DSL по-умолчанию, так что закапывайте стюардессу)