从 Gradle 构建脚本中提取常用方法

我有一个 Gradle 构建脚本(build.gradle) ,在其中我创建了一些任务。这些任务主要由方法调用组成。被调用的方法也在构建脚本中。

情况是这样的:

我创建了相当数量的构建脚本,其中包含不同的任务,但使用相同的方法从原始脚本。因此,我希望以某种方式提取这些“常用方法”,这样我就可以轻松地重用它们,而不是为我创建的每个新脚本复制它们。

如果 Gradle 是 PHP,那么下面这样的代码将是最理想的:

//script content
...
require("common-methods.gradle");
...
//more script content

但是,当然,这是不可能的。或者说,是吗?

无论如何,我怎样才能达到这个结果呢?做到这一点的最佳方法是什么?我已经通读了 Gradle 的文档,但是我似乎无法确定哪种方法最简单、最适合这种情况。

先谢谢你!


更新:

我已经设法提取了另一个文件中的方法

(使用 apply from: 'common-methods.gradle') ,

所以结构如下:

parent/
/build.gradle              // The original build script
/common-methods.gradle     // The extracted methods
/gradle.properties         // Properties used by the build script

在执行了来自 build.gradle的任务之后,我遇到了一个新问题: 显然,方法在 common-methods.gradle中不能被识别。

有什么办法吗?

32762 次浏览

It isn't possible to share methods, but you can share extra properties containing a closure, which boils down to the same thing. For example, declare ext.foo = { ... } in common-methods.gradle, use apply from: to apply the script, and then call the closure with foo().

Building on Peter's answer, this is how I export my methods:

Content of helpers/common-methods.gradle:

// Define methods as usual
def commonMethod1(param) {
return true
}
def commonMethod2(param) {
return true
}


// Export methods by turning them into closures
ext {
commonMethod1 = this.&commonMethod1
otherNameForMethod2 = this.&commonMethod2
}

And this is how I use those methods in another script:

// Use double-quotes, otherwise $ won't work
apply from: "$rootDir/helpers/common-methods.gradle"


// You can also use URLs
//apply from: "https://bitbucket.org/mb/build_scripts/raw/master/common-methods.gradle"


task myBuildTask {
def myVar = commonMethod1("parameter1")
otherNameForMethod2(myVar)
}

Here's more on converting methods to closures in Groovy.

Using the Kotlin DSL it works like this:

build.gradle.kts:

apply {
from("external.gradle.kts")
}


val foo = extra["foo"] as () -> Unit
foo()

external.gradle.kts:

extra["foo"] = fun() {
println("Hello world!")
}

Another approach for Kotlin DSL could be:

my-plugin.gradle.kts

extra["sum"] = { x: Int, y: Int -> x + y }

settings.gradle.kts

@Suppress("unchecked_cast", "nothing_to_inline")
inline fun <T> uncheckedCast(target: Any?): T = target as T
    

apply("my-plugin.gradle.kts")
    

val sum = uncheckedCast<(Int, Int) -> Int>(extra["sum"])
    

println(sum(1, 2))

I would suggest a slight adjustment to Matthias Braun's answer, in that instead of writing the same method-name twice and still have it clear and consise, why not simply do the following:

ext.commonMethod1 = (param) -> {
return true
} as Closure<boolean>

The usage of the as-operator simply tells one explicitly, that this function will return a value of boolean-type.

Because after all, this still is Groovy goodness. Neat huh?