假设我正在开发一个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
?
答案 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
正在解决的问题。它与任务输入和输出评估没有任何关系。