[Gradle翻译]介绍Gradle模块元数据

403 阅读6分钟

本文由 简悦SimpRead 转码,原文地址 blog.gradle.org

Gradle模块元数据在Gradle 5.3中达到1.0,这里我们解释了为什么你应该像......。

Gradle模块元数据在Gradle 5.3中达到了1.0,在此我们解释一下为什么你应该像我们一样兴奋!"。

Gradle模块元数据的创建是为了解决多年来困扰依赖性管理的许多问题,特别是在Java生态系统中,但不限于此。它特别重要,因为POM文件(或Ivy文件)根本不足以描述现在的软件现实,在这种情况下,你可能需要区分不同平台的二进制文件,或者在有多个API可用时选择一个特定的实现。

我们将在本帖后面描述更多的例子。有些问题可能有变通办法,但这些变通办法是黑客式的,甚至是容易出错的。例如,你是否意识到这些是有问题的:为不同的Java版本使用分类器,为避免特定的记录器绑定而使用排除法,或者仅仅因为你需要覆盖一个特定的版本而添加第一层依赖关系?

Gradle模块元数据1.0是对这些问题的一个回答,也是我们整个行业向更好的依赖管理迈出的第一步。

它在实践中允许什么?

当你在classpath上同时拥有guava-jdk5guava-jdk8时,你是否曾经咒骂过,而你的应用程序只是因为幸运的排序而运行?你有没有遇到过这样的问题:有不同的SLF4J绑定,但在运行时才发现?那是因为这些库有不同的_变体,无法用现有的元数据格式正确描述。一个构建工具怎么能理解 "jdk8 "JAR、"sources "JAR、甚至 "all "JAR之间的区别?Gradle模块元数据的设计是为了以这样一种方式来解释区别,即消费者可以表达更精确的需求。例如,消费者可以特别要求他们能在JDK 8上使用的东西。而在SLF4J的情况下,构建工具会识别出Log4J的绑定与java.util.logging的绑定是互斥的。

整个想法是支持变体感知的依赖管理,这是基于对组件变体的描述--如主二进制文件、源码包、平台特定二进制文件等--以及它们相应的依赖关系。

我们的一些合作伙伴已经使用Gradle元数据好几个月了。例如,Kotlin native正在使用Gradle模块元数据来表示在将一个Kotlin项目编译到不同的架构时可以得到的不同二进制文件。Google正在使用variant-aware dependency management,但缺乏一个 "外部模型"。Gradle模块元数据就是那个外部模型,并将允许正确发布Android档案(AAR)。

这些只是例子,但这些问题以及更多的问题都可以通过利用Gradle元数据来解决。随着更多的库作者采用Gradle模块元数据,我们的行业将从整体上解决更多的问题。

Gradle Module Metadata如何影响你

Gradle Module Metadata 1.0为所有Gradle用户实现了细粒度的依赖解决。从Gradle 5.3开始,如果你是一个消费者,并且你使用的库有Gradle元数据发布,Gradle将自动消费任何发布到Maven或Ivy仓库的Gradle元数据。

然而,Gradle 5.3默认不会自动 发布 --这将在6.0中出现。你现在就可以发布Gradle模块元数据,但你必须通过使用Maven Publish或Ivy Publish插件来选择发布,并通过在设置脚本中添加以下一行来启用实验性发布功能。

settings.gradle(.kts)

enableFeaturePreview("GRADLE_METADATA")

Gradle模块元数据对Maven或Ant+Ivy的构建有何影响?

对于Maven和Ivy消费者来说,没有什么变化:如果你选择了发布Gradle模块元数据,相应的文件会与POM文件(如果你发布到Maven资源库)或Ivy文件(如果你发布到Ivy资源库)一起发布。请注意,从构建组件到Maven和Ivy元数据的映射是 lossy 的:例如,你不知道用什么Java版本来构建什么东西,所以这使得消费者无法事先知道它们是否兼容。另一个例子是当你使用Gradle的特定功能,如丰富的版本。我们尽力将它们映射到Maven或Ivy中的概念,但由于它们的元数据格式的限制,信息还是会在这个过程中丢失。

