2010-03-10 99 views
8

如在the documentation中所述,Gradle使用有向無環圖(DAG)來構建依賴關係圖。根據我的理解,具有獨立的評估和執行週期是構建工具的主要功能。例如Gradle doc指出,這使一些否則將不可能的功能。什麼是Gradle依賴關係圖的實際例子?

我對說明此功能的實際示例很感興趣。什麼是一些依賴圖很重要的用例?我特別感興趣的是來自該領域的個人故事,無論是使用Gradle還是配備類似的工具。

我從一開始就製作這個「社區維基」,因爲它很難評估一個「正確的」答案。

回答

5

這個挑釁性的問題爲最終研究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看起來很棒。感謝您挑釁一些研究!

3

一種example from the same documentation示出了這種方法的功率:

正如我們在全部細節描述後 (參見第30章,構建生命週期) 搖籃具有這樣的配置相和 執行階段。在配置階段Gradle知道應該執行的所有 任務之後。 Gradle 爲您提供了一個鉤子來利用這個 信息。一個用例爲 將檢查是否發佈任務是 部分要執行的任務。 根據不同,您可以將 不同的值分配給某些變量。

換句話說,您可以儘早掛鉤構建過程,以便您可以根據需要更改其過程。如果一些實際的構建工作已經完成,那麼改變可能爲時已晚。

+0

謝謝,回覆!但是,我很熟悉那個例子。我正在尋找一些有點肉的東西。 – 2010-03-18 15:23:44

1

我正在評估不同的構建系統和gradle我設法添加難看的代碼,枚舉'jar'類型的所有任務並更改它們,以便每個jar清單包含'Build-Number'屬性(使用後來組成最終的文件名):

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) 
    } 
}