Clojure

依存関係展開

このページでは、Clojureツールとtools.depsがルート依存関係のセットを推移的な依存関係のセットに展開する方法を詳しく説明します。このアルゴリズムはMavenの依存関係展開と似ていますが(どちらも幅優先探索によるツリー展開です)、バージョン選択の方法が異なります。

展開

展開の入力

  • 初期依存関係 - 各依存関係は、ライブラリ(シンボル)と座標(Maven、Git、ローカルなど)として定義されます。

  • default-deps - 座標が指定されていない場合に使用する、ライブラリから座標へのマップ。

  • override-deps - ライブラリが見つかった場合に使用する、ライブラリから座標へのマップ。

展開プロセスは、ツリー内のパスのキューをループ処理します。初期キューは、ルート依存関係への単一パスで構成されます。

ループの各ステップで、検討のためにキューからパス(依存関係で終わる)を取り出します。デフォルトとオーバーライドの依存関係を使用して(必要に応じて)、依存関係で使用される座標を置き換えます。次に、このライブラリ/座標を検討し、選択に含めるか除外するかを決定し、後で理解できるように理由コードを記録します。ノードに子ノードがある場合は、それらをキューに追加します。

ループ全体を通して、すべてのライブラリ、見られたバージョン、バージョンマップの選択、除外マップの除外をトラッキングします。必要に応じて、各検討事項とノードが含まれたかどうか、その理由を展開トレースに記録します。

すべての選択は、ツリーを一度通過する間に実行されます。メインラインの展開はシングルスレッドですが、依存関係の子ノードを取得するには、外部ネットワークソース(MavenリポジトリからPOMを要求するなど)からフェッチする必要がある場合があります。パフォーマンス向上のため、スレッドプールを使用して、必要になる前にメタデータを並列でフェッチします。

依存関係の選択

ノードを選択するかどうかを検討する場合、次の条件を満たす場合、ライブラリは含まれます。

  • 最上位の依存関係である場合(最上位の依存関係のバージョンが常に優先されます)、または新しいライブラリであるか、既知のライブラリの新しいバージョンである場合(Mavenは新しい/古いに関わらず、最初に検出されたバージョンのみを保持します)。

  • そして、このノードのパスの親のいずれかに除外されていない場合(次の「除外」セクションを参照)。

  • そして、パス内のすべての親ノードが選択されている場合(次の「孤児」セクションを参照)。

ライブラリ/バージョンが含まれる場合、バージョンマップで選択済みとしてマークされます。

除外

除外は、ツリー内のノードの子ノードにマークされ、その子依存関係とそのサブノードに適用されます。除外は除外マップに記録され、ツリー内のそのポイントより下のライブラリを含めるかどうかを確認する際に使用されます。

特に厄介なケースは、同じライブラリとバージョンがツリー内の異なるポイントで異なる除外セットとともに発生する場合です。このような場合、そのライブラリに使用される除外は、2つの除外セットの**積集合**になります。

たとえば、次のようなツリーがあるとします。

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

この場合、A-D-Cブランチではその依存関係が必要なため、CはXのみを除外します(#{X Y}と#{X}の積集合)。

また重要なのは、パス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を使用して依存関係のトレースを有効にすると、現在のディレクトリにトレースデータファイルtrace.ednが出力されます。そのデータを確認すると、次のキーを持つマップが見つかります。

  • :log - 検討されたライブラリノード、含まれていたかどうか、それぞれの理由のログ。ログは、検討されたノードごとに1つのマップであるマップのベクトルになります。キーは、: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 - 除外、最上位のライブラリと同じだが最上位ではない

  • :older-version - 除外、以前選択したものより古いバージョン

  • :excluded - 除外、親パスのノードがこのライブラリを除外している

  • :parent-omitted - 除外、親ノードが選択解除されている

  • :superseded - 除外、このバージョンが選択解除されている