Этот провокационный вопрос послужил мотивацией для окончательного изучения Gradle. Я до сих пор не использовал его, поэтому могу предлагать анализ, отмеченный при просмотре документов, а не личные истории.
Мой первый вопрос заключался в том, почему граф зависимостей задач Gradle гарантированно является ациклическим. Я не нашел ответа на этот вопрос, но легко построить противоположный случай, поэтому я предполагаю, что обнаружение цикла является проверкой, которая запускается при построении графика, и сборка завершается неудачно до выполнения первой задачи, если существуют незаконные циклические зависимости. Без предварительного построения графика это условие сбоя может не быть обнаружено, пока сборка не будет почти завершена. Кроме того, подпрограмма обнаружения должна была бы выполняться после выполнения каждой задачи, что было бы очень неэффективно (поскольку график был построен постепенно и доступен глобально, поиск в глубину потребуется только для поиска начальной точки, а затем оценки цикла потребовали бы минимальной работы, но общая работа все равно была бы больше, чем одноразовое сокращение всего набора отношений с самого начала). Я бы назвал раннее обнаружение главным преимуществом.
Зависимость задачи может быть ленивой (см .: 4.3 Зависимости задачи и связанный пример в 13.14). Зависимости отложенных задач не могут быть правильно оценены, пока не будет построен весь график. То же самое верно для транзитивного (не заданного) разрешения зависимостей, которое может вызвать неисчислимые проблемы и потребовать повторных перекомпиляций, когда обнаруживаются и разрешаются дополнительные зависимости (также требующие повторных запросов к хранилищу). Функция правил задачи (13.8) также была бы невозможна. Эти проблемы и, вероятно, многие другие, можно обобщить, учитывая, что Gradle использует динамический язык и может динамически добавлять и изменять задачи, поэтому до оценки первого прохода результаты могут быть недетерминированными, поскольку путь выполнения создан и измененные во время выполнения, таким образом, различные последовательности оценки могут давать произвольно разные результаты, если есть зависимости или поведенческие директивы, которые неизвестны до позднего времени, поскольку они еще не созданы. (Это может быть достойно изучения на некоторых конкретных примерах. Если это правда, то даже двух проходов не всегда будет достаточно. Если A -> B, B -> C, где C меняет поведение A так, что оно больше не будет зависит от B, тогда у вас есть проблема. Я надеюсь, что есть некоторые лучшие практики по ограничению метапрограммирования с нелокальной областью действия, чтобы не допустить его в произвольных задачах. Интересным примером будет симуляция парадокса путешествия во времени, когда внук убивает дедушку или женится на бабушке, ярко иллюстрируя некоторые практические этические принципы!)
Позволяет улучшить отчеты о состоянии и ходе выполнения текущей сборки. TaskExecutionListener предоставляет до / после перехватчики для обработки каждой задачи, но, не зная количества оставшихся задач, мало что можно сказать о статусе, кроме «6 задач завершены. О выполнении задачи foo». Вместо этого вы можете инициализировать TaskExecutionListener с количеством задач в gradle.taskGraph.whenReady, а затем присоединить его к TaskExecutionGraph. Теперь он может предоставить информацию для включения подробностей отчета, например «6 из 72 задач завершены. Теперь выполняется задача foo. Предполагаемое оставшееся время: 2 ч. 38 м.» Это было бы полезно для отображения на консоли для сервера непрерывной интеграции, или если Gradle использовался для организации большой многопроектной сборки, и оценки времени были критически важны.
Как отметил Джерри Буллард, оценочная часть жизненного цикла имеет решающее значение для определения плана выполнения, который предоставляет информацию о среде, поскольку среда частично определяется контекстом выполнения (пример 4.15 в разделе «Настройка по DAG»). ). Кроме того, я мог видеть, что это полезно для оптимизации исполнения. Независимые подпути могут быть безопасно переданы различным потокам. Алгоритмы обхода для выполнения могут быть менее ресурсоемкими, если они не наивны (моя интуиция говорит, что всегда обход пути с большинством подпутей приведет к большему стеку, чем всегда предпочтение путей с наименьшим количеством подпутей).
Интересным использованием этого может быть ситуация, когда многие компоненты системы изначально отключаются для поддержки демонстраций и постепенного развития. Затем во время разработки вместо обновления конфигурации сборки по мере реализации каждого компонента сама сборка может определить, готов ли подпроект еще к включению (возможно, он пытается получить код, скомпилировать его и запустить заранее определенный набор тестов) , Если это так, этап оценки выявит это, и будут включены соответствующие задачи, в противном случае он выбирает задачи для заглушек. Возможно, существует зависимость от базы данных Oracle, которая еще не доступна, и вы тем временем используете встроенную базу данных. Вы можете позволить сборке проверять доступность, прозрачно переключаться, когда это возможно, и сообщать вам, что она переключала базы данных, а не сообщать об этом. Там может быть много творческого использования по этим направлениям.
Градл выглядит потрясающе. Спасибо за провокацию!