Clojure

Dep 擴充

此頁面深入探討 Clojure 工具和 tools.deps 如何將一組根部 dep 擴充為傳遞依賴項的集合。此演算法類似於 Maven dep 擴充(兩者都是廣度優先樹狀擴充),它們在版本選擇上做出不同的選擇。

擴充

擴充輸入

  • 初始依賴項 - 各個依賴項定義為 lib(符號)和座標(maven、git、local 等)

  • default-deps - 如果未提供座標,則使用 lib 到 coord 的對應

  • override-deps - 如果找到 lib,則使用 lib 到 coord 的對應

擴充程序會迴圈處理樹狀結構中路徑的佇列。初始佇列包含到根依賴項的單一路徑。

在迴圈的每個步驟中,我們會從佇列中拉出一個路徑(以依賴項結尾)進行考量。如果需要,會使用預設和覆寫依賴項來取代要與依賴項一起使用的座標。然後,我們會考量這個 lib/coord,並決定是否要包含或排除在選取中,並記錄原因代碼以供稍後了解。如果節點有子節點,則會將它們新增到佇列中。

在整個迴圈中,我們會追蹤版本對應中的所有 lib、已見過的版本和選取選項,以及排除對應中的排除項。如果需要,會在擴充追蹤中記錄每個考量,以及節點是否包含以及原因。

所有選取都是在單次通過樹狀結構時進行的。主線擴充是單執行緒的,但是,擷取依賴項的子節點可能需要從外部網路來源(例如從 Maven 儲存庫要求 pom)擷取它們。為了提升效能,會使用執行緒池在需要之前平行擷取元資料。

依賴項選取

在考量節點是否選取時,如果符合下列條件,則會包含 lib

  • 它是頂層依賴項(頂層依賴項版本永遠會獲勝),或者它是新的 lib 或已知 lib 的較新版本(Maven 僅保留第一個找到的版本,不論新舊)

  • 而且它未在這個節點路徑的其中一個父項中排除(請參閱下列的排除部分)

  • 而且路徑中的所有父節點都已選取(請參閱下列的孤立部分)

如果包含 lib/version,則會在版本對應中標記為已選取。

排除

排除會標記在樹狀結構節點的子節點上,並套用到該子依賴項及其子節點。排除會記錄在排除映射中,並在檢查是否要包含樹狀結構中該點以下的程式庫時使用。

特別棘手的案例發生在同一個程式庫和版本在樹狀結構的不同點出現,且具有不同的排除設定。在這些案例中,該程式庫使用的排除會是兩個排除設定的交集

例如,針對像這樣的樹狀結構

A
  B
    C (excl X, Y)
      X
      Y
      Z
  D
    C (excl X)
      X
      Y
      Z

C 將只排除 X(#{X Y} 和 #{X} 的交集),因為 A-D-C 分支需要該依賴項!

同樣重要的是,在考慮路徑 A-B-C 時,它只會將 Z 加入佇列作為子依賴項(因為 X 和 Y 已排除)。在考慮 A-D-C 時,它會縮小 C 的排除設定,並將 Y 標記為要包含,作為 C 的新子項進行擴充。請注意,無論先考慮 A-B-C 或 A-D-C,擴充順序可能會不同,但會針對包含做出相同的最終選擇。

孤立

在擴充大型樹狀結構時,我們可能會將特定程式庫版本的子項加入佇列,然後稍後找到並選取具有不同依賴項設定的較新程式庫版本。在此案例中,原始程式庫版本節點會被取消選取,但其子項可能仍會在佇列中。

當遇到這些子項時,只有在所有父節點仍被選取時,才會將其包含。

例如,針對像這樣的樹狀結構

A
  B
    C1
      X
  D
    C2
      Y

追蹤可能會顯示

  • A - 包含 A,頂層依賴項

  • A-B - 包含 B,新程式庫

  • A-D - 包含 D,新程式庫

  • A-B-C1 - 包含 C1,新程式庫(將 X、Y 加入佇列)

  • A-D-C2 - 包含 C2,較新版本(+ 取消選取 C1)

  • A-B-C1-X - 排除 X,父項已略過

  • A-D-C2-Y - 包含 Y

在某些案例中,子節點可能已在版本映射中選取,然後才取消選取父節點。為了找出這些案例,會在擴充後執行孤立檢查,以確保所有選取的程式庫都包含父節點。如果不是這樣,孤立的節點會被切斷。

A
  B1
    X
  C
    B2
      Z

追蹤

  • A - 包含 A,頂層依賴項

  • A-B1 - 包含 B1,新程式庫

  • A-C - 包含 C,新程式庫

  • A-B1-X - 包含 X,新程式庫

  • A-C-B2 - 包含 B2,較新版本(+ 取消選取 B1)

  • A-C-B2-Z - 包含 Z

在擴充後,我們會選取 A、X、C、B2 和 Z。但是,在檢查每個節點時,我們會發現 X 的父項 B1 未包含,因此 X 會被切斷。

追蹤資料

使用命令列工具時,你可以使用選項 -Strace 來啟用 dep 追蹤,這會在目前目錄中產生一個追蹤資料檔 trace.edn。如果你檢查該資料,你會找到一個包含下列金鑰的映射

  • :log - 已考慮的 lib 節點的記錄,包括它們是否包含,以及每個原因。記錄將會是一個映射的向量,每個考慮的節點一個,包含下列金鑰::lib:coord:coord-id:paths:include:reason,以及可能的其他金鑰。

  • :vmap - 版本映射(格式可能會變更)

  • :exclusions - 排除映射(格式可能會變更)

樹狀列印

可以使用 clj -Stree 或程式 clj -X:deps tree 列印相依性,其中 有更多選項

樹狀結構會從追蹤記錄建立,並包含所有已考慮的節點。已包含的節點會加上前綴 .。已排除的節點會加上前綴 X。行尾會包含原因代碼(有些代碼會被抑制)。目前的原因代碼組(可能會變更)為

  • :new-top-dep - 已包含為頂層相依性(已抑制)

  • :new-dep - 已包含為新的相依性(已抑制)

  • :same-version - 已排除,與目前選取的相依性相同(已抑制)

  • :newer-version - 已包含,比先前選取的版本更新

  • :use-top - 已排除,與頂層 lib 相同,但不在頂層

  • :older-version - 已排除,比先前選取的版本舊

  • :excluded - 已排除,父路徑中的節點排除了此 lib

  • :parent-omitted - 已排除,父節點已取消選取

  • :superseded - 已排除,此版本已取消選取