如果应用Java插件,Gradle将无法在复合构建中找到ZIP伪像



我有一个gradle项目,该项目创建了zip伪像。我通过artifacts.add('default', zipTask)定义工件。我通过includeBuild将此项目添加到另一个项目中,并将ZIP用作依赖项(dependencies { myConfiguration 'org.example:testA:+@zip' }(。到目前为止,一切都很好。它有效。

当我将插件java添加到第一个项目时,问题开始。由于某种原因,它可以防止Gradle找到拉链伪像。错误是:

Execution failed for task ':doubleZipTask'.
> Could not resolve all files for configuration ':myConfiguration'.
   > Could not find testA.zip (project :testA).

为什么?如何修复它?

完成示例:

项目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
}
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 {
    myConfiguration
}
dependencies {
    myConfiguration 'org.test:testA:0.0.0.+@zip'
}
task doubleZipTask(type: Zip) {
    from configurations.myConfiguration
}

更新1

我在build.grade的末尾添加了一些诊断代码:

configurations.default.allArtifacts.each() {
    println it.toString() + ' -> name: ' + it.getName() + ', extension: ' + it.getExtension()
}

和使用java插件的版本打印:

ArchivePublishArtifact_Decorated testA:zip:zip: -> name: testA, extension: zip
org.gradle.api.internal.artifacts.dsl.LazyPublishArtifact@2c6aaa5 -> name: testA, extension: jar

但是,我不确定额外的工件是否会破坏东西。

当我自己添加第二个工件时,这似乎不是问题。


更新2

也许zip文件不是我意图的最佳表示。毕竟,我可以在一个项目中构建与Java相关的文件,然后将其划在另一个项目中。但是,问题也适用于战争文件。(War插件内部使用Java插件,因此不能单独运行。(

该问题似乎是Gradle中的一个错误伪影被打破。

在这里进行了一些讨论:https://discuss.gradle.org/t/composite-build-cant-cant-use-cuse-included-artifact-infact-in-buildsrc-build-build-dradle/24978

错误报告:https://github.com/gradle/gradle/issues/3768

解决方法是将工件依赖性移至任务依赖性:

plugins {
    id 'base'
}
configurations {
    myConfiguration
}
dependencies {
}
task doubleZipTask(type: Zip) {
    dependsOn gradle.includedBuild('testA').task(':zipTask')
    from configurations.myConfiguration
}

以下设置应与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的构建中获取其依赖性。在testA(myConfiguration 'org.test:testA:0.0.0.+@jar'(的JAR伪像中添加testB的额外依赖性。

也可以。

关于(我认为(正在进行的事情的一些解释:Gradle需要一种自动确定testA中哪种本地组件/工件的方法,它可以用于替换testB的外部依赖性。

  • 在不应用java插件的情况下,只有一个组件/伪像,我的猜测是Gradle然后只选择没有其他ADO的单个单个。
  • 如您所见,通过应用java插件,将另一个工件添加到testA中。现在Gradle应该服用哪一个?人们希望它会查看testB中依赖关系上指定的文件扩展名,但事实并非如此。似乎Gradle在替换依赖性时实际上并没有在伪像级别上工作,而是在 module / component 级别上工作。您可能会说我们只有一个具有两个工件的组件,因此选择一个组件应该很简单。但是,似乎我们实际上有同一组件的两个变体,而gradle希望选择其中一种 variants 。在您自己的testB设置中,没有任何线索可以告诉Gradle选择哪种变体;因此,它失败了(公认的错误/误导性错误消息(。在我更改的testB设置中,我提供了线索:我告诉Gradle,我们希望具有具有值my-zipped-lib的特定属性的变体。由于我在testA的已发布配置上添加了相同的属性,因此Gradle现在能够选择正确的变体(因为只有一个具有所需属性(。依赖关系上的文件扩展名仍然在第二步中相关:一旦Gradle选择了组件变体,它仍然需要选择正确的伪像 - 但只有这样。

请注意,我们实际上正在研究当今复合构建支持的边缘。另请参见Gradle问题#2529,其中指出"发布非JAR文物的项目"的支持不足。当我第一次看到您的问题时,我诚实地以为我们会在这里不幸……但是看来有一种方法可以再次接近边缘; - (


在评论中,问题出现了为什么添加多个自定义工件在应用java插件时会破坏构建。正如我试图在上面解释的那样,这不是多个伪像的问题,而是多个组件变体的问题。IIUIC,这些变体源自配置上的不同属性。当您不添加此类属性时,您将不会具有不同的组件变体。但是,java插件 dis 添加了此类属性,从而导致项目(/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插件中生活。

最新更新