gradle扩展可以处理属性的惰性评估吗?

Jos*_*non 16 gradle

我正在编写一个自定义gradle插件来处理一些模糊的复杂工作,我在使用属性配置插件应用的一些任务时遇到了令人沮丧的问题.

apply plugin: myPlugin

//Provide properties for the applied plugin
myPluginProps {
    message = "Hello"
}

//Define a task that uses my custom task directly
task thisTaskWorksFine(type: MyTask) {
    input = myPluginProps.message
}

//Define a plugin that will apply a task of my custom type
class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.extensions.create('myPluginProps', MyPluginExtension)

        project.task(type: MyTask, 'thisTaskWorksIncorrectly') {
            input = project.myPluginProps.message
        }
    }
}

//The extension used by my custom plugin to get input
class MyPluginExtension {
    def String message
}

//The task used by both the standard build section and the plugin
class MyTask extends DefaultTask {
    def String input

    @TaskAction
    def action() {
        println "You gave me this: ${input}"
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此文件的结果如下:

$ gradle thisTaskWorksFine thisTaskWorksIncorrectly
:thisTaskWorksFine
You gave me this: Hello
:thisTaskWorksIncorrectly
You gave me this: null

BUILD SUCCESSFUL
Run Code Online (Sandbox Code Playgroud)

我认为这是非常意外的.在我看来,从插件中应用一个任务并直接写一个任务应该在给出相同的输入时产生相同的输出.在这种情况下,两个任务都myPluginProps.message作为输入给出,但插件应用的任务是贪婪的,并且在早期评估为null.(在申请阶段?)

我发现的唯一解决方案是在插件任务的配置块中使用闭包,如下所示:

//Define a plugin that will apply a task of my custom type
class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.extensions.create('myPluginProps', MyPluginExtension)

        project.task(type: MyTask, 'thisTaskWorksIncorrectly') {
            input = { project.myPluginProps.message }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这很好地解决了贪婪的评估问题,现在必须修改自定义任务以期望和处理闭包.这并不是很难做到,但我不认为处理关闭应该是任务的责任,因为插件是"责怪".

我在这里使用扩展程序不正确吗 或者他们只是不够?官方立场似乎是我们应该使用扩展,但我还没有找到任何扩展可以做我需要的例子.我可以继续使用闭包并编写一堆可以处理闭包和普通类型的闭包eval和setter的样板getter,但它似乎非常违反groovy的理念,因此也是gradle.如果有一种方法可以使用扩展并自动获得惰性评估,我将非常高兴.

erd*_*rdi 13

此问题的常见解决方案是使用约定映射:

class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
       project.extensions.create('myPluginProps', MyPluginExtension)

        project.task(type: MyTask, 'thisTaskWorksIncorrectly') {
            conventionMapping.input = { project.myPluginProps.message }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在任务中:

class MyTask extends DefaultTask {
    def String input

    @TaskAction
    def action() {
        println "You gave me this: ${getInput()}"
    }
Run Code Online (Sandbox Code Playgroud)

}

请注意,我明确使用了getter input- 如果您直接引用该字段,则不会启用约定映射.

  • 彼得提到的[公约](http://www.gradle.org/docs/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:convention)是旧机制扩展.不同之处在于您使用扩展免费获得dsl(`myPluginProps {message ="Hello"}`)并且您没有使用约定.约定和约定映射是两种不同的事物,并且[gradle code]内部使用了约定映射(https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/groovy/org/gradle/ api/plugins/JavaPlugin.java#L131)很多. (2认同)

cei*_*ors 13

彼得在我的问题的答案在这里表示conventionMapping功能肯定会消失.最好避免它.

使用afterEvaluate解决延迟配置问题使我的代码比conventionMapping方法更清晰.

class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.extensions.create('myPluginProps', MyPluginExtension)

        project.afterEvaluate {
            project.task(type: MyTask, 'thisTaskWorksIncorrectly') {
                input = project.myPluginProps.message
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)