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


Композитные сборки


В готовящейся к релизу версии 3.1 в Gradle появляется новый поход к организации сборок, состоящих из нескольких компонентов: композитные сборки (ориг. Composite Builds).


Композитные сборки позволяют:


  • Быстро подложить исправленную версию исходников библиотеки в другой проект без необходимости собирать её, опубликовывать и править сборку.
  • Делить большие проекты на несколько небольших, изолированных сборок, над каждой из которых можно работать как по отдельности, так и одновременно.
  • Отделить разработку плагина для системы сборки от проекта, его использующего (аналог buildSrc)


Разберем простой пример использования новой возможности.


Для этого создадим простенький проектик:


--app/
|-src/main/java/Main.java
|-build.gradle
- lib/
|-src/main/java/A.java
|-build.gradle
|-settings.gradle

lib/build.gradle:


apply plugin: 'java'

group "ru.shadam"
version "1.0"

task wrapper(type: Wrapper) {
    gradleVersion = '3.1-rc-1'
}

app/build.gradle


apply plugin: 'java'
apply plugin: 'application'

mainClassName='Main'

dependencies {
    compile 'ru.shadam:lib1:1.0'
}

task wrapper(type: Wrapper) {
    gradleVersion = '3.1-rc-1'
}

Теперь, если мы попробуем запустить app с помощью команды ./gradlew run Gradle будет ругаться на неразрешенную зависимость:


$ ./gradlew run
:compileJava
FAILURE: Build failed with an exception.

* What went wrong:
Could not resolve all dependencies for configuration ':compileClasspath'.
> Cannot resolve external dependency ru.shadam:lib1:1.0 because no repositories are defined.
  Required by:
      project :

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 1.027 secs

Но, если мы добавим новый флаг --include-build, то Gradle разрешит зависимости автоматически:


$ ./gradlew run --include-build ../lib1
[composite-build] Configuring build: C:\Users\sala\projects\gradle-compose\lib1
:compileJava
:lib1:compileJava UP-TO-DATE
:lib1:processResources UP-TO-DATE
:lib1:classes UP-TO-DATE
:lib1:jar UP-TO-DATE
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:run
Hello

BUILD SUCCESSFUL

Total time: 1.092 secs

Продвинутые варианты использования.


Встраиваем --include-build в скрипт


Представленный выше вариант больше подходит для одноразового использования — здесь и сейчас. Каждый раз указывать флаги не хочется — даже если зашить их во wrapper.


Для этого gradle предлагает использовать конфигурацию с использованием settings.gradle. Так, указанный выше флаг можно заменить с помощью следующего settings.gradle:


includeBuild('../lib1')

Подстановки


Что если в проекте, который вы хотите включить не указаны координаты артефакта? (группа, версия)


На помощь приходят подстановки:


includeBuild('../lib1') {
    dependencySubstitution {
        substitute('ru.shadam:lib1') with project(':')
    }
}

Эта возможность позволяет подставить любую зависимость на ru.shadam:lib1 зависимостью на проект lib1.


Зависимости между задачами


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


В связи с этим появился новый синтаксис для доступа к включаемым сборкам. Например, можно определить зависимость от задачи включенной сборки:


 task run {
    dependsOn gradle.includedBuild('lib1').task(':jar')
}

Что пока не работает?


  • Не поддерживаются в качестве включаемых проекты, у которых есть публикуемые артифакты, которые не соответствуют конфигурации по умолчанию. ссылка
  • Пока нет поддержки в IDE (но поддерживается генерация проекта с помощью команды ./gradlew idea)
  • Не поддерживаются native builds.

Планы команды


  • Добавить возможность вызывать задачи напрямую из включенных сборок.
  • Добавить возможность параллельно исполнять включенные сборки
  • Добавить обнаружение изменений во включенных сборках, когда используется флаг -t.
  • Сделать неявный проект buildSrc включенной сборкой.

Использованные материалы


Поделиться с друзьями
-->

Комментарии (5)


  1. xkor
    14.09.2016 09:36

    Композитные сборки позволяют:
    • Быстро подложить исправленную версию исходников библиотеки в другой проект без необходимости собирать её, опубликовывать и править сборку.
    • Делить большие проекты на несколько небольших, изолированных сборок, над каждой из которых можно работать как по отдельности, так и одновременно.
    • Отделить разработку плагина для системы сборки от проекта, его использующего (аналог buildSrc)

    А что то из этого не позволяют сделать многопроектные сборки?


    1. saladinkzn
      14.09.2016 09:39

      Многопроектная сборка — это дерево в файловой системе. Композитные сборки же позволяют разделить собираемые проекты в файловой системе со всеми вытекающими отсюда преимуществами.

      К тому же, у Gradle появляются гарантии, что включаемые сборки не зависят друг от друга, поэтому они собираются сделать возможность запускать их параллельно — а это уже должно дать прирост к производительности


      1. Prototik
        14.09.2016 18:51

        Многопроектная сборка — это дерево в файловой системе

        Ну, формально нет, проекты можно было тянуть из совершенно раных мест. Этот composite builds — лишь сахар над многопроектной сборкой, имхо. Я не говорю, что он бесполезен, но и новых возможностей он не привносит.


        1. saladinkzn
          14.09.2016 19:35

          Этот composite builds — лишь сахар

          Тут есть отличие в том, что:


          Included builds do not share any configuration with the composite build, or the other included builds. Each included build is configured and executed in isolation.

          Но, вообще говоря, да: это комбинация из фичи с подстановками + возможность делать include из командной строки.


          То есть никто не мешает сделать тоже самое, не используя Composite build: создать проект, заинклюдить туда :lib1 и :app и сделать Dependency Substituion.


  1. m1ld
    14.09.2016 09:36

    Теперь они сделали parent pom.xml…