Gradle';s依赖图?

Gradle';s依赖图?,gradle,Gradle,如中所述,Gradle使用有向无环图(DAG)构建依赖关系图。根据我的理解,拥有独立的评估和执行周期是构建工具的一个主要特性。e、 g.声明这将启用一些原本不可能实现的功能 我对真实世界的例子很感兴趣,这些例子说明了这个特性的威力。依赖关系图对哪些用例很重要?我对来自现场的个人故事特别感兴趣,无论是使用Gradle还是类似的工具 我从一开始就做这个“社区维基”,因为很难评估一个“正确”的答案 An说明了这种方法的威力: 正如我们在后面详细描述的那样 (参见第30章,构建生命周期) Gradle有

如中所述,Gradle使用有向无环图(DAG)构建依赖关系图。根据我的理解,拥有独立的评估和执行周期是构建工具的一个主要特性。e、 g.声明这将启用一些原本不可能实现的功能

我对真实世界的例子很感兴趣,这些例子说明了这个特性的威力。依赖关系图对哪些用例很重要?我对来自现场的个人故事特别感兴趣,无论是使用Gradle还是类似的工具

我从一开始就做这个“社区维基”,因为很难评估一个“正确”的答案

An说明了这种方法的威力:

正如我们在后面详细描述的那样 (参见第30章,构建生命周期) Gradle有一个配置阶段和 执行阶段。之后 配置阶段Gradle无所不知 应该执行的任务。格拉德尔 给你一个钩子来利用这个 信息。这方面的一个用例是 要检查发布任务是否已完成 要执行的部分任务。 根据这一点,您可以指定 对某些变量使用不同的值


换句话说,您可以尽早加入构建过程,以便根据需要更改其过程。如果已经执行了一些实际的构建工作,那么改变可能就太晚了。

这个具有挑衅性的问题为最终研究Gradle提供了动力。我还没有使用它,所以我只能在浏览文档时提供分析记录,而不能提供个人故事

我的第一个问题是为什么Gradle任务依赖关系图保证是非循环的。我没有找到答案,但相反的情况很容易构建,因此我假设循环检测是在构建图时运行的验证,如果存在非法的循环依赖,则在执行第一个任务之前构建失败。如果不首先构建图形,在构建接近完成之前,可能无法发现此故障情况。此外,检测例程必须在每个任务执行后运行,这将非常低效(只要以增量方式构建图表并在全球范围内可用,则只需进行深度优先搜索即可找到起点,随后的周期评估将需要最少的工作量,但总工作量仍将大于在开始时对整个关系集进行单一缩减).我认为早期发现是一大好处

任务依赖关系可能是惰性的(请参阅:4.3任务依赖关系,以及13.14中的相关示例)。在构建整个图之前,无法正确计算惰性任务依赖关系。对于可传递(非任务)也是如此依赖项解析,这可能会导致无数问题,并且在发现和解析其他依赖项时需要重复重新编译(也需要重复请求存储库)。任务规则功能(13.8)也不可能。考虑到Gradle使用动态语言,并且可以动态添加和修改任务,这些问题以及其他许多问题都可以概括,因此在第一次通过评估之前,结果可能是不确定的,因为执行路径是在运行时构建和修改的,因此,不同的评估序列如果有依赖项或行为指令直到后来才知道,因为它们还没有被创建,评估可能会产生任意不同的结果。(这可能值得用一些具体的例子来研究。如果这是真的,那么即使两次通过也不总是足够的。如果A->B,B->C,其中C改变了A的行为,使其不再依赖于B,那么您就有问题了。我希望有一些最佳实践来限制非局部范围的元编程,以避免不允许一个有趣的例子是模拟时间旅行悖论,孙子杀死祖父或娶祖母,生动地说明了一些实用的道德原则!)

它可以在当前正在执行的构建上实现更好的状态和进度报告。TaskExecutionListener提供了处理每个任务的前/后挂钩,但在不知道剩余任务数的情况下,除了“6个任务已完成。即将执行任务foo”之外,它对状态没有什么可说的相反,您可以使用gradle.taskGraph.whenReady中的任务数初始化TaskExecutionListener,然后将其附加到TaskExecutionGraph。现在,它可以提供信息以启用报告详细信息,如“已完成72项任务中的6项。正在执行任务foo。估计剩余时间:2h 38m。”这对于在控制台上显示持续集成服务器非常有用,或者如果Gradle被用于协调大型多项目构建,那么时间估计至关重要

正如Jerry Bullard所指出的,生命周期的评估部分对于确定执行计划至关重要,执行计划提供了有关环境的信息,因为环境部分由执行上下文决定(在“按DAG配置”一节中的示例4.15)。此外,我可以看到这对执行优化很有用。独立的子路径可以安全地传递给不同的线程。如果执行的步行算法不幼稚,那么它们的内存占用会更少(我的直觉告诉我,总是沿着子路径最多的路径行走会比总是选择子路径最少的路径产生更大的堆栈)

这种方法的一个有趣用途可能是,一个系统的许多组件最初都被删除以支持演示和增量开发。然后在开发过程中,构建本身可以确定子项目是否准备好包含,而不是在每个组件实现时更新构建配置(也许它试图
gradle.taskGraph.whenReady {
    taskGraph ->
    taskGraph.getAllTasks().findAll {
        it instanceof org.gradle.api.tasks.bundling.Jar
    }.each {
        it.getManifest().getAttributes().put('Build-Number', project.buildVersion.buildNumber)
    }
}