为什么PropertyState是必要的

时间:2017-08-17 01:05:34

标签: gradle

假设我正在开发一个Gradle插件,并且插件配置的一些任务的输入取决于它是如何通过扩展配置的。例如:

class MyTask extends DefaultTask {
    @InputFile
    File toTrack

    @TaskAction
    def run() {
        println("The file now contains ${toTrack.text}")
    }
}

class MyConfig {
    File toTrack = new File('bad-default.txt')
}

class MyPlugin implements Plugin<Project> {
    @Override
    def apply(Project project) {
        project.with {
            extensions.create('config', MyConfig)
            task('printChanges', type: MyTask) {
                toTrack = config.toTrack
            }
        }
     }
}

不幸的是,这不能正常工作。问题是,如果我有一个build.gradle,如:

apply plugin: my-plugin

config {
   toTrack = file('file-to-track.txt')
}

我已经指定了要跟踪的文件,Gradle会在@InputFile块运行之前评估我的任务上的config,以便它决定是否执行任务通过查看bad-default.txt而不是file-to-track.txt来获取最新信息。

建议的解决方法似乎是使用PropertyState,如下所示:

class MyTask extends DefaultTask {
    PropertyState<File> toTrack = project.property(File)

    @InputFile
    File getToTrack { return toTrack.get() }

    @TaskAction
    def run() {
        println("The file now contains ${toTrack.get().text}")
    }
}

class MyConfig {
    private PropertyState<File> toTrack 

    MyConfig(Project project) {
        toTrack = = project.property(File)
        toTrack.set('bad-default.txt')
    }

    void setToTrack(File fileToTrack) { toTrack.set(fileToTrack) }
}

class MyPlugin implements Plugin<Project> {
    @Override
    def apply(Project project) {
        project.with {
            extensions.create('config', MyConfig)
            task('printChanges', type: MyTask) {
                toTrack = config.toTrack
            }
        }
     }
}

虽然有效,但看起来非常冗长,PropertyState的东西似乎完全没必要。看起来真正的修复只是将@InputFile注释更改为getter而不是将其置于属性上。换句话说,我相信以下内容具有相同的效果,代码更少且更易于理解:

class MyTask extends DefaultTask {
    File toTrack

    // This is the only change: put the annotation on a getter
    @InputFile
    File getToTrack() { return toTrack }

    @TaskAction
    def run() {
        println("The file now contains ${toTrack.text}")
    }
}

class MyConfig {
    File toTrack = new File('bad-default.txt')
}

class MyPlugin implements Plugin<Project> {
    @Override
    def apply(Project project) {
        project.with {
            extensions.create('config', MyConfig)
            task('printChanges', type: MyTask) {
                toTrack = config.toTrack
            }
        }
     }
}

通过一些实验,这似乎确实具有预期的效果。我错过了什么?是否有必要PropertyState

1 个答案:

答案 0 :(得分:2)

问题不在于评估时间@InputFile@InputFile在执行任务之前进行评估,因此配置阶段完成后渐变执行阶段。问题PropertyState正在解决的问题是扩展和任务之间的连接。

让我们再看看你的申请方法:

def apply(Project project) { project.with { extensions.create('config', MyConfig) task('printChanges', type: MyTask) { toTrack = config.toTrack } } }

在这里:

1)使用MyConfig类中提供的默认值创建自定义扩展。

2)将MyConfig中设置的值当前链接到MyTask toTrack属性。

现在查看插件用法:

apply plugin: my-plugin

config {
    toTrack = file('file-to-track.txt')
}

在这里:

1)应用插件(基本上执行插件的apply方法)。

2)重新配置MyConfig#toTrack扩展名属性。

但是这里没有发生的事情是更新printChanges任务中的值。这就是PropertyState正在解决的问题。它与任务输入和输出评估没有任何关系。