Избавляемся от бинарных зависимостей с композитной сборкой в Gradle 3.1

    С самого появления 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 включенной сборкой.

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


    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 5

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

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

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

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

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

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

        Only users with full accounts can post comments. Log in, please.