我很难理解 Gradle 的 Groovy DSL 是如何工作的。
不幸的是,Gradle 是我在日常工作中遇到的 Groovy 的主要用例,而且我注意到对于许多开发人员来说,他们对 Groovy 的接触完全是通过 Gradle 进行的。因此,大多数 Gradle 用户对 Groovy 的掌握非常有限。
在我对 Groovy 的有限理解中,以下tokenA tokenB { tokenC }所有标记都不是语言关键字的语法tokenA将是我们使用参数调用的方法,tokenB最后一个参数是闭包。我想我是对的,但我知道我错了,因为在 tokenB 之后可能需要有一个逗号才能使分析正确。
正如您已经知道的那样,我绝不是 Groovy 开发人员,而且我认为在不学习 Groovy 基础知识的情况下使用 Gradle 是一件坏事,因为它限制了我充分利用其功能。但不幸的是,我唯一可行的选择是通过例子学习而不学习理论。
我没有检查出像一些类似的问题,这一次却没有答案,其中明确或完全够我。
TL; 博士
task myTask { doLast {} }在 Groovy 中如何解释令牌?myTask当它背后有task和没有def或类型时如何解释为标识符?myTask { dependsOn myOtherTask }如何解释?我相信这一切都很时髦,gradle 没什么特别的。这是您需要了解的常规概念。
class MyClass {
void doStuff(String name, Closure c) {
c.call()
}
}
def o = new MyClass()
o.doStuff('x') {
println "hello"
}
Run Code Online (Sandbox Code Playgroud)
class MyClass {
def methodMissing(String name, args) {
println "You invoked ${name}(${args})"
}
}
def o = new MyClass() {
o.thisMethodDoesNotExist('foo')
}
Run Code Online (Sandbox Code Playgroud)
class MyBean {
void include(String pattern) {...}
void exclude(String pattern) {...}
}
class MyClass {
private MyBean myBean = new MyBean()
void doStuff(Closure c) {
c.setDelegate(myBean)
c.call()
}
}
def o = new MyClass()
o.doStuff {
include 'foo'
exclude 'bar'
}
Run Code Online (Sandbox Code Playgroud)
这 3 个 groovy 特性几乎解释了 gradle 脚本中发生的“神奇”行为,这些行为让 Java 开发人员摸不着头脑。
所以,让我们分解你的片段
task myTask(type:Foo) {
doLast {...}
}
Run Code Online (Sandbox Code Playgroud)
让我们添加一些括号并添加隐式项目引用。让我们也将闭包提取到一个变量中
Closure c = {
doLast {...}
}
project.task(project.myTask([type: Foo.class], c))
Run Code Online (Sandbox Code Playgroud)
该project.myTask(...)方法不存在,行为最终通过methodMissing功能实现。Gradle 会将闭包上的委托设置为任务实例。所以闭包中的任何方法都将委托给新创建的任务。
最终,这就是逻辑上所说的
Action<? extends Task> action = { task ->
task.doLast {...}
}
project.tasks.create('myTask', Foo.class, action)
Run Code Online (Sandbox Code Playgroud)
参见TaskContainer.create(String, Class, Action)
(免责声明,我不是一个出色的开发人员)
运行构建时(例如),将针对对象(由 Gradle 运行程序创建)评估gradle clean内容;请参阅API-Gradle 项目中的 Javadoc ;还要阅读整个摘要,因为它包含很多信息。在该页面中,他们澄清了这一点:build.gradleProject
一个项目有 5 个方法“范围”,它会搜索方法: 项目对象本身 ... 构建文件 ... 通过插件添加到项目的扩展 ...项目的任务.. 添加一个方法对于每个任务,使用任务名称作为方法名称...
task myTask { }应该相当于project.task('myTask'). 它创建一个名为“myTask”的新任务并将该任务添加到当前项目(请参阅 Javadoc)。然后,将一个属性添加到项目对象中,以便可以将其作为project.myTask. doLast {..}调用doLast该任务对象上的方法;请参阅Task-doLast中的 Javadoc
因此,对于您的一些观点:
project.task('myTask').doLast(..)(也许这里有更多关于闭包的信息)build.gradle在运行构建之前,该文件被“注入”到项目实例中。加上很多其他步骤project.task('myTask')project.myTask.dependsOn(project.myOtherTask)(可能需要额外的闭包或涉及 Action 实例)。这是因为任务作为属性添加到项目中。另请注意,显式语句(如)project.myTask...是有效的,并且可以在build.gradle脚本中使用;但它们很冗长,所以很少使用。
| 归档时间: |
|
| 查看次数: |
640 次 |
| 最近记录: |