【问题标题】:Gradle is unable to find zip artifact in composite build if java plugin is applied如果应用了 java 插件,Gradle 无法在复合构建中找到 zip 工件
【发布时间】:2019-07-30 13:12:35
【问题描述】:

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

当我将插件java 添加到第一个项目时,问题就开始了。由于某种原因,它会阻止 Gradle 找到 zip 工件。 错误是:

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插件,不能单独运行。)

【问题讨论】:

标签: java gradle build.gradle artifact


【解决方案1】:

问题似乎是 Gradle 中的错误,其中复合构建和对工件的引用被破坏。

这里有一些讨论:https://discuss.gradle.org/t/composite-build-cant-use-included-artifact-in-buildsrc-build-gradle/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
}

【讨论】:

  • 我不太确定它是否相同。您发现的问题集中在一些奇怪的项目结构上(我承认我并不完全理解)。它从未明确指出 java 插件的任何问题。
  • 据我了解,复合构建和工件依赖项是第一个链接中的错误引用“但是,如果我想在 aa buildSrc/build.gradle 中执行此操作,它将无法找到工件来自复合。例如 my-project/buildSrc/build.gradle"
  • 好吧,我仍然不能使用它。我尝试使用 Gradle 的主要原因之一是因为我可以将其配置为使用存储库而不是包含的构建。 (我在 includeBuild('../testA') 周围有 if 子句。)这确实加快了大项目树中的编译速度。
【解决方案2】:

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

请注意,我们今天实际上是在使用复合构建在 what is supported 的边缘上工作。另请参阅Gradle issue #2529,其中指出“发布非 jar 工件的项目”没有得到很好的支持。当我第一次看到你的问题时,我真的以为我们在这里运气不好……但似乎有办法再次靠近篮筐;-)


在 cmets 中,出现了一个问题,为什么在应用 java 插件的同时添加多个自定义工件会破坏构建。正如我在上面试图解释的,这不是多个工件的问题,而是多个组件变体的问题。 IUIC,这些变体源自配置的不同属性。当您不添加此类属性时,您将不会有不同的组件变体。但是,Java 插件确实添加了这样的属性,从而导致您的项目(/组件)中出现不同的组件变体。如果您有兴趣,可以通过在build.gradle 中添加类似以下内容来查看不同的属性:

configurations.each { conf ->
    println "Attributes of $conf:"
    conf.attributes.keySet().each { attr ->
        println "\t$attr -> ${conf.attributes.getAttribute(attr)}"
    }
}

现在何时何地添加哪些属性?这取决于您的设置。我不会盲目地为所有配置添加属性,希望能神奇地解决问题。虽然它可能有效(取决于您的设置),但它肯定不干净。如果您的项目设置与您的问题所暗示的一样复杂和/或特殊,那么更深入地考虑您需要哪些配置以及它们应该具有哪些属性可能会有意义。如果您还不太熟悉 Gradle 中的这些细微差别,那么我在上面链接的 the Gradle documentation page 的第一部分可能是一个很好的起点。是的,我同意这样的逻辑最好存在于 Gradle 插件中。

【讨论】:

  • 哇,它有效。虽然,我将不得不通过自定义插件找到一些方法来完成它,因为我不喜欢将它复制到数十个项目的想法。如果我只是不加选择地将这个属性添加到每个项目的每个配置中,会不会破坏一些想法?
  • 我认为这不仅仅是单个项目中多个工件的问题。 Java 插件必须做的不仅仅是添加另一个工件。我可以自己创建第二个,并且它们都可以在我不设置任何属性的情况下工作。
  • 是的,确实,我不认为多个工件的问题,而是多个组件变体的问题。我已经更新了我的答案以详细说明这一点。我也试着回答你的其他问题。
猜你喜欢
  • 2016-02-06
  • 2023-01-29
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多