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


85

我有一个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

关于如何解决该问题的任何想法?


您确定要编写所有方法吗?如果您按照方法编写构建脚本,则可能会错过一些Gradle的好东西,最重要的是,要使增量构建正常工作,还需要付出额外的工作。预期的抽象是使用和重复使用Task。您还可以创建自定义任务。也许您应该考虑将方法中已有的实现放入任务中。
Alpar

@Alpar和其他人; 使atimestamp()currentWorkingDirectory()方法为task-s的目的是什么(例如)。实用程序函数和类似的事物名义上是标量的-它们不是任务,除了Gradle和大多数构建系统内置的代码重用受到限制之外。我喜欢DRY世界,在这里我可以一次做一件事情并重复使用。实际上,在扩展@Pieter VDE的示例时,我还root.gradle对父项目使用了“ ”模式-build.gradle文件通常定义了一些项目细节,然后apply ${ROOT}...

如果你需要一个集中的方式来工作,性能也许这个问题可以帮助你:stackoverflow.com/questions/60251228/...
GarouDan

Answers:


76

不可能共享方法,但是您可以共享包含闭包的额外属性,归结为同一件事。例如,ext.foo = { ... }在中声明common-methods.gradle,使用apply from:以应用脚本,然后使用调用闭包foo()


1
它确实做到了!但是我确实有一个问题:方法返回什么?铁File foo(String f)会变成ext.foo = { f -> ... },那么我能做点什么File f = foo(...)吗?
Pieter VDE 2013年

2
显然,我之前的评论中的问题是可能的。所以,谢谢彼得,回答了这个问题!
Pieter VDE 2013年

1
@PeterNiederwieser为什么不可能呢?Gradle.org认为不是这样:docs.gradle.org/current/userguide/…–
IgorGanapolsky

1
@IgorGanapolsky感谢您的链接。我不知道如何在gradle.build中使用在单独的构建文件中生成的值-这样,它将非常有用:)
kiedysktos

@IgorGanapolsky在Peter VDE问题中,您共享的链接应该如何提供帮助?
t0r0X

157

基于Peter的答案,这就是我导出方法的方式:

内容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
}

这就是我在另一个脚本中使用这些方法的方式:

// 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)
}

这里是有关在Groovy中将方法转换为闭包的更多信息。


是否有任何特定原因将闭包名称用作ext?
Anoop

1
@AnoopSS我们将​​两个闭包添加到Gradle的extra属性中。这些额外的属性捆绑在名为的对象中ext
马提亚斯·布劳恩

我们可以以某种方式将值转换为包含文件中定义的类吗?
GarouDan

最好将单独的问题与示例代码@GarouDan一起发布。
Matthias Braun

7

使用Kotlin dsl,它的工作方式如下:

build.gradle.kts

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

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

external.gradle.kts

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

有没有一种共享实际类型的方法?您基本上失去了类型安全性,并且编译器提供了帮助...如果您可以共享包含方法的类,则可以使用编译器。
vach

0

Kotlin DSL的另一种方法可能是:

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))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.