Глава 9. Непрерывная сборка.

Непрерывная сборка - инкубационная функция. Это значит, что она не законченная и не соответствует производственному качеству Gradle. Еще это означает, что эта глава находится в процессе разработки.

Обычно, вы просите Gradle выполнить одиночную сборку посредством определения задач, которые он должен выполнить. Gradle вычислит фактический набор задач, которые нужно выполнить, чтобы удовлетворить запрос, выполнит их и затем прекратит работу до следующего запроса. Непрерывная сборка отличается тем, что Gradle будет продолжать выполнять первоначальный запрос сборки (пока ему не скажут остановиться), выполняя сборку, когда обнаруживает, что результаты прошлой сборки устарели. Например, если ваша сборка компилирует исходные коды Java в класс-файлы, непрерывная сборка автоматически инициирует компиляцию, когда файлы исходных кодов изменятся. Это функция полезна во многих случаях.

9.1. Как я могу запустить и остановить непрерывную сборку?

Непрерывная сборка может быть запущена передачей переключателя --continuous или -t Gradle, вместе со списком задач, переключателями и аргументами, которые определяют необходимую работу. Например, gradle build --continuous. У этой команды тот же эффект, что и у gradle build, но вместо выхода из Gradle после выполнения, она будет ждать изменений во входных данных. Когда будет какое-либо изменение, команда gradle build будет выполнена и процесс повторится.

Если Gradle прикреплен к интерактивному входному источнику, такому как терминал, выйти из непрерывной сборки можно с помощью комбинации клавиш CTRL-D (на Microsoft Windows после этого необходимо нажать ENTER ИЛИ RETURN). Если не подключен к такому источнику (например, запущен как часть скрипта), то процесс сборки необходимо завершить (используя команду kill или что-то наподобие). Если сборка запущена с помощью инструментального API, то ее можно прекратить с использованием механизма отмены инструментального API.

9.2. Что послужит причиной запуска последующей сборки?

В настоящее время, только изменения во входных даннных к задачам принимаются во внимание. Gradle начнет отслеживать изменения сразу перез запуском задачи на выполнение. Никакие другие изменения не послужат причиной сборки. Например, изменения в сборочных скриптах и логике сборки не начнут сборку. Также, как и изменения в файлах, которые считываются во время настройки сборки, а не во время выполнения. Для того, чтобы подхватить такие изменения, необходимо перезапустить непрерывную сборку вручную.

Файловые входы задач

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

Рассмотрим обычную сборку с использованием плагина Java и расположение в файловой системе по соглашению. На диаграмме ниже, показан граф для команды gradle build:

Рисунок 9.1. Граф задачи Java плагина
Рисунок 9.1. Граф задачи Java плагина

Следующие ключевые задачи с графа используют файлы и соответствующих папкок как входы:

compileJava

    src/main/java
	  

processResources

    src/main/resources
	  

compileTestJava

    src/test/java
	  

processTestResources

    src/test/resources
	  

Предполагая, что начальная сборка окончилась успешно (т.е. задача build и все еще зависимости завершились без ошибок), изменения в файлах в, а также добавление/удаление файлов из, папках перечисленных выше, инициирует новую сборку. Если изменения сделаны в исходном коду файла Java в src/main/java, то сборка будет запущена и все задачи будут поставлены в очередь. Поддержка последовательной сборки Gradle гарантирует, что будут выполнены только те задачи, на которые влияют изменения.

Если изменения в главной папке с исходными кодами Java стали причиной ошибки компиляции, то последующие изменения в исходных кодах тестов в src/test/java не инициируют сборку. Так как тестовые исходники зависят от основных, их нет смысла собирать до того момента, пока не будут внесены изменения в основные, потенциально исправляющие ошибку компиляции. После каждой сборки, только у задач, которые в действительности были выполнены, отслеживаются изменения входных данных.

Непрерывная сборка никак не связана с компиляцией. Она работает для любых типов задач. Например, задача processResources копирует и обрабатывает файлы из папки src/main/resources для включения их в собираемый jar-файл. Таким образом, изменение в любом файле в этой папки, запустит сборку.

9.3. Ограничения и особенности.

Есть несколько проблем, о которых стоит знать, в современной реализации непрерывной сборки. Весьма вероятно, что они будут решены в будущих выпусках Gradle.

9.3.1. Зацикленные сборки.

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

Если ваша сборка попадает в цикл, похожий на описанный, вы можете отследить виновника по списку файлов, которые Gradle вывел как изменившиеся. После определения файла (или файлов), который изменяется во время каждой сборки, вам необходимо посмотреть на задачу, которая принимает на вход эти файлы. В некоторых случаях, задачу можно найти без проблем (например, файлы Java компилируются задачей compileJava). В других случаях, вы можете использовать логгирование с помощью --info, чтобы найти задачу, которая постоянно устаревает из-за таких файлов.

9.3.2. Ограничения при использовании Java 9.

Вследствие классовых ограничений в Java 9, Gradle не может установить некоторые опции, присущие операционной системе. Это значит, что:

  • На Mac OS X Gradle подсчитывает изменения каждые 10 секунд вместо 2-х.
  • На Windows, Gradle должен использовать отдельные потоки наблюдения для каждого файла, что может быть причиной отказа непрерывной сборки на очень больших проектах.

9.3.3. Производительность и стабильность.

В JDK средства наблюдения полагаются на неэффективный системный файловый подсчет на Mac OS X (смотрите: JDK-7133447). Это может значительно задержать уведомления об изменении на больших проектах со множеством файлов исходных кодов.

К тому же, в механизме наблюдения может появится взаимная блокировка при большой нагрузке на Mac OS X(смотрите: JDK-8079620). Это проявляется в том, что Gradle не видит изменения файлов. Если у вас есть подозрение, что случилась такая ситуация, завершите непрерывную сборку и запустите ее снова.

На Linux реализация сервиса наблюдения за файлами в OpenJDK, иногда может пропускать файловые системные события (смотрите: JDK-8145981).

9.3.4. Изменения в символических ссылках.

  • Создание или удаление символической ссылки на файлы стартует сборку.
  • Изменение файла, на который указывает символическая ссылка, не влечет за собой пересборку.
  • Создание или удаление символической ссылки на папку не запускает пересборку.
  • Удаление папки, на которую указывает символическая ссылка, не запускает пересборку.

9.3.5. Изменение логики сборки не учитывается.

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