如果应用了Java插件,Gradle将无法在复合版本中找到zip工件 [英] Gradle is unable to find zip artifact in composite build if java plugin is applied

查看:97
本文介绍了如果应用了Java插件,Gradle将无法在复合版本中找到zip工件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a Gradle project which creates a zip artifact. I define the artifact via artifacts.add('default', zipTask). I add this project to another project via includeBuild and use the zip as dependency (dependencies { myConfiguration 'org.example:testA:+@zip' }). So far so good. It works.

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

The problem starts when I add the plugin java to the first project. For some reason it prevents Gradle from finding the zip artifact. The error is:

Execution failed for task ':doubleZipTask'.
> Could not resolve all files for configuration ':myConfiguration'.
   > Could not find testA.zip (project :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 插件的版本中打印:

and in the version with java plugin it prints:

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

但是,我不确定其他工件是否可以破坏某些东西

However, I'm not sure if an additional artifact can break something.

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

It doesn't seem to be a problem when I add a second artifact myself.

也许zip文件不是我意图的最佳体现。毕竟,我可以在一个项目中构建与Java相关的文件,然后在另一个项目中压缩它们。
但是,该问题也适用于war文件。 (战争插件内部使用Java插件,因此无法单独运行。)

Maybe the zip file isn't the best representation of my intentions. After all, I could build java related files in one project and zip them in another. However, the problem also applies to war files. (War plugin internally uses the Java plugin so it cannot be run separately.)

推荐答案

以下设置应与Gradle 5.6配合使用(使用其他属性时,它也可能会与以前的版本一起使用)。除 XXX 所指示的更改外,它基本上与您的原始设置相对应。

The following setup should work with Gradle 5.6 (when using another attribute it will likely also work with previous versions). It mostly corresponds to your original setup with the exception of the changes indicated by XXX.

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 中添加对 testA myConfiguration'org.test :testA:0.0.0。+ @ jar')也起作用。


I have tested this setup both with and without the java plugin. I’ve also tested publishing to a Maven repository and letting testB take its dependency from there instead of from the included build of testA. Adding an additional dependency from testB on the JAR artifact of testA (myConfiguration 'org.test:testA:0.0.0.+@jar') worked, too.

关于(我相信)发生了什么的一些解释: Gradle需要一种方法来自动确定 testA 中的哪个本地组件/工件可以用来替代 testB 的外部依赖关系

Some explanation on what (I believe) is going on: Gradle needs a way of determining automatically which local component/artifact in testA it can use for substituting the external dependency of testB.


  • 如果不应用 java 插件,则只有一个组件/工件我的猜测是Gradle会选择该单个对象,而无需多做。

  • 如您所见,通过应用 java 插件,另一个工件被添加到 testA 中。现在,Gradle应该选哪一个?有人希望它会查看在 testB 中的依赖项上指定的文件扩展名,但事实并非如此。替代依赖项时,Gradle似乎实际上不是在 artifacts 级别上工作,而是在 module / component 级别上工作。您可能会说我们只有一个带有两个工件的组件,因此选择一个组件应该很简单。但是似乎实际上我们有两个相同分量的 variant ,并且Gradle想要选择这些 variant 之一。在您自己的 testB 设置中,没有任何线索可以告诉Gradle选择哪个变体。因此失败(带有公认的错误/误导性错误消息)。在更改后的 testB 设置中,我提供了线索:我告诉Gradle我们想要具有特定属性,其值为 my-zipped-lib 。由于我在发布的 testA 配置中添加了相同的属性,因此Gradle现在可以选择正确的变体(因为只有一个具有必需的属性)。依赖项的文件扩展名仍然与第二步相关:Gradle选择了组件变体之后,仍然需要选择正确的工件,但只有那时。

  • Without applying the java plugin, there is only a single component/artifact and my guess is that Gradle then just selects that single one without further ado.
  • As you saw, by applying the java plugin, another artifact is added to testA. Now which one should Gradle take? One would expect that it would look at the file extension specified on the dependency in testB but that doesn’t seem to be the case. It seems that Gradle isn’t actually working at the artifacts level when substituting dependencies but rather at the module/component level. You might say we only have one component with two artifacts, so selecting the one component should be straightforward. But it seems that we actually have two variants of the same component and Gradle wants to select one of these variants. In your own testB setup, there is no clue given that would tell Gradle which variant to select; so it fails (with an admittedly bad/misleading error message). In my changed testB setup I provide the clue: I tell Gradle that we want the variant that has a specific attribute with the value my-zipped-lib. Since I’ve added the same attribute on the published configuration of testA, Gradle is now able to select the right variant (because there is only one that has the required attribute). The file extension on the dependency is still relevant in a second step: once Gradle has selected the component variant, it still needs to select the right artifact – but only then.

请注意,我们实际上是在今天有什么支持。另请参见版本问题2529 ,其中指出发布非jar工件的项目没有得到很好的支持。当我第一次看到您的问题时,老实说,我们在这里很不幸……但是,似乎有一种方法可以再度靠近边缘;-)

Note that we’re actually working on the rim of what is supported with composite builds today. See also Gradle issue #2529 which states that "projects that publish non-jar artifacts" were not terribly well supported. When I first saw your question I honestly thought we’d be out of luck here … but it seems there’s a way to again step a little closer to the rim ;-)

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

In the comments, the question came up why adding multiple custom artifacts works while applying the java plugin breaks the build. As I’ve tried to explain above, it’s not a question of multiple artifacts but of multiple component variants. IIUIC, these variants originate from different attributes on configurations. When you don’t add such attributes, then you will not have different components variants. However, the Java plugin does add such attributes which consequently leads to different component variants in your project(/component). If you’re interested, you can see the different attributes by adding something like the following to your build.gradle:

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

现在在何时何地添加哪些属性?这取决于您的设置。我不会盲目地将属性添加到所有配置中,以希望能够神奇地解决问题。尽管它可能会起作用(取决于您的设置),但肯定不是干净的。如果您的项目设置像问题所提示的那样复杂和/或特殊,那么可能更有意义的是,对所需的配置以及它们应携带的属性进行更深入的思考。我上面链接的 Gradle文档页面的第一部分可能是如果您还不熟悉Gradle中的配置细微差别,那么这是一个很好的起点。是的,我同意这样的逻辑最好放在Gradle插件中。

Now where and when to add which attributes? That depends on your setup. I wouldn’t blindly add attributes to all configurations in the hope that that’ll solve things magically. While it might work (depending on your setup), it’d certainly not be clean. If your project setup is as complex and/or special as your question suggests, then it’ll probably make sense to think more deeply about which configurations you need and what attributes they should carry. The first sections of the Gradle documentation page that I have linked above are probably a good starting point if you are not intricately familiar with these nuances of configurations in Gradle, yet. And yes, I agree that such logic would best live in a Gradle plugin.

这篇关于如果应用了Java插件,Gradle将无法在复合版本中找到zip工件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