【问题标题】:How can I get Gradle to build dependencies before running my task?如何在运行任务之前让 Gradle 构建依赖项?
【发布时间】:2020-11-17 11:42:37
【问题描述】:

背景:我正在尝试将我自己的特定领域语言的编译器挂接到 Gradle 中。 DSL 被编译为 Java 源代码,所以我构建了一个在 Java 编译器之前运行的任务。编译器目前无法处理具有依赖关系的多个项目,所以我正在尝试添加它。

我的 DSL 有像 Java 这样的包,它们被映射到相同的 Java 包。项目也应该如此。在这种情况下,对于每个项目,DSL 源都被编译为 Java 源代码以及元数据(每个编译类的 JSON 文件,包含来自 DSL 类型系统的信息,这些信息无法映射到 Java 类型)。当项目 A 依赖于 B 时,A 的 DSL 编译过程需要来自 B 的元数据文件。该元数据应作为资源与生成和编译的 Java 代码一起打包到 JAR 文件中,可能还需要手动打包。编写和编译的 Java 代码。

FoobarPlugin.groovy:

class FoobarPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {

        // create the compileFoobar task
        CompileFoobarTask task = project.getTasks().create('compileFoobar', CompileFoobarTask.class);
        task.group = 'build';
        task.setDescription('Compiles Foobar to Java code.');
        task.sourceDirectory = new File(project.projectDir, "src/main/foobar");
        task.outputDirectory = new File(project.getBuildDir(), "foobar-java");

        // compileFoobar must run before compiling Java code
        project.tasks.compileJava.dependsOn(task);

        // add the task's output folders as Java source folders
        project.sourceSets.main.java.srcDirs += task.outputDirectory;
        project.sourceSets.main.resources.srcDirs += task.outputDirectory;
        project.sourceSets.test.java.srcDirs += task.outputDirectory;
        project.sourceSets.test.resources.srcDirs += task.outputDirectory;

        // Turn project dependencies into task dependencies. We have to delay this until the end of the configuration
        // phase because project dependencies are not fully known until then.
        project.gradle.addBuildListener(new BuildAdapter() {
            @Override
            void projectsEvaluated(Gradle gradle) {
                project.configurations.compile.each {
                    task.dependencyOutputs += it
                }
            }
        });

    }

}

编译FoobarTask.groovy:

class CompileFoobarTask extends DefaultTask {

    @InputDirectory
    File sourceDirectory;

    @InputFiles
    List<File> dependencyOutputs = new ArrayList<>();

    @OutputDirectory
    File outputDirectory;

    @TaskAction
    void run() {
        FileUtils.write(new File(outputDirectory, "timestamp"), "" + System.currentTimeMillis(), StandardCharsets.UTF_8);
    }

}

来自项目 A 的 build.gradle:

apply plugin: 'java'
apply plugin: foobar.gradle.FoobarPlugin

repositories {
    mavenCentral()
}

dependencies {
    compile project(':b')
}

来自项目 B 的 build.gradle:

apply plugin: 'java'
apply plugin: foobar.gradle.FoobarPlugin

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.0'
}

测试运行和输出:

martin@xyz:~/git-repos/gradle-test$ ./gradlew clean a:compileFoobar
adding dependency /home/martin/git-repos/gradle-test/b/build/libs/b.jar to task task ':a:compileFoobar'

> Task :a:compileFoobar
running task ':a:compileFoobar'

BUILD SUCCESSFUL in 1s
4 actionable tasks: 2 executed, 2 up-to-date


martin@xyz:~/git-repos/gradle-test$ ./gradlew clean b:compileFoobar
adding dependency /home/martin/git-repos/gradle-test/b/build/libs/b.jar to task task ':a:compileFoobar'

> Task :b:compileFoobar
running task ':b:compileFoobar'

BUILD SUCCESSFUL in 469ms
4 actionable tasks: 2 executed, 2 up-to-date


martin@xyz:~/git-repos/gradle-test$ ./gradlew clean a:compileJava
adding dependency /home/martin/git-repos/gradle-test/b/build/libs/b.jar to task task ':a:compileFoobar'

> Task :a:compileFoobar
running task ':a:compileFoobar'

> Task :b:compileFoobar
running task ':b:compileFoobar'

BUILD SUCCESSFUL in 487ms
7 actionable tasks: 5 executed, 2 up-to-date


martin@xyz:~/git-repos/gradle-test$ ./gradlew clean b:compileJava
adding dependency /home/martin/git-repos/gradle-test/b/build/libs/b.jar to task task ':a:compileFoobar'

> Task :b:compileFoobar
running task ':b:compileFoobar'

BUILD SUCCESSFUL in 471ms
4 actionable tasks: 3 executed, 1 up-to-date

如您所见,即使我将 b.jar 作为依赖项添加到 a:compileFoobar,Gradle 也不会在运行 a:compileFoobar 之前构建该 JAR。 Java 插件似乎做了一些不同的事情,因为运行 a:compileJava 将首先构建 b.jar。为了完成我的任务,我必须做些什么?

【问题讨论】:

    标签: gradle plugins dependencies


    【解决方案1】:

    您需要做的是在消费者项目的 compileFoobar 任务和生产者项目的 jar 任务之间显式创建 任务依赖(在您的示例中,project a 依赖于 project b ,需要创建任务依赖a:compileFoobar -&gt; b.jar)

    您可以在自定义插件中实现这一点,方法是检查当前项目是否具有 ProjectDependency 类型的依赖项:如果是,则相应地创建任务依赖项。

    代码示例(在您的插件apply() 方法中):

            // Turn project dependencies into task dependencies. We have to delay this until the end of the configuration
            // phase because project dependencies are not fully known until then.
            project.gradle.addBuildListener(new BuildAdapter() {
                @Override
                void projectsEvaluated(Gradle gradle) {
                    project.configurations.each { config ->
                        config.dependencies.each { dep ->
                            if (dep instanceof ProjectDependency) {
                                def producerProject = ((ProjectDependency) dep).dependencyProject
                                def producerJarTask = producerProject.tasks.jar
                                println " **** Project $project.name depends on $producerProject.name"
                                println "      => create dependency between $task to $producerJarTask"
                                task.dependsOn(producerJarTask)
                            }
                        }
                    }
                }
            })
    

    构建执行:

    $  ./gradlew clean a:compileFoobar
     **** Project a depends on b
          => create dependency between task ':a:compileFoobar' to task ':b:jar'
    > Task :a:clean
    > Task :b:clean
    > Task :b:compileFoobar
    > Task :b:compileJava NO-SOURCE
    > Task :b:processResources NO-SOURCE
    > Task :b:classes UP-TO-DATE
    > Task :b:jar
    > Task :a:compileFoobar
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 2018-02-27
      • 1970-01-01
      • 2019-07-12
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      相关资源
      最近更新 更多