从 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 -> ...
,然后我可以这样做:File f = foo(...)
?
显然,我之前评论中的问题是可能的。所以感谢彼得回答这个问题!
@PeterNiederwieser 为什么不可能? Gradle.org 不这么认为:docs.gradle.org/current/userguide/…
@IgorGanapolsky 感谢您的链接。我想知道如何在 gradle.build 的单独构建文件中使用生成的值 - 这样它会非常有用:)
@IgorGanapolsky 您分享的链接应该如何帮助解决 Peter VDE 的问题?以上是关于从 Gradle 构建脚本中提取常用方法的主要内容,如果未能解决你的问题,请参考以下文章
Gradle&Maven-Android Gradle 常用命令参数及解释