kotlin - 摇篮。块插件中的自定义函数{}
问题描述
我可以在我的自定义插件中编写一些函数,如 kotlin("jvm") 吗?
plugins {
java
kotlin("jvm") version "1.3.71"
}
我想在我的自定义插件中编写函数 myplugin("foo") 然后像使用它一样使用它
plugins {
java
kotlin("jvm") version "1.3.71"
custom.plugin
myplugin("foo")
}
我该怎么做?
解决方案
我认为该plugins
块是某种宏表达式。它使用非常有限的上下文进行解析和预编译。可能,魔法发生在kotlin-dsl的某个地方。这可能是从插件中获取静态访问器和扩展函数以在 Kotlin 中工作的唯一方法。我从未在 Gradle 的文档中看到过这个过程,但让我解释一下我的想法。可能来自 Gradle 的一些聪明人会纠正我。
让我们看看一些第三方插件,比如Liquibase。它允许你在你的build.gradle.kts
:
liquibase {
activities {
register("name") {
// Configure the activity here
}
}
}
想一想:在像 Kotlin 这样的静态编译语言中,为了使这种语法能够工作,应该有一个以类型命名的扩展名liquibase
(Project
因为它是this
every 中的对象类型build.gradle.kts
)在执行的 Gradle 的 VM 的类路径中可用构建脚本。
事实上,如果你点击它,你会看到类似的东西:
fun org.gradle.api.Project.`liquibase`(configure: org.liquibase.gradle.LiquibaseExtension.() -> Unit): Unit =
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("liquibase", configure)
但是看一下定义它的文件。就我而言,它是~/.gradle/caches/6.3/gradle-kotlin-dsl-accessors/cmljl3ridzazieb8fzn553oa8/cache/src/org/gradle/kotlin/dsl/Accessors39qcxru7gldpadn6lvh8lqs7b.kt
。它绝对是一个自动生成的文件。文件树的上几层——~/.gradle/caches/6.3/gradle-kotlin-dsl-accessors/
在我的例子中——有几十个类似的目录。我想,我曾经在 Gradle 6.3 中使用过的每个插件/版本都一个。这是Detekt插件的另一个:
fun org.gradle.api.Project.`detekt`(configure: io.gitlab.arturbosch.detekt.extensions.DetektExtension.() -> Unit): Unit =
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("detekt", configure)
因此,我们有一堆.kt
文件定义了应用于项目的不同插件的所有扩展。这些文件显然是预缓存和预编译的,它们的内容在build.gradle.kts
. 事实上,您可以classes
在这些来源旁边找到目录。
源是根据应用插件的内容生成的。这可能是一项棘手的任务,其中包括一些魔术、反思和内省。有时这种魔法不起作用(由于 Groovy 的特性太复杂),然后你需要使用这个包中的一些糟糕的 DSL 。
它们是如何产生的?我认为没有其他办法,但
build.script.kts
使用嵌入式 Kotlin 编译器/词法分析器解析- 提取所有
plugins
部分 - 编译它们,可能针对一些模拟(记住它
Project
还不可用:我们还没有执行它build.gradle.kts
本身!) - 解析Gradle Plugin 存储库中声明的插件(有一些细微差别来自
settngs.gradle.kts
) - 内省插件的工件
- 生成源
- 编译源码
- 将生成的类添加到脚本的类路径
plugins
这里有个问题:编译块时可用的上下文(类路径、类、方法——随便叫什么)非常有限。实际上,尚未应用任何插件!因为,您知道,您正在解析应用插件的块。鸡、蛋,还有它们的问题,呵呵……</p>
因此,我们越来越接近您问题的答案,要在plugins
块中提供自定义 DSL,您需要修改该类路径。这不是你的类路径build.gradle.kts
,而是解析的 VM 的类路径build.gradle.kts
。基本上,它是 Gradle 自己的类路径——捆绑在 Gradle 发行版中的所有类。
因此,可能在块中提供真正自定义 DSL 的唯一方法plugins
是创建自定义 Gradle 发行版。
编辑:
确实,完全忘记测试buildSrc
. 我在其中创建了一个文件PluginExtensions.kt
,其中包含一个内容
inline val org.gradle.plugin.use.PluginDependenciesSpec.`jawa`: org.gradle.plugin.use.PluginDependencySpec
get() = id("org.gradle.war") // Randomly picked
inline fun org.gradle.plugin.use.PluginDependenciesSpec.`jawa`(): org.gradle.plugin.use.PluginDependencySpec {
return id("org.gradle.cunit") // Randomly picked
}
它似乎正在工作:
plugins {
jawa
jawa()
}
但是,这仅PluginExtensions.kt
在默认包中时才有效。每当我将它放入子包中时,即使使用导入,扩展也无法识别:
魔法!
推荐阅读
- kubernetes - 维护到目前为止在 K8s 集群中创建的 PV 列表
- php - Apache 测试页面正在加载而不是应用程序索引页面
- kubernetes - 入口控制器可以包含默认后端和规则吗?
- python - 在 Python 中重命名临时文件
- python - 如何为使用 boto3 导入的 cognito 客户端编写单元测试?
- c# - 如何调用通用委托?
- javascript - 如何使用 perl(和 JS?)登录这个网站?
- java - 当我将 CustomView(Segment bar)动态添加到具有 ScrollView 父级的 recyclerView 时,滚动不流畅
- tensorflow2.0 - TensorFlow 初学者快速入门教程:损失比预期更糟
- angular - 如何以角度分配api获取请求的响应数据