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

Posted

技术标签:

【中文标题】从 Gradle 构建脚本中提取常用方法【英文标题】:Extract common methods from Gradle build script 【发布时间】:2013-09-13 22:33:27 【问题描述】:

我有一个 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 好东西,最重要的是,要使增量构建正常工作需要额外的工作。预期的抽象是使用和重用Tasks。您也可以创建custom tasks。也许您应该考虑将您现在在方法中的实现放入任务中。 @Alpar 和 其他人;将timestamp()currentWorkingDirectory() 方法设置为task-s(例如)的目的是什么。实用函数和类似的东西名义上是标量的——它们不会是任务,除非 Gradle 和大多数构建系统内置的代码重用存在限制。我喜欢 DRY 的世界,我可以一次制作一件东西并重复使用它。事实上,扩展@Pieter VDE 的示例我还为我的父项目使用了“root.gradle”模式——build.gradle 文件通常定义了一些项目细节,然后只是apply $ROOT ... 如果您需要一种集中的方式来处理属性,也许这个问题可以帮助您:***.com/questions/60251228/… 【参考方案1】:

我建议对Matthias Braun's answer 稍作调整, 在那个而不是两次编写相同的方法名称并且仍然拥有它 清晰简洁,为什么不简单地执行以下操作:

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

as-operator 的用法只是明确地告诉一个人, 这个函数将返回一个值boolean-type。

因为毕竟这仍然是 Groovy 的优点。整齐吧?

【讨论】:

【参考方案2】:

以Peter's answer 为基础,这是我导出方法的方式:

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)

Here's more 在 Groovy 中将方法转换为闭包。

【讨论】:

使用闭包名称作为分机有什么具体原因吗? @AnoopSS 我们将两个闭包添加到Gradle's extra properties。这些额外的属性捆绑在一个名为 ext 的对象中。 我们能否以某种方式将值转换为包含文件中定义的我们的类? 用示例代码发布一个单独的问题可能是个好主意,@GarouDan。【参考方案3】:

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

【讨论】:

【参考方案4】:

使用 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!")

【讨论】:

有没有办法分享实际类型?你基本上失去了类型安全和编译器的帮助......如果你可以共享包含你的方法的类,那么你可以使用编译器。【参考方案5】:

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

【讨论】:

它确实成功了!但我确实有一个问题:方法返回一些东西怎么样? F.e. File foo(String f) 将变为 ext.foo = f -&gt; ... ,然后我可以这样做:File f = foo(...) 显然,我之前评论中的问题是可能的。所以感谢彼得回答这个问题! @PeterNiederwieser 为什么不可能? Gradle.org 不这么认为:docs.gradle.org/current/userguide/… @IgorGanapolsky 感谢您的链接。我想知道如何在 gradle.build 的单独构建文件中使用生成的值 - 这样它会非常有用:) @IgorGanapolsky 您分享的链接应该如何帮助解决 Peter VDE 的问题?

以上是关于从 Gradle 构建脚本中提取常用方法的主要内容,如果未能解决你的问题,请参考以下文章

Gradle系列之构建脚本基础

Gradle&Maven-Android Gradle 常用命令参数及解释

python常用模块email----从原始邮件中提取邮件头信息

从 Bamboo 中的单独 GIT 存储库中提取文件

mysql提权常用方法

gradle常用命令和查看错误