什么是Gradle依赖图的真实示例?

Mic*_*ter 9 gradle

文档所述,Gradle使用有向非循环图(DAG)来构建依赖图.根据我的理解,具有单独的评估和执行周期是构建工具的主要特征.例如,Gradle doc声明这可以实现一些本来不可能的功能.

我对真实世界的例子感兴趣,这些例子说明了这个功能的强大功能.依赖图重要的一些用例是什么?我对这个领域的个人故事特别感兴趣,无论是使用Gradle还是使用类似的工具.

我从一开始就制作这个"社区维基",因为很难评估"正确"的答案.

小智 6

这个挑衅性的问题为最终研究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.估计剩余时间:2小时38分钟." 这对于在持续集成服务器的控制台上显示是有用的,或者如果Gradle用于编排大型多项目构建并且时间估计是至关重要的.

正如Jerry Bullard所指出的,生命周期的评估部分对于确定执行计划至关重要,执行计划提供有关环境的信息,因为环境部分由执行上下文决定("配置DAG"部分中的示例4.15).另外,我可以看到这对执行优化很有用.独立的子路径可以安全地传递给不同的线程.如果执行的行走算法不是天真的话,那么执行它们的内存密集程度会更低(我的直觉说总是沿着大多数子路径行走的路径将导致更大的堆栈,而不是总是更喜欢具有最少子路径的路径).

一个有趣的用途可能是这样一种情况,即系统的许多组件最初被删除以支持演示和增量开发.然后在开发期间,而不是在每个组件实现时更新构建配置,构建本身可以确定子项目是否已准备好包含(可能它尝试获取代码,编译它,并运行预定的测试套件) .如果是,评估阶段将揭示这一点,并且将包括适当的任务,否则,它选择存根的任务.也许依赖于尚未提供的Oracle数据库,同时您正在使用嵌入式数据库.您可以让构建检查可用性,在可能的情况下透明地切换,并告诉您它切换了数据库,而不是您告诉它.沿着这些方向可能会有很多创造性的用途.

Gradle看起来很棒.谢谢你挑起一些研究!