Есть ли способ определить свойство, которое будет использоваться как в settings.gradle.kts, так и в проектах / подпроектах build.gradle.kts с gradle 6.0?

У нас есть многомодульное приложение для Android с логикой сборки, написанной на gradle kotlin dsl. Мы используем buildSrc для извлечения общей логики, такой как версии зависимостей. У нас есть что-то вроде:

buildSrc/src/main/kotlin/Dependencies.kt:

object Versions {
    const val fooVersion = "1.2.3"
    const val barVersion = "4.5.6"
}

object Libraries {
    val foo = "com.example.foo:foo:$fooVersion"
    val bar = "com.example.bar:bar:$barVersion"
}

object Modules {
    const val app = ":app"
    const val base = ":base"
    const val baz = ":baz"
}

Затем мы можем использовать их в блоке dependencies модулей, чтобы избежать жестко запрограммированных / дублированных значений:

app/build.gradle.kts:

dependencies {
    implementation(Libs.foo)
    implementation(Libs.bar)

    implementation(project(Modules.base))
    implementation(project(Modules.baz))
}

И мы также используем его в settings.gradle.kts:

settings.gradle.kts:

include(
    Modules.app,
    Modules.base,
    Modules.baz
)

Это нормально работает с Gradle 5.6. Когда я обновляюсь до 6.0, я получаю Unresolved reference: Modules в файле settings.gradle.kts. Я обнаружил, что это упомянуто в руководстве по миграции:

Раньше проект buildSrc создавался до применения скрипта настроек проекта, и его классы были видны внутри скрипта. Теперь buildSrc создается после скрипта настроек, и его классы ему не видны. Классы buildSrc остаются видимыми для сценариев сборки проекта и подключаемых модулей сценариев.

Пользовательскую логику можно использовать из скрипта настроек, объявив внешние зависимости.

Итак, я знаю, что сломало сборку, и могу исправить ее, используя жестко запрограммированные значения в settings.gradle.kts:

include(
    ":app",
    ":base",
    ":baz"
)

Можно ли избежать этого дублирования с помощью Gradle 6.0?


person ferini    schedule 27.11.2019    source источник


Ответы (2)


См. билет № 11090 "Определения из buildSrc / не найдены в settings.gradle.kts с использованием gradle 6.0-rc -1 ".

Как вы уже заметили, это недавно изменилось:

Это изменилось в 6.0 и устарело в 5.6. См. https://docs.gradle.org/current/userguide/upgrading_version_5.html#buildsrc_usage_in_gradle_settings

- https://github.com/gradle/gradle/issues/11090#issuecomment-544473179

Один из сопровождающих описывает причины этого решения:

К сожалению, у обеих схем (settings-then-buildSrc и buildSrc-then-settings) есть плюсы и минусы, и после рассмотрения мы выбрали первое.

(...)

Плюсы, которые побудили нас внести изменения:

  1. Плагины настроек могут влиять на buildSrc и основную сборку (т. Е. Применять плагин сборки к обоим)
  2. Конфигурация кэша сборки применяется к buildSrc
  3. buildSrc больше похож на обычную включенную сборку

- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268

И напоследок плохие новости:

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

- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268

Обходные пути

В вышеупомянутом сообщении автор предлагает некоторые обходные пути:

Минус именно в том, что вы ударили. Использовать сложную логику в скрипте настроек теперь менее удобно. Теперь вам нужно либо:

  1. Вставьте логику в файл настроек
  2. Переместите логику в общий сценарий, который можно использовать там, где это необходимо.
  3. Переместите логику в предварительно созданный двоичный файл, который вы загружаете в файл настроек (то есть плагин настроек)

- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268

№1 довольно прост, но я могу только предположить, что означают №2 и №3. Я пришел из мира Groovy и только недавно начал подружиться с Kotlin DSL. Сказав это, давайте попробуем.

В № 3 автор может говорить о разработке внешнего плагина и применении его в обоих сценариях. Я не совсем уверен, есть ли смысл реализовать это (хотя это дает вам строгую типизацию).

«# 2 Перенесите логику в общий сценарий, который можно использовать там, где это необходимо»

Думаю, дело в общем плагине скрипта и его включении. в файлах settings.gradle и build.gradle. Плагин помещал статическую информацию в _5 _ ExtensionAware в области ( Settings в случае подключаемого модуля сценария settings.gradle и Project в случае build.gradle). Это описано в этом ответе на «Включить скрипты с Gradle Kotlin DSL»:

Как я могу поместить все общие константы (например, версии зависимостей) в отдельный файл, чтобы включить их, просто используя что-то вроде springBootVersion или Constants.springBootVersion с проверками во время компиляции?

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

// $rootDir/dependencies.gradle.kts

// this will try to take configuration from existing ones
val compile by configurations
val api by configurations
dependencies {
  compile("commons-io:commons-io:1.2.3")
  api("some.dep")
}

// This will put your version into extra extension
extra["springBootVersion"] = "1.2.3"

И вы можете использовать это так:

// $rootDir/build.gradle.kts
subprojects {
  apply {
    plugin<JavaLibraryPlugin>()
    from("$rootDir/dependencies.gradle.kts")
  }

И в вашем модуле:

// $rootDir/module/build.gradle.kts
// This will take existing dependency from extra
val springBootVersion: String by extra
dependencies {
  compile("org.spring:boot:$springBootVersion")
}

- Включить скрипты с Gradle Kotlin DSL

person jannis    schedule 29.04.2020
comment
Не могли бы вы представить, как будут выглядеть обходные пути (пункты 2 и 3)? - person Nominalista; 30.04.2020

AFAIK - нет, и это то, что говорится в вышеупомянутом руководстве по миграции: settings.gradle является первым, который оценивается, поэтому на этом этапе объекты, определенные в buildSrc, еще даже не существуют.

Я могу представить себе какой-нибудь хитрый обходной путь - просто для науки, но в реальном проекте это будет так плохо пахнуть, что, IMO, того не стоит.

П. С .: Думаю, вы могли бы отменить это и попытаться создать экземпляр некоторого перечисления, пройдя через подмодули в коде buildSrc. Но опять же, способы добиться этого могут быть довольно экзотическими и должны использоваться только с единственной целью доказать, что это может работать)

person Den Drobiazko    schedule 22.04.2020