请注意,Gradle 5.2引入了发布插件的警告,当它知道映射对其他构建工具来说是有损失或有问题时,会发出警告。

链接和参考文献

Gradle模块元数据是一个JSON文件,其扩展名为.module。每个文件都描述了一个具有零个或多个变体的单一软件组件。下面是一个 "com.acme:client:1.0-SNAPSHOT "组件的元数据文件示例的内容,其中有几个变体。

{
  "formatVersion": "1.0",
  "component": {
    "group": "com.acme",
    "module": "client",
    "version": "1.0-SNAPSHOT",
    "attributes": {
      "org.gradle.status": "integration"
    }
  },
  "createdBy": {
    "gradle": {
      "version": "5.3",
      "buildId": "4wqjtkcv2fbmjjsewyu66wbvfq"
    }
  },
  "variants": [
    {
      "name": "apiElements",
      "attributes": {
        "org.gradle.dependency.bundling": "external",
        "org.gradle.jvm.version": 11,
        "org.gradle.usage": "java-api-jars"
      },
      "dependencies": [
        {
          "group": "com.mycompany",
          "module": "core",
          "version": {
            "requires": "2.5"
          }
        }
      ],
      "files": [
        {
          "name": "client-1.0-SNAPSHOT.jar",
          "url": "client-1.0-SNAPSHOT.jar",
          "size": 539,
          "sha1": "1f94fe53d33babdc9de537bb3a0108dbc0e25e4b",
          "md5": "6364cdd9923e1eda9b328bc80f93969c"
        }
      ]
    },
    {
      "name": "runtimeElements",
      "attributes": {
        "org.gradle.dependency.bundling": "external",
        "org.gradle.jvm.version": 11,
        "org.gradle.usage": "java-runtime-jars"
      },
      "dependencies": [
        {
          "group": "org.apache.commons",
          "module": "commons-lang3",
          "version": {
            "requires": "3.8"
          }
        },
        {
          "group": "com.mycompany",
          "module": "core",
          "version": {
            "requires": "2.5"
          }
        }
      ],
      "files": [
        {
          "name": "client-1.0-SNAPSHOT.jar",
          "url": "client-1.0-SNAPSHOT.jar",
          "size": 539,
          "sha1": "1f94fe53d33babdc9de537bb3a0108dbc0e25e4b",
          "md5": "6364cdd9923e1eda9b328bc80f93969c"
        }
      ]
    },
    {
      "name": "shadowApiElements",
      "attributes": {
        "org.gradle.dependency.bundling": "shadowed",
        "org.gradle.usage": "java-api"
      },
      "files": [
        {
          "name": "client-1.0-SNAPSHOT-all.jar",
          "url": "client-1.0-SNAPSHOT-all.jar",
          "size": 601730,
          "sha1": "9b70e54ffdce0541701d8f855bf75e059857eb0c",
          "md5": "3499bb6d9ccf86283854a5550135ea4a"
        }
      ]
    },
    {
      "name": "shadowRuntimeElements",
      "attributes": {
        "org.gradle.dependency.bundling": "shadowed",
        "org.gradle.usage": "java-runtime-jars"
      },
      "files": [
        {
          "name": "client-1.0-SNAPSHOT-all.jar",
          "url": "client-1.0-SNAPSHOT-all.jar",
          "size": 601730,
          "sha1": "9b70e54ffdce0541701d8f855bf75e059857eb0c",
          "md5": "3499bb6d9ccf86283854a5550135ea4a"
        }
      ]
    }
  ]
}

这个文件声明了4个变体,而属性让构建工具知道它们的用途。特别是你会看到这里有2个 "API "的变体和2个 "运行时 "的变体,而通常你只看到每个变体的一个。原因是这个特殊的组件声明了一个额外的变体,其中的依赖关系是 shadowed(胖jar)。这使消费者有机会决定它是否需要单独的jar,或者只是库的fatjar变体。

如果你对更多技术细节感兴趣,请参考Gradle模块元数据规范1.0

欢迎早期采用者,请随时给出你的反馈!


www.deepl.com 翻译