等级。块插件中的自定义功能{}

问题描述 投票:0回答:2

我可以在自定义插件中编写像kotlin(“ jvm”)之类的函数吗?

plugins {
    java
    kotlin("jvm") version "1.3.71"
}

我想在我的自定义插件中编写函数myplugin(“ foo”),然后像使用它一样

plugins {
    java
    kotlin("jvm") version "1.3.71"
    custom.plugin
    myplugin("foo")
}

我该怎么做?

kotlin gradle gradle-plugin gradle-kotlin-dsl
2个回答
0
投票

kotlin函数只是包装传统id方法的简单扩展函数,不难定义:

fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec =
    id("org.jetbrains.kotlin.$module")

但是,此扩展功能是标准gradle kotlin DSL API的一部分,这意味着它无需任何插件即可使用。如果要使这样的自定义功能可用,则需要一个插件。用于加载插件的插件。不太实用。

我还尝试使用buildSrc模块来制作类似上述的扩展功能。但是事实证明,插件DSL块甚至没有buildSrc定义,它的语法非常受限制。无论如何这都不是很实际,您需要为每个要使用扩展名的项目创建一个buildSrc文件夹。

我不确定这是否完全可能。尝试询问https://discuss.gradle.org/


0
投票

我认为plugins块是某种宏表达式。它是使用非常有限的上下文进行解析和预编译的。魔术可能发生在kotlin-dsl中的某个地方。这可能是从插件获取静态访问器和扩展功能以在Kotlin中工作的唯一方法。我从未在Gradle的文档中提及此过程,但让我解释一下我的想法。也许,Gradle的一些聪明人会纠正我。

让我们看一些第三方插件,例如Liquibase。它允许您在build.gradle.kts

中编写类似的内容
liquibase {
    activities {
        register("name") {
            // Configure the activity here
        }
    }
}

考虑一下:在像Kotlin这样的静态编译语言中,为了使此语法有效,在liquibase类型上应该有一个名为Project的扩展名(因为它是每种语言中this对象的类型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目录。

源是根据所应用插件的内容生成的。它可能是tricky task,其中包含一些魔术,反射和自省。有时,这种魔力不起作用(由于过于时髦的Groovy性质),然后您需要使用this package中的一些糟糕的DSL。

它们是如何生成的?我看不到其他方式,但可以

  1. 使用嵌入式Kotlin编译器/词法分析器解析build.script.kts
  2. 提取所有plugins部分
  3. 编译它们,可能针对一些模拟(记住Project尚不可用:我们还没有执行build.gradle.kts本身!]
  4. 解析来自Gradle Plugin repository的声明的插件(其中一些nuances来自settngs.gradle.kts
  5. 自省插件的工件
  6. 生成源代码

这里是陷阱:编译plugins块时,可用的上下文非常有限(类路径,类,方法-随便叫什么)。实际上,尚未应用任何插件!因为您知道您正在解析适用于插件的块。鸡,鸡蛋及其问题,呵呵...

所以,我们离您的问题的答案越来越近,要在plugins块中提供自定义DSL,您需要修改该类路径。这不是您的build.gradle.kts的类路径,而是分析build.gradle.kts的VM的类路径。基本上,这是Gradle自己的类路径-所有类捆绑在Gradle发行版中。

因此,可能在plugins块中提供真正的自定义DSL的唯一方法是创建自定义的Gradle分发。

© www.soinside.com 2019 - 2024. All rights reserved.