本文由 简悦 SimpRead转码, 原文地址 jonnyzzz.com
更深入地使用插件、扩展和 buildSrc
在将实际项目的 Gradle 构建从 Groovy 迁移到 Kotlin 的过程中,我收集了一些有用的建议、代码片段和解释。在本系列文章中,我们将一起学习如何更快、更轻松地转换为 Gradle Kotlin DSL。
刚接触 Gradle Kotlin DSL?请查看 第一篇文章,了解从 Groovy 迁移到 Kotlin 构建脚本的实用建议。在第二篇帖子中,我们介绍了在 Gradle Kotlin DSL 脚本上设置 Kotlin 任务。
在这篇文章中,我将自豪地分享我对 Gradle 中代码重用的发现:扩展、插件和 buildSrc 脚本。这将是 Ad-hoc Plugins with Gradle 一文的下一章,但我们将使用 Gradle Kotlin DSL。
项目扩展
我转换为 Kotlin DSL 的实际项目包含多个微服务,每个微服务都使用 Application 插件创建可执行文件,而 jib 插件则用于生成 Docker 镜像。我们通过 Gradle 临时插件重用代码,以避免脚本重复。pattern有助于重复使用相同的 Gradle(Groovy)代码,每个微服务的用法如下:
'some-service' {
diImplClassName = 'some-class'
}
临时插件通过父项目中的 project.subjects.forEach{..} 调用来应用。每个微服务只需一行代码,就足以为每个微服务项目提供命令行应用程序、docker 容器、日志配置、几个常用依赖项、测试 classpath 和测试。
同样的代码在 Kotlin DSL 中不起作用。相反,在 Kotlin DSL 中,我们可以通过 configure<T>{...}代码块调用其强类型版本,其中 "T "是要配置的扩展或约定的类型。我们需要知道扩展的类型才能使用它,例如
configure<MicroPluginSetup> {
diImplClassName = "some-class"
}
一般来说,我们可以尝试以下步骤将扩展或约定设置转换为 Kotlin。Gradle 会为通过 plugins{..} 块启用的插件生成约定和扩展的访问器。如果没有生成(就像我的情况),我们可以查看文档或源代码,了解扩展的类型名称。使用 println() 函数打印 project.extensions 映射项,尝试在 Groovy 或 Kotlin 中进行简短调试,以查看实际的项目扩展及其类型。
在 Gradle 中还有另一种处理共享代码的方法。它叫做 buildSrc。我决定将这种方法与静态类型的 Kotlin DSL 结合使用。buildSrc路径下的所有声明都应该在我项目的每个 "build.gradle.kts "文件中可见,并提供类型信息、错误高亮、代码导航和 IDE 支持。让我们看看它是如何工作的
buildSrc 项目
在 Gradle 中,良好做法 是将实用类或函数移到 "buildSrc "项目下。Ad Hoc Plugins with Gradle一文介绍了更多使用 Gradle 重用代码的方法。
按照惯例,Gradle 会检查 buildSrc 文件夹中的构建源项目。这样,我们就可以直接从根项目的其他构建文件(Gradle/Groovy 和 Gradle/Kotlin)中使用我们的代码、工具和类。
下面这个针对 buildSrc 项目的 Gradle/Kotlin 脚本就足够了,它通常被放在项目根目录下的 buildSrc/build.gradle.kts 文件中:
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
mavenCentral()
}
kotlinDslPluginOptions {
experimentalWarning.set(false)
}
项目准备就绪。你可能需要在 IntelliJ IDEA 中点击刷新 Gradle 项目才能继续。让我们创建一个辅助函数作为示例。为此,我们需要创建一个内容如下的 buildSrc/src/main/kotlin/file-op.kt 文件:
operator fun File.div(s: String) = File(this, s)
这是我最喜欢的构建操作符。它为 File 和 String 类型定义了 / 重载操作符。因此,我们可以使用 / 来组合路径,例如,我们可以编写以下代码来为子路径创建新的 File 对象:
buildScript / "aaa" / "jonnyzzz.txt"
早在 KotlinConf 2018 上,我们就和 Gradle 团队的一些成员讨论过 / 操作符。除此之外,我还注意到 Gradle sources 中也有类似的操作符:)
现在是时候把 Groovy Ad-Hoc 插件转换成 buildSrc 下的 Kotlin DSL 了。让我们开始吧
Ad-Hoc Gradle 插件
我的脚本是用 Groovy 编写的,作为父项目文件中的特设插件类。有关该设置的更多详情,请参阅ad-hoc Gradle plugins帖子中的解释。从 buildSrc 文件夹开始,我们将插件代码移到 buildSrc 文件夹。将 Groovy 脚本转换为 Kotlin DSL 需要几个转换步骤。您可以查看本系列的第一篇文章,了解更多详情。现在我们有了以下 Kotlin 代码:
package theBuildSrcPackage
fun applyMicroPlugin() {
apply<MicroPlugin>()
}
open class MicroPlugin : Plugin<Project> { ... }
open class MicroPluginSetup { ... }
applyMicroPlugin() 是一个很好的快捷方式,可以简化我们处理插件的方式。得益于 build.gradle.kts 文件中的代码自动补全功能,现在通过函数调用来应用插件比调用较长的 apply<>() 变体更容易了。
现在,Kotlin DSL 中特设插件的用法如下:
import theBuildSrcPackage.*
applyMicroPlugin()
configure<MicroPluginSetup> {
diImplClassName = "some-class"
}
这与我们之前的做法类似。我们首先应用插件,然后在第二步传递插件配置。我们应该意识到,我们使用了太长的 API 来实现目标。让我们试着让 API 更有表现力、更简短。请参阅我的talk《Kotlin 中富有表现力的 API》(Expressive APIs in Kotlin),了解更多提示。我们不需要多次重复启用 Gradle 插件的意图。这意味着所有其他类型和配置参数都应隐式包含在内。让我们为此添加以下辅助函数:
fun applyMicroPlugin(action: MicroPluginSetup.() -> Unit) {
apply<MicroPlugin>()
configure<MicroPluginSetup>(action)
}
上面的代码向我们隐藏了所有实现细节,因此我们可以简单地应用和配置插件:
applyMicroPlugin {
diImplClassName = "some-class"
}
这样的代码易于阅读和理解。现在我们的工作已经很清楚了。不再可能在不传递配置的情况下启用插件了。希望这能帮助我团队中的其他人更快地处理 Gradle 脚本。
结论
在这篇文章中,我们看到了如何将 ad-hoc plugin 转换为 Gradle/Kotlin。这样可以更方便地重用 Gradle 代码。
作为一种静态类型编程语言,Kotlin 与编写 Gradle 编译脚本似乎很搭。得益于静态类型推断,Kotlin 编译器能更早地发现错误,并显示有用的编译错误信息和警告。集成开发环境和编译器都会使用类型信息来推断给定作用域中的可用函数和属性,即使是在带有接收器的第五层嵌套 lambda 中也是如此。
我将在接下来的文章中介绍更多内容,敬请期待!查看
。