如何将我的 Gradle 插件中的任务执行 link 输出到另一个插件的输出文件?
How to link the task execution in my Gradle plugin to the output file of another plugin?
我正在尝试为 Gradle 编写一个插件,它将使用执行另一个任务(在另一个插件 - java-library-distribution
中定义)的文件结果执行一些操作。我可以在我的任务 class.
中通过 this.getProject().getTasks().getByName("distZip").getOutputs().getFiles().getSingleFile()
轻松获取我需要的文件
但是用这种方法,我的任务每次都会执行,不管文件是否在更高级别的任务中发生变化。
我将 getter 方法注释为 @InputFile
。但不幸的是 Gradle 仍然没有将问题标记为 UP-TO-DATE
.
public class YcfPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getExtensions().create("ycf", YcfPluginExtension.class);
project.getPluginManager().apply("java-library-distribution");
project.getTasks().register("ycfCreateVersion", YcfTaskCreateVersion.class);
}
}
abstract class YcfTask extends DefaultTask {
public static final String TASK_GROUP = "Some Description";
YcfPluginExtension ycfExtension = this.getProject().getExtensions().getByType(YcfPluginExtension.class);
Logger logger = this.getProject().getLogger();
public YcfTask() {
this.setGroup(TASK_GROUP);
}
}
public class YcfTaskCreateVersion extends YcfTask {
private File fi;
public YcfTaskCreateVersion() {
this.setDescription("Some description");
this.dependsOn(this.getProject().getTasks().getByName("distZip"));
}
@InputFile
public File getFi() {
return this.getProject().getTasks().getByName("distZip").getOutputs().getFiles().getSingleFile();
}
@TaskAction
public void run() {
byte[] bytes = Files.readAllBytes(getFi().toPath());
//..do something with file content
}
}
您目前的做法存在一些误解:
@InputFile
注释应该用在 getter 方法上。 getter 方法不仅仅是以前缀 get
开头的方法。通常它是 return 一个(私有)字段的值的方法。在您的示例中,有一个名为 fi
的字段,因此相应的 getter 方法 getFi
应该只是 return 该字段的值。顺便说一下,在您当前的代码中,字段 fi
根本没有被使用。
很高兴您知道应该使用什么值作为任务的输入 (getProject().getTasks().getByName("distZip").getOutputs().getFiles().getSingleFile()
),但这不应该是任务类型实现的一部分。相反,任务类型应该尽可能可配置。然后,您可以在插件代码中创建和配置此任务类型的一个实例:
public class YcfTaskCreateVersion extends YcfTask {
private File fi;
@InputFile
public File getFi() {
return fi;
}
public void setFi(File fi) {
this.fi = fi;
}
@TaskAction
public void run() {
// ...
}
}
public class YcfPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
// ...
YcfTaskCreateVersion createVersionTask = project.getTasks()
.register("ycfCreateVersion", YcfTaskCreateVersion.class);
createVersionTask.setFi(project.getTasks().getByName("distZip")
.getOutputs().getFiles().getSingleFile());
}
}
遗憾的是,上面的代码无法运行,因为在创建任务时(应用插件时),任务的输出 distZip
(甚至可能任务)将不可用。但这不是什么大问题,因为 Gradle 支持这种用例。您可以将字段的类型更改为 Object
,这样不仅可以传入类型 File
的对象。无论是否传递文件(或可能转换为文件的内容),都会在任务执行时被检查。
public class YcfTaskCreateVersion extends YcfTask {
private Object fi;
@InputFile
public Object getFi() {
return fi;
}
public void setFi(Object fi) {
this.fi = fi;
}
@TaskAction
public void run() {
File file = getProject().files(fi).getSingleFile();
// do something with file
}
}
此设置有一个很酷的地方:您可以直接传递任务 distZip
,Gradle 将自动提取文件输出。它甚至会检测到您正在使用一个任务的输出作为另一个任务的输入,因此 Gradle 将自动设置两个任务之间的任务依赖关系,您不必再使用 dependsOn
:
createVersionTask.setFi(project.getTasks().getByName("distZip"));
让我们检查一下 Gradle documentation on task outcomes。在 UP-TO-DATE
:
上有一节
Task’s outputs did not change.
- Task has outputs and inputs and they have not changed. See Incremental Builds.
- Task has actions, but the task tells Gradle it did not change its outputs.
- Task has no actions and some dependencies, but all of the dependencies are up-to-date, skipped or from cache. See also Lifecycle Tasks.
- Task has no actions and no dependencies.
如您所见,您的任务需要定义要考虑的输出 up-to-date。您可以使用与输入文件相同的方式定义输出文件(字段,getter 与 @OutputFile
和 setter)。它们应该是可配置的,并且默认为 build
目录中的一个文件。或者,您可以使用 onlyIf
来实现自定义检查任务是否应为 运行。如果onlyIf
里面的谓词returns false
,任务就会是SKIPPED
.
我正在尝试为 Gradle 编写一个插件,它将使用执行另一个任务(在另一个插件 - java-library-distribution
中定义)的文件结果执行一些操作。我可以在我的任务 class.
this.getProject().getTasks().getByName("distZip").getOutputs().getFiles().getSingleFile()
轻松获取我需要的文件
但是用这种方法,我的任务每次都会执行,不管文件是否在更高级别的任务中发生变化。
我将 getter 方法注释为 @InputFile
。但不幸的是 Gradle 仍然没有将问题标记为 UP-TO-DATE
.
public class YcfPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getExtensions().create("ycf", YcfPluginExtension.class);
project.getPluginManager().apply("java-library-distribution");
project.getTasks().register("ycfCreateVersion", YcfTaskCreateVersion.class);
}
}
abstract class YcfTask extends DefaultTask {
public static final String TASK_GROUP = "Some Description";
YcfPluginExtension ycfExtension = this.getProject().getExtensions().getByType(YcfPluginExtension.class);
Logger logger = this.getProject().getLogger();
public YcfTask() {
this.setGroup(TASK_GROUP);
}
}
public class YcfTaskCreateVersion extends YcfTask {
private File fi;
public YcfTaskCreateVersion() {
this.setDescription("Some description");
this.dependsOn(this.getProject().getTasks().getByName("distZip"));
}
@InputFile
public File getFi() {
return this.getProject().getTasks().getByName("distZip").getOutputs().getFiles().getSingleFile();
}
@TaskAction
public void run() {
byte[] bytes = Files.readAllBytes(getFi().toPath());
//..do something with file content
}
}
您目前的做法存在一些误解:
@InputFile
注释应该用在 getter 方法上。 getter 方法不仅仅是以前缀get
开头的方法。通常它是 return 一个(私有)字段的值的方法。在您的示例中,有一个名为fi
的字段,因此相应的 getter 方法getFi
应该只是 return 该字段的值。顺便说一下,在您当前的代码中,字段fi
根本没有被使用。很高兴您知道应该使用什么值作为任务的输入 (
getProject().getTasks().getByName("distZip").getOutputs().getFiles().getSingleFile()
),但这不应该是任务类型实现的一部分。相反,任务类型应该尽可能可配置。然后,您可以在插件代码中创建和配置此任务类型的一个实例:public class YcfTaskCreateVersion extends YcfTask { private File fi; @InputFile public File getFi() { return fi; } public void setFi(File fi) { this.fi = fi; } @TaskAction public void run() { // ... } } public class YcfPlugin implements Plugin<Project> { @Override public void apply(Project project) { // ... YcfTaskCreateVersion createVersionTask = project.getTasks() .register("ycfCreateVersion", YcfTaskCreateVersion.class); createVersionTask.setFi(project.getTasks().getByName("distZip") .getOutputs().getFiles().getSingleFile()); } }
遗憾的是,上面的代码无法运行,因为在创建任务时(应用插件时),任务的输出
distZip
(甚至可能任务)将不可用。但这不是什么大问题,因为 Gradle 支持这种用例。您可以将字段的类型更改为Object
,这样不仅可以传入类型File
的对象。无论是否传递文件(或可能转换为文件的内容),都会在任务执行时被检查。public class YcfTaskCreateVersion extends YcfTask { private Object fi; @InputFile public Object getFi() { return fi; } public void setFi(Object fi) { this.fi = fi; } @TaskAction public void run() { File file = getProject().files(fi).getSingleFile(); // do something with file } }
此设置有一个很酷的地方:您可以直接传递任务
distZip
,Gradle 将自动提取文件输出。它甚至会检测到您正在使用一个任务的输出作为另一个任务的输入,因此 Gradle 将自动设置两个任务之间的任务依赖关系,您不必再使用dependsOn
:createVersionTask.setFi(project.getTasks().getByName("distZip"));
让我们检查一下 Gradle documentation on task outcomes。在
上有一节UP-TO-DATE
:Task’s outputs did not change.
- Task has outputs and inputs and they have not changed. See Incremental Builds.
- Task has actions, but the task tells Gradle it did not change its outputs.
- Task has no actions and some dependencies, but all of the dependencies are up-to-date, skipped or from cache. See also Lifecycle Tasks.
- Task has no actions and no dependencies.
如您所见,您的任务需要定义要考虑的输出 up-to-date。您可以使用与输入文件相同的方式定义输出文件(字段,getter 与
@OutputFile
和 setter)。它们应该是可配置的,并且默认为build
目录中的一个文件。或者,您可以使用onlyIf
来实现自定义检查任务是否应为 运行。如果onlyIf
里面的谓词returnsfalse
,任务就会是SKIPPED
.