Gradle任务语法:如何从Groovy角度进行解释?

时间:2019-07-05 16:23:41

标签: gradle groovy dsl

我很难理解Gradle的Groovy DSL的工作原理。

不幸的是,Gradle是我在日常工作中遇到的Groovy的主要用例,而且我已经注意到,对于许多开发人员来说,他们对Groovy的接触严格是通过Gradle进行的。因此,大多数Gradle用户对Groovy的了解非常有限。

在我对Groovy的有限理解中,以下正则表达式tokenA tokenB { tokenC }(其中所有标记都不是语言关键字),tokenA将是我们使用参数tokenB和最终参数调用的方法是一个关闭。我想想我是正确的,但是我知道我错了,因为在令牌B之后可能需要用逗号才能使该分析正确。

正如您已经知道的那样,我绝不是Groovy开发人员,并且我认为在不学习Groovy基础知识的情况下使用Gradle是一件不好的事,因为它限制了我充分利用其功能。但是,我唯一可行的选择是通过示例学习而不不幸地学习理论。

我确实检查了一些类似的问题,例如this one,但对于我来说足够清晰或完整的答案都没有。

TL; DR

  1. 在Groovy中如何解释令牌task myTask { doLast {} }
  2. Gradle是否使用标准的Groovy解释器?
  3. myTask而不是task或后面的类型时,如何将def解释为标识符?
  4. 如果稍后在文件中添加了myTask { dependsOn myOtherTask },该如何解释?

2 个答案:

答案 0 :(得分:1)

(免责声明,我不是一个笨拙的开发人员)

运行构建时(例如gradle clean),将根据build.gradle对象(由Gradle运行程序创建)评估Project的内容;请参见API-Gradle Project上的Javadoc;还请阅读整个摘要,因为其中包含很多信息。他们在该页面中阐明:

  

一个项目有5个方法“作用域”,它会搜索方法:Project对象本身...构建文件...插件通过插件添加到项目中的扩展名... 项目任务 ..为每个任务添加一个方法,使用任务名称作为方法名称...

task myTask { }应该等效于project.task('myTask')。它创建一个名为“ myTask”的新任务,并将该任务添加到当前项目中(请参阅Javadoc)。然后,将一个属性添加到项目对象,以便可以将其作为project.myTask进行访问。 doLast {..}在该任务对象上调用doLast方法;请参见Task-doLast

上的Javadoc

因此,对于您的一些观点:

  1. project.task('myTask').doLast(..)(也许这里有更多关于闭包的信息)
  2. 可以(尝试从github构建);但是还有其他处理;在运行构建之前,将build.gradle文件“注入”到Project实例中。加上许多其他步骤
  3. project.task('myTask')
  4. project.myTask.dependsOn(project.myOtherTask)(可能带有附加的闭包,或涉及到Action实例)。这是由于任务已作为属性添加到项目中。

还要注意,像project.myTask...这样的显式语句是有效的,可以在build.gradle脚本中使用;但是冗长,因此很少使用。

答案 1 :(得分:1)

我相信这很古怪,没有什么特别的。这是您需要了解的常规概念。

  1. 如果方法的最后一个参数是闭包,则可以将闭包放在方法参数的右括号之后。
class MyClass {
   void doStuff(String name, Closure c) {
      c.call()
   } 
} 

def o = new MyClass() 
o.doStuff('x') {
   println "hello" 
} 
  1. 您可以在对象上实现method missing。如果有人尝试调用一个不存在的方法,您可以做些事
class MyClass {
    def methodMissing(String name, args) {
        println "You invoked ${name}(${args})" 
    }
} 
def o = new MyClass() {
   o.thisMethodDoesNotExist('foo')
}
  1. 您可以set the delegate进行关闭
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' 
} 

这3个时髦特性在很大程度上解释了gradle脚本中发生的“魔术”行为,使Java开发人员抓狂了。

所以,让我们分解一下片段

task myTask(type:Foo) { 
   doLast {...} 
}

让我们添加一些括号,并添加隐式项目引用。让我们还将闭包提取到变量

Closure c = { 
   doLast {...} 
}
project.task(project.myTask([type: Foo.class], c)) 

project.myTask(...)方法不存在,并且该行为最终通过methodMissing功能实现。 Gradle会将闭包上的委托设置为任务实例。因此,闭包中的任何方法都将委派给新创建的任务。

最终,这在逻辑上称为

Action<? extends Task> action = { task ->
   task.doLast {...} 
}
project.tasks.create('myTask', Foo.class, action)

请参见TaskContainer.create(String, Class, Action)