Глава 27. Плагины Gradle.

Ядро Gradle намеренно предоставляет очень мало для автоматизации в реальном мире. Все полезные функции, такие как возможность компилировать Java-код, добавляются плагинами. Они добавляют новые задачи (например, JavaCompile), объекты предметной области (SourceSet), соглашения (например, исходные коды Java размещаются в src/main/java), наряду с этим расширяя объекты ядра или объекты из других плагинов.

В этой главе мы обсудим как пользоваться плагинами, а также терминологию и концепты окружающие их.

27.1. Что делают плагины.

Применение плагина к проекту позволяет плагину расширить возможности проекта. Он может делать такие вещи:

  • Расширять модель Gradle (например, добавлять новые элементы DSL, которые могут быть настроены).
  • Настраивать проект в соотвествии с соглашениями (например, добавлять новые задачи или настраивать значимые умолчания).
  • Применять специфичную конфигурацию (например, добавлять организационные хранилища или вынуждать соблюдать стандарты).

Применяя плагин вместо добавления логики к сборочному скрипту проекта, мы можем получить много преимуществ. Применение плагинов:

  • Способствует повторному использованию и снижению накладных расходов поддержания похожей логики между несколькими проектами.
  • Дает более высокую степень модуляризации, расширяя понятность и организацию.
  • Инкапсулирует императивную логику и позволяет сборочным скриптам быть декларативными настолько, насколько это возможно.

27.2. Типы плагинов.

Есть два общих типа плагинов в Gradle, скриптовые плагины и двоичные. Скриптовые плагины - дополнительные сборочные скрипты, которые еще сильнее настраивают сборку и обычно реализуют декларативные подход для манипуляции сборкой. Обычно они используются в рамках сборки, хотя их можно экспортировать и обращаться к ним из удаленного местоположения. Двоичные плагины - классы, которые реализуют интерфейс Plugin и принимают программный подход для манипуляции сборкой. Двоичные плагины могут размещаться внутри сборочного скрипта, в рамках иерархии проекта или во внешнем jar-файле плагина.

Плагин чаще всего начинают писать как скриптовый (потому что их легко писать) и затем, когда код становится более значимым, он переносится в двоичный, который можно легко протестировать и совместно использовать в нескольких проектах или огранизациях.

27.3. Использование плагинов.

Чтобы использовать сборочную логику, заключенную в плагине, Gradle необходимо выполнить два шага. Первый, необходимо разрешить плагин и затем применить его к цели, обычно к Project.

Разрешение плагина означает нахождение корректной версии jar-файла, который содержит данный плагин и добавление его в путь к классам скрипта. Как только плагин разрешен, его API можно использовать в сборочном скрипте. Скриптовые плагины - саморазрешающиеся, так как они разрешаются из специфичного файлового пути или URL-адреса, предоставленного, при его применении. Двоичные плагины ядра предоставляющиеся как часть дистрибутива Gradle - разрешаются автоматически.

Применение плагина в действительности означает выполнение Plugin.apply(T) на Project, который вы хотите расширить с помощью плагина. Применение плагина идемпотентно. То есть, вы можете безопасно применять любой плагин много раз без побочных эффектов.

Самый распространенный вариант использования плагина - его разрешение и применение к текущему проекту. Так как это самый распространенный случай, авторам сборки рекомендуется использовать DSL плагинов и для разрешения, и для применения в один шаг. Технически эта возможность инкубационная, но она работает хорошо и должна использоваться большинством пользователей.

27.4. Скриптовые плагины.

Пример 27.1. Применение скриптового плагина

build.gradle

apply from: 'other.gradle'
	  

Скриптовые плагины автоматически разрешаются и могут быть применены из скрипта в локальной файловой системе или удаленного местоположения. Местоположения в файловой системе относительны папки проекта, тогда как удаленные местоположения скриптов указываются посредством HTTP URL-адреса. Несколько скриптовых плагинов (в любой форме) могут быть применены к данной цели.

27.5. Двоичные плагины.

Иъ вы применяете по идентификатору плагина, который является уникальным глобальным идентификатором или именем, для плагина. Плагины ядра Gradle особенны в том, что они предоставляют короткие имена, такие как 'java' для JavaPlugin. Все остальные двоичные плагины должны использовать полностью определенные идентификаторы (например, com.github.foo.bar), хотя некоторые устаревшие плагины все еще могут использовать короткую, неполную форму. Где вы разместите идентификатор зависит используете ли вы DSL плагинов или блок сборочного скрипта.

27.5.1. Местоположения двоичных плагинов.

Плагин - всего навсего класс, который реализует интерфейс Plugin. Gradle предоставляет основные плагины (например, JavaPlugin) как часть дистрибутива и это означает, что они разрешаются автоматически. Однако, неосновные двоичные плагины должны быть разрешены до их применения. Вы можете этого достичь несколькими способами:

  • Подключить плагин из портала плагинов или пользовательского хранилища, используя DSL плагинов (смотрите Секцию 27.5.2 Применение плагинов с помощью DSL).
  • Подключить плагин из внешнего jar-файла, заданного в качестве зависимости сборочного скрипта (смотрите секцию под названием Применение плагинов с помощью блока сборочного скрипта).
  • Задать плагин как исходный файл, находящийся в папке buildSrc в проекте (смотрите Секцию 43.4 Исходники сборки в проекте buildSrc).
  • Задать плагин как встроенный класс внутри сборочного скрипта.

Чтобы узнать больше о создании собственных плагинов, смотрите Главу 41 Написание пользовательских плагинов.

27.5.2. Применение плагинов с помощью DSL.

Сейчас данная функция инкубационная. Помните, что она может измениться в последних версиях Gradle.

Новый DSL плагинов предоставляет лаконичный и удобный способ объявления зависимостей от плагинов. Он работает с порталом плагинов Gradle для предоставления легкого доступа к основным и плагинам сообщества. Блок DSL плагинов настраивает экзмепляр PluginDependenciesSpec.

Чтобы применить основной плагин, можно использовать краткое имя:

Пример 27.2. Применение основного плагина

build.gradle

plugins {
    id 'java'
}
	  

Чтобы применить плагин сообщества с портала, должен использоваться полностью определенный идентификатор:

Пример 27.3. Применение плагина сообщества

build.gradle

plugins {
    id "com.jfrog.bintray" version "0.4.1"
}
	  

Чтобы узнать больше об использовании DSL плагинов, смотрите PluginDependenciesSpec.

Ограничения DSL плагинов

Добавление плагинов таким способом - больше чем просто удобный синтакс. Этот DSL обрабатывается таким образом, который позволяет Gradle вычислеть используемые плагины очень рано и очень быстро. Благодаря этому есть возможность делать такие интеллектуальные вещи:

  • Оптимизировать загрузку и повторное использование классов плагина.
  • Позволять различным плагинам использовать различные версии зависимостей.
  • Предоставлять редакторам детальную информацию о потенциальных свойствах и значениях в сборочном скрипте для помощи в редактировании.

Для этого требуется, чтобы плагины были определены таким способом, чтобы Gradle мог легко и быстро их извлечь, до выполнения оставшегося сборочного скрипта. Также требуется, чтобы определение плагинов для использования были чем-то статическим.

Есть несколько ключевых различий между новым механизмом плагинов и 'традиционным' механизмом метода apply(). Также есть несколько ограничений, некоторые из которых временнные, так как механизм все еще разрабатывается, а другие присущи новому подходу.

Ограниченный синтакс

Новый блок plugins {} не поддерживает произвольный код Groovy. Это ограничение сделано для идемпотентности (выдачи одинаковых результатов каждый раз) и отсутствия побочных эффектов (безопасно для выполнения Gradle в любое время).

Форма:

plugins {
    id «идентификатор плагина» version «версия плагина» [apply «false»]
}
	  

Где 'версия плагина' и 'идентификатор плагина' должны быть константой, литералом, строками и инструкция apply с булиновских значением может быть использована для отключения поведения по умолчанию, когда плагин применяет немедленно (например, вы хотите применить его только в подпроектах (subprojects)). Все остальные инструкции запрещены; их наличие повлечет за собой ошибку компиляции.

Блок plugins {} должен быть верхнеуровневой инструкцией в сборочном скрипте. Он не может быть вложен в другую конструкцию (например, в инструкцию if или цикл for).

Может быть использован только в сборочных скриптах

На текущий момент, блок plugins {} может быть использован только в сборочном скрипте проекта. Он не может быть использован в скриптовых плагинах, файле settings.gradle или инициализационных скриптах.

Будущие версии Gradle уберит это ограничение.

Если ограничения нового синтакса слишком строгие, рекомендуемый подход - применять плагины с помощью блока buildscript {}.

Применение плагинов к подпроектам

Если у вас многопроектная сборка, вероятно вам понадобится применять плагины к некоторым или всем подпроектам, но не к корневому или master. По умолчанию блок plugins {} немедленно разрешает и применяет плагины. Но вы можете использовать синтакс apply false, чтобы сказать Gradle не применять плагин в текущем проекте и затем использовать apply plugin: «версия плагина» в блоке subprojects:

Пример 27.4. Применение плагинов только к определенным подпроектам

settings.gradle

include 'helloA'
include 'helloB'
include 'goodbyeC'
	  

build.gradle

plugins {
  id "org.gradle.sample.hello" version "1.0.0" apply false
  id "org.gradle.sample.goodbye" version "1.0.0" apply false
}

subprojects { subproject ->
    if (subproject.name.startsWith("hello")) {
        apply plugin: 'org.gradle.sample.hello'
    }
    if (subproject.name.startsWith("goodbye")) {
        apply plugin: 'org.gradle.sample.goodbye'
    }
}
	  

Если вы затем запустите gradle hello, вы увидите, что только к подпроектам helloA и helloB был применен плагин hello.

gradle/subprojects/docs/src/samples/plugins/multiproject $> gradle hello
Parallel execution is an incubating feature.
:helloA:hello
:helloB:hello
Hello!
Hello!

BUILD SUCCESSFUL
	  

Управление плагинами

На текущий момент DSL pluginManagement {} инкубационный. Пожалуйста, знайте, что в последних версиях Gradle DSL и другая конфигурация может измениться.

Пользовательские хранилища плагинов

По умолчанию, DSL plugins {} разрешает плагины из открытого Портала плагинов Gradle. Многие авторы сборок также хотели бы разрешать плагины из закрытых хранилищ Maven или Ivy, потому что плагины содержат проприетарные детали реализации или просто, чтобы иметь больше контроля над тем, какие плагины доступны в их сборках.

Чтобы указать пользовательские хранилища плагинов, добавьте блок repositories {} внутри pluginManagement {} в файл settings.gradle:

Пример 27.5. Использование плагинов из пользовательских хранилищ

settings.gradle

pluginManagement {
  repositories {
      maven {
        url 'maven-repo'
      }
      gradlePluginPortal()
      ivy {
        url 'ivy-repo'
      }
  }
}
	  

Этот код скажет Gradle сначала искать в хранилище Maven в maven-repo при разрешении плагинов и затем проверить портал плагинов Gradle, если они не найдены в хранилище Maven. Если вы не хотите, чтобы плагины искались в портале плагинов Gradle, пропустите строчку gradlePluginPortal(). В конце будет проверено хранилище Ivy в ivy-repo.

Правила разрешения плагинов

Правила разрешения плагинов позволяют вам изменять запросы плагинов сделанные в блоках plugins {}, например, изменяя запрошенную версию или явно указывая координаты артефакта реализации.

Чтобы добавить правила разрешения, используйте resolutionStrategy {} внутри блока pluginManagement {}:

Пример 27.6. Стратегия разрешения плагинов

settings.gradle

pluginManagement {
  resolutionStrategy {
      eachPlugin {
          if (requested.id.namespace == 'org.gradle.sample') {
              useModule('org.gradle.sample:sample-plugins:1.0.0')
          }
      }
  }
  repositories {
      maven {
        url 'maven-repo'
      }
      gradlePluginPortal()
      ivy {
        url 'ivy-repo'
      }
  }
}
	  

Этот код скажет Gradle использовать указанный артефакт реализации плагина вместо встроенного по умолчанию отображения из идентификатора плагина в координаты Maven/Ivy.

Блок pluginManagement {} может находиться только в файле settings.gradle и должен быть первым блоком. Пользовательские хранилища плагинов Maven и Ivy должны содержать артефакты маркеров плагинов в дополнение к артефактам, которые в действительности реализуют плагин. Чтобы узнать больше о публикации плагинов в пользовательские хранилища, читайте Главу 42 Плагин Java Gradle для разработки плагинов.

Здесь PluginManagementSpec смотрите полную документацию об использовании блока pluginManagement {}.

Артефакты маркеров плагинов

Так как блок DSL plugins {} позволяет объявлять плагины только по их глобальным уникальным свойствам id и version, Gradle требуется способ поиска координат артефакта, реализующего плагин. Чтобы найти их, Gradle будет искать артефакт маркера плагина с координатами plugin.id:plugin.id.gradle.plugin:plugin.version. Этому маркеру требуется иметь зависимость от действительной реализации плагина. Публикация этих маркеров автоматизирована с помощью java-gradle-plugin.

Например, следующий законченный пример из проекта sample-plugins показывает как опубликовать плагины org.gradle.sample.hello и org.gradle.sample.goodbye в репозитории Ivy и Maven, используя комбинацию плагинов - java-gradle-plugin, maven-publish и ivy-publish.

Пример 27.7. Законченный пример публикации плагина

build.gradle

plugins {
  id 'java-gradle-plugin'
  id 'maven-publish'
  id 'ivy-publish'
}

group 'org.gradle.sample'
version '1.0.0'

gradlePlugin {
  plugins {
    hello {
      id = "org.gradle.sample.hello"
      implementationClass = "org.gradle.sample.hello.HelloPlugin"
    }
    goodbye {
      id = "org.gradle.sample.goodbye"
      implementationClass = "org.gradle.sample.goodbye.GoodbyePlugin"
    }
  }
}

publishing {
  repositories {
    maven {
      url "../consuming/maven-repo"
    }
    ivy {
      url "../consuming/ivy-repo"
    }
  }
}
	  

Запуск gradle publish в папке примера повлечет за собой следующую разметку хранилища:

Разметка хранилища

27.5.3. Устаревшее применение плагинов.

С введением нового DSL плагинов, у пользователей не должно остаться резона использовать устаревший метод применения плагинов. Он приведен здесь для случая, когда автор сборки не может использовать новый метод вследствие существующих на данный момент ограничений его работы.

Применение двоичных плагинов

Пример 27.8. Применение двоичного плагина

build.gradle

apply plugin: 'java'
	  

Плагины могут применяться с использованием их идентификатора. В случае выше, мы используем краткое имя 'java' для применения JavaPlugin.

Вместо использования идентификатора плагина, их можно применять просто указывая класс:

Пример 27.9. Применение двоичного плагина по типу

build.gradle

apply plugin: JavaPlugin
	  

Символ JavaPlugin указывает на JavaPlugin. Это класс не обязательно импортировать, так как пакет org.gradle.api.plugins автоматически импортируется во всех сборочных скриптах (смотрите Секцию 18.8 Импорты по умолчанию). Более того, нет необходимости добавлять .class для указания литера класса в Groovy, как это делается в Java.

Применение плагинов с использованием блока buildscript

Двоичные плагины, которые опубликованы как внешние jar-файлы, могут быть добавлены в проект, присовокуплением плагина к пути к классам сборочного скрипта и затем применением. Внешние jar-файлы могут быть добавлены в путь к классам сборочного скрипта с использованием блока buildscript {}, как описано в Секции 43.6 Внешние зависимости для сборочного скрипта.

Пример 27.10. Применение плагина с помощью блока buildscript

build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
    }
}

apply plugin: "com.jfrog.bintray"
	  

27.6. Нахождение плагинов сообщества.

У Gradle есть живое сообщество разработчиков, которые создают плагины для широкого спектра функций. Портал плагинов Gradle предоставляет интерфейс для поиска и исследования плагинов сообщества.

27.7. Больше о плагинах.

Цель этой главы - введение в плагины и Gradle и их роль. Чтобы узнать больше о внутренней работе плагинов, смотрите Главу 41.