java - 如何将我的 Gradle 插件中的任务执行链接到另一个插件的输出文件?

标签 java gradle gradle-plugin

我正在尝试为 Gradle 编写一个插件,该插件将使用执行另一个任务的文件结果执行一些操作(在另一个插件中定义 - java-library-distribution )。我可以通过 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 开头的方法。 .通常它是一种返回(私有(private))字段值的方法。在您的示例中,有一个名为 fi 的字段, 所以相应的 getter 方法 getFi应该只返回该字段的值。顺便说一句,在您当前的代码中,字段 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.

    如您所见,您的任务需要定义输出以被认为是最新的。您可以像定义输入文件一样定义输出文件(字段、带有 @OutputFile 的 getter 和 setter)。它们应该是可配置的,并且默认为 build 中的文件。目录。或者,您可以使用 onlyIf实现自定义检查是否应运行任务。如果 onlyIf 中的谓词返回 false ,任务将是 SKIPPED .
  • 关于java - 如何将我的 Gradle 插件中的任务执行链接到另一个插件的输出文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64258735/

    相关文章:

    java - 如何从 Eclipse 内部找出我的应用程序正在使用哪个端口?

    android - 迭代执行任务

    android - 二维产品口味,Android Studio?

    java - 如何在我的 gradle java 项目中包含外部 .jar?

    java - 从自定义 Gradle Java 插件应用 gradle 插件(容易出错)

    java - Spring JPA/Hibernate 事务强制插入而不是更新

    java - Android Textview 文本在底部被截断

    java - Hadoop 运行 WordCount 失败

    android - 升级到新版flutter时出现 “:app:transformClassesWithDexBuilderForDebug”错误

    java - 项目gradle插件的加载类路径应用于