Следующая настройка должна работать с Gradle 5.6 (при использовании другого атрибута он, вероятно, будет работать и с предыдущими версиями). В основном это соответствует вашей первоначальной настройке, за исключением изменений, обозначенных XXX
.
Проект testA
settings.gradle
:
rootProject.name = 'testA'
build.gradle
:
plugins {
id 'base'
// Uncomment the line below to break the zip artifact
//id 'java'
}
group = 'org.test'
version = '0.0.0.1_test'
task zipTask(type: Zip) {
from './settings.gradle' // just so the zip isn't empty
}
// XXX added an attribute to the configuration
configurations.default.attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
project.objects.named(LibraryElements, 'my-zipped-lib'))
}
artifacts.add('default', zipTask)
Проект testB
settings.gradle
:
rootProject.name = 'testB'
// This line may be commented out in some cases and then the artifact should be downloaded from Maven repository.
// For this question it should be always uncommented, though.
includeBuild('../testA')
build.gradle
:
plugins {
id 'base'
}
configurations {
// XXX added the same attribute as in the testA project
myConfiguration {
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
project.objects.named(LibraryElements, 'my-zipped-lib'))
}
}
}
dependencies {
myConfiguration 'org.test:testA:0.0.0.+@zip'
}
task doubleZipTask(type: Zip) {
from configurations.myConfiguration
}
Я протестировал эту настройку как с плагином java
, так и без него. Я также протестировал публикацию в репозиторий Maven и позволил testB
получить зависимость оттуда, а не из включенной сборки testA
. Добавление дополнительной зависимости от testB
к артефакту JAR testA
(myConfiguration 'org.test:testA:0.0.0.+@jar'
) также сработало.
Некоторое объяснение того, что (я думаю) происходит: Gradle нужен способ автоматического определения того, какой локальный компонент/артефакт в testA
он может использовать для замены внешней зависимости testB
.
- Без применения плагина
java
есть только один компонент/артефакт, и я предполагаю, что Gradle затем просто выбирает этот единственный без лишних слов.
- Как вы видели, применяя плагин
java
, к testA
добавляется еще один артефакт. Теперь, какой из них должен взять Gradle? Можно было бы ожидать, что он будет смотреть на расширение файла, указанное в зависимости в testB
, но, похоже, это не так. Похоже, что Gradle на самом деле работает не на уровне артефактов при замене зависимостей, а скорее на уровне модуля/компонента. Можно сказать, что у нас есть только один компонент с двумя артефактами, поэтому выбор одного компонента должен быть простым. Но похоже, что на самом деле у нас есть два варианта одного и того же компонента, и Gradle хочет выбрать один из этих вариантов. В вашей собственной настройке testB
нет подсказки, которая указывала бы Gradle, какой вариант выбрать; поэтому он терпит неудачу (с заведомо плохим/вводящим в заблуждение сообщением об ошибке). В моей измененной настройке testB
я даю подсказку: я говорю Gradle, что нам нужен вариант, который имеет определенную атрибут со значением my-zipped-lib
. Поскольку я добавил тот же атрибут в опубликованную конфигурацию testA
, теперь Gradle может выбрать правильный вариант (поскольку есть только один, который имеет требуемый атрибут). Расширение файла для зависимости по-прежнему актуально на втором этапе: как только Gradle выбрал вариант компонента, ему все равно нужно выбрать правильный артефакт — но только тогда.
Обратите внимание, что на самом деле мы работаем над тем, что поддерживается. с композитными сборками сегодня. См. также выпуск Gradle #2529, в котором говорится, что "проекты, публикующие артефакты, отличные от jar-файлов" не очень хорошо поддерживались. Когда я впервые увидел ваш вопрос, я, честно говоря, подумал, что нам здесь не повезет… но, похоже, есть способ снова подойти немного ближе к краю ;-)
В комментариях возник вопрос, почему добавление нескольких пользовательских артефактов работает, а применение плагина java
ломает сборку. Как я пытался объяснить выше, речь идет не о нескольких артефактах, а о нескольких вариантах компонентов. IIUIC, эти варианты происходят из разных атрибутов конфигураций. Когда вы не добавляете такие атрибуты, у вас не будет разных вариантов компонентов. Однако подключаемый модуль Java добавляет такие атрибуты, что приводит к различным вариантам компонентов в вашем проекте (/component). Если вам интересно, вы можете увидеть различные атрибуты, добавив что-то вроде следующего к вашему build.gradle
:
configurations.each { conf ->
println "Attributes of $conf:"
conf.attributes.keySet().each { attr ->
println "\t$attr -> ${conf.attributes.getAttribute(attr)}"
}
}
Теперь, где и когда добавлять какие атрибуты? Это зависит от вашей настройки. Я бы не стал слепо добавлять атрибуты ко всем конфигурациям в надежде, что это волшебным образом решит проблему. Хотя это может работать (в зависимости от ваших настроек), это определенно не будет чистым. Если настройка вашего проекта настолько сложна и/или специфична, как предполагает ваш вопрос, то, вероятно, имеет смысл более глубоко подумать о том, какие конфигурации вам нужны и какие атрибуты они должны нести. Первые разделы страницы документации Gradle, на которые я ссылался выше, вероятно, хорошая отправная точка, если вы еще не знакомы с этими нюансами конфигураций в Gradle. И да, я согласен, что такая логика лучше всего будет жить в плагине Gradle.
person
Chriki
schedule
17.08.2019