如何在 Gradle 中迭代所有已注册的任务?



在我们的 Gradle(使用 Gradle 6.4.1(项目中,启用了按需配置。这意味着在项目的配置阶段不会配置任务。例如,这意味着subproject/build.gradleprintln(project.tasks)语句可能仅打印子项目中存在的某些任务。

我想以编程方式在所有项目中按名称查找所有任务。我当前的代码只是迭代allprojects

def foobar(Project rootProject, String name) {
Collection<String> paths = rootProject.allprojects.findResults { Project p ->
return p.tasks.findByName(name)?.getPath()
}
return paths
}

方法foobar()由自定义 Gradle 插件调用,以设置复杂的依赖关系图。此图包括:"taskFoobardependOnallprojects中名为name的所有任务"。这是插件的行为类似于 Gradle 本身的 CLI 行为方式所必需的:

您还可以使用仅包含任务名称的任务选择器为所有子项目运行任务。例如,当从根项目目录调用时,这将对所有子项目运行"test"任务:

$ gradle test

这就是为什么需要这种程序化迭代的原因。请注意,foobar()是在rootProject.afterEvaluate块中调用的。

但是,由于按需配置功能,某些子项目中的某些任务在集合paths中丢失,因为它们尚未"配置",仅"已注册"。

在调查期间,我研究了内置任务tasks的工作原理。类TaskReportTask使用内部 Gradle API,称为ProjectTaskLister,其实现DefaultProjectTaskLister调用另一个内部 API,即接口TaskContainerInternal的方法realize()

/**
* Force the task graph to come into existence.
*/
void realize();

如何确保所有"已注册"的任务都可以在不使用这个内部 Gradle API 的情况下进行迭代?

如果不需要设置新的依赖项,则可以改用rootProject.getGradle().projectsEvaluated()。这将确保在调用foobar()时评估所有项目,而不仅仅是rootProject

方法 foobar(( 由自定义 Gradle 插件调用,以设置复杂的依赖关系图。

如果在评估完所有项目后确实需要更改依赖项图,很遗憾,您不能使用rootProject.getGradle().projectsEvaluated().此挂钩在构建的生命周期中执行得太晚 - 此时所有依赖项都是固定的。

但是,您可以像这样滚动自己的听众:

static void whenAllProjectsEvaluated(Project rootProject, Closure action) {
final AtomicInteger counter = new AtomicInteger()
final int allProjectsCount = rootProject.getAllprojects().size()
rootProject.allprojects { p ->
p.afterEvaluate {
final int currentEvaluatedCount = counter.incrementAndGet()
rootProject.logger.lifecycle("${p.name} - afterEvaluate (${currentEvaluatedCount}/$allProjectsCount")
if (currentEvaluatedCount == allProjectsCount) {
action.call()
}
}
}
}

需要AtomicInteger才能允许并行生成。然后,此方法可以调用为:

whenAllProjectsEvaluated(project) {
foobar(...)
}

最新更新