依存関係管理

Wippy はソースの宣言からモジュール依存関係を解決し、正確なバージョンを wippy.lock に記録します。公開済みモジュールは Hub からプロジェクトのモジュールディレクトリへダウンロードされます。

以下の acme/* モジュール名、バージョン、ハッシュ、ローカルパスは例です。 実際のプロジェクトまたは Hub にあるモジュールと検証済みダイジェストに置き換えてください。

プロジェクトファイル

wippy.lock

ロックファイルはプロジェクトのディレクトリレイアウトと固定された依存関係を追跡します:

directories:
  modules: .wippy
  src: ./src
modules:
  - name: acme/http
    version: v1.2.0
    hash: 4ea816fe84ca58a1f0869e5ca6afa93d6ddd72fa09e1162d9e600a7fbf39f0a2
  - name: acme/sql
    version: v2.0.1
    hash: b3f9c8e12a456d7890abcdef1234567890abcdef1234567890abcdef12345678
フィールド 説明
directories.modules ダウンロードしたモジュールの保存先 (デフォルト: .wippy)
directories.src ソースコードの場所 (デフォルト: ./src)
modules[].name org/module 形式のモジュール識別子
modules[].version 固定されたセマンティックバージョン
modules[].hash ダウンロードしたパックが一致しなければならないアーティファクトダイジェスト。ハッシュ値のみの場合は sha256 として解釈されます
modules[].root 選択されたデプロイメントルートを示します。これを持てるモジュールは最大1つです
options.unpack_modules パックを .wapp ファイルとしてロードする代わりにディレクトリへ展開します (デフォルト: false)

wippy.yaml

公開用のモジュールメタデータ。自分のモジュールを公開する場合にのみ必要です:

organization: acme
module: http
version: 1.2.0
description: HTTP utilities for Wippy
license: MIT
repository: https://github.com/acme/wippy-http
keywords:
  - http
  - web
フィールド 必須 説明
organization はい 小文字、英数字とハイフン
module はい 小文字、英数字とハイフン
version いいえ セマンティックバージョン (公開時に設定)
description いいえ モジュールの説明
license いいえ SPDXライセンス識別子
repository いいえ ソースリポジトリURL
homepage いいえ プロジェクトホームページ
keywords いいえ 検索用キーワード
authors いいえ 著者リスト

依存関係の宣言

_index.yaml に ns.dependency エントリを追加します:

version: "1.0"
namespace: app
entries:
  - name: dependency.http
    kind: ns.dependency
    component: acme/http
    version: "^1.0.0"

  - name: dependency.sql
    kind: ns.dependency
    component: acme/sql
    version: ">=2.0.0"

バージョン制約

制約 例 マッチ
完全一致 1.2.3 1.2.3のみ
キャレット ^1.2.0 >=1.2.0, <2.0.0
チルダ ~1.2.0 >=1.2.0, <1.3.0
範囲 >=1.0.0 1.0.0以上
ワイルドカード * 任意のバージョン (最新を選択)
複合 >=1.0.0 <2.0.0 1.0.0から2.0.0の間

解決ルール

  • 各モジュールは、依存関係グラフ全体で宣言されたすべての範囲の積集合に対して解決されます。互換性のない範囲(ダイヤモンド競合)は、どちらか一方を黙って選ぶのではなく、明示的なエラーで解決に失敗します。
  • 完全な wippy update はすべてのモジュールを宣言された範囲から解決します。対象を絞った更新とブート時の修復は、有効なすべての範囲を依然として満たすピン留めされたバージョンを維持します。
  • ルートのパラメータは推移的なものより優先されます: アプリと依存関係の両方が同じ要件をバインドする場合、あなたの ns.dependency のパラメータが優先されます。バージョン範囲が上書きされることはなく、すべての宣言が積集合に加わります。
  • 複数のルート ns.dependency エントリから宣言されたコンポーネントは、そのうちの1つによって制御されます — 新しい宣言より確立済みの宣言、パラメータを持たないものよりパラメータを持つもの、同点の場合はエントリ ID が最も小さいもの — 残りはそれへの参照に畳み込まれます。制御する宣言とパラメータが食い違う重複は競合エラーとして拒否されます。代わりに既存の依存関係を更新してください。

解決の失敗は2種類に区別して報告されます。どのリリースによっても満たされ得ない制約式 — 有効な範囲の積集合が空 — は競合であり、エラーはモジュール名と範囲を寄与したすべての要求元を示します。範囲の集合自体は有効だが、ハブが現時点で一致するバージョンを公開していない場合は可用性の失敗です。この場合、宣言を一切変更しなくても後のリリースによって解決可能になります。

ランタイムは解決された各グラフをレジストリ履歴に永続化し、ブート時に再解決する代わりにそれをリプレイします。そのため、デプロイされたアプリケーションは、依存関係の変更が適用された時点で解決されたバージョンそのままで起動します。wippy.lock は引き続き、ソースプロジェクト向けのポータブルなスナップショットです。

エントリの来歴

来歴はレジストリが所有するものであり、エントリのメタデータではありません。エントリのロード時、レジストリは各エントリにそれを供給したデプロイメントソースを刻印します:

フィールド 説明
registry.owner エントリを供給したモジュール名 (org/module)。アプリケーションソースの場合は空
registry.root デプロイメントルートが供給した ns.dependency エントリに設定され、ルート宣言であることを示します

エントリの作者がこれらのフィールドを書くことはありません。ロード時に割り当てられ、_index.yaml から偽装することはできません。wippy registry list --registry-meta --json で確認できます。

ワークフロー

新規プロジェクトの開始

wippy init

デフォルトのディレクトリで wippy.lock を作成します。

依存関係の追加

wippy add acme/http               # Latest version
wippy add acme/http@1.2.3         # Exact version
wippy add acme/http@latest         # Latest label

これによりロックファイルが更新されます。次にインストールします:

wippy install

ソースからの解決

ソースに ns.dependency エントリが既に宣言されている場合:

wippy update

これはソースディレクトリをスキャンし、すべての依存関係の制約を解決し、ロックファイルを更新し、モジュールをインストールします。

依存関係の更新

wippy update                       # Re-resolve all dependencies
wippy update acme/http             # Update only acme/http
wippy update acme/http acme/sql    # Update specific modules

特定のモジュールを更新する場合、他のモジュールは現在のバージョンに固定されたままです。更新により対象外のモジュールの変更が必要になる場合、確認が求められます。

ロックファイルからのインストール

wippy install                      # Install all from lock
wippy install --refresh            # Re-fetch every module (--force and --repair are aliases)

モジュールストレージ

ダウンロードしたモジュールは .wippy/vendor/ ディレクトリに保存されます:

project/
  wippy.lock
  src/
    _index.yaml
  .wippy/
    vendor/
      acme/
        http-v1.2.0.wapp
        sql-v2.0.1.wapp

デフォルトでは、モジュールは .wapp ファイルとして保持されます。ディレクトリに展開するには:

# wippy.lock
options:
  unpack_modules: true

展開を有効にした場合:

.wippy/
  vendor/
    acme/
      http-v1.2.0.wapp
      http/
        wippy.yaml
        src/
          _index.yaml
          ...

展開してもパックが破棄されることはありません。検証済みの正規の .wapp は展開されたディレクトリの隣に残ります。これはモジュールに対する唯一のコンテンツアドレス指定された証跡であり、アーティファクトのマテリアライズと修復はそこからリソースを読み戻すためです。インストール済みかどうかの判定対象は .wapp です。パックが欠けているディレクトリはインストールされていないものとして扱われ、モジュールは再ダウンロードされます。インストールのたびに検証済みアーカイブからディレクトリを新たに展開するため、ベンダーディレクトリへの手動編集は残りません。

ワークスペースリプレースメントから解決されたモジュールは、ダウンロードもベンダー化もされず、ローカルパスからロードされます。

リプレースメントによるローカル開発

開発時にハブモジュールをローカルディレクトリで上書きします。リプレースメントはランタイム設定ファイルの workspace セクションで宣言します — 通常は .wippy.yaml の上に合成される、git 管理外のプライベートなファイルです:

# .wippy.workspace.yaml
version: "1.0"
workspace:
  replacements:
    acme/http: ../local-http
    acme/sql: ../local-sql
wippy run --config .wippy.yaml --config .wippy.workspace.yaml

キーは org/module、値はディレクトリです(相対パスは最初の --config ファイルのディレクトリを基準に解決されます)。リプレースメントを null に設定すると、前の設定レイヤーやプロファイルから継承したものを無効化できます。リプレースメントはプロファイルの中に置くこともでき、その場合は --profile workspace を指定したときのみ有効になります。

パスが存在し、かつディレクトリであることが要求されるのは、ロックグラフが実際に選択するモジュールに対してのみです。何も依存していないモジュールに対して宣言されたリプレースメントは、ブートの入力ではなく解決の入力です。そのため、このマシンにチェックアウトされていないディレクトリを指していても検証に失敗しません。

リプレースメントが変えるのはモジュールのソースの取得元であって、どのリリースが選択されたかではありません。ロードパスはロックがそのモジュールに対して選択したバージョンを保持し、リプレースメントとしてフラグ付けされます。そこからロードされたエントリは、同じIDを持つベンダー化されたエントリを覆い隠します。ロックがバージョンを固定していないモジュールに対してリプレースメントが宣言された場合、解決はハブにリリースバージョンを問い合わせ、より強い根拠によっていずれかが選択されるまではローカル限定のゼロバージョンを保持します。

リコンシリエーションでは現在のローカルツリーをスナップショットし、そのダイジェストとサイズをリプレースメントの識別情報として記録します。以前のダイジェストはチェックポイントであり、不変の Hub アーティファクト識別情報ではありません。

ワークスペースリプレースメントはブート時のロードグラフに作用し、wippy.lock に書き込まれることはありません。ローカルソースへの変更は、ハブに接続することなく直接反映されます。wippy.yaml のソース exclude: グロブは、エントリのロード時とコンテンツのハッシュ時の両方で、リプレースメントディレクトリにも適用されます。

wippy.lock 内の replacements: セクションは非推奨です: 引き続きロードされますが警告が表示されます。それらのエントリは設定ファイルの workspace.replacements に移してください。

ロード順序

起動時に、Wippyは以下の順序でディレクトリからエントリをロードします:

  1. ソースディレクトリ (src)
  2. リプレースメントディレクトリ
  3. ベンダーモジュールディレクトリ

アクティブなリプレースメントがあるモジュールはベンダーパスをスキップします。

整合性検証

ロックファイル内のすべてのモジュールはアーティファクトダイジェストを持ちます。ブートは、ロックエントリにダイジェストがないモジュールのロードを拒否します。wippy install はそのようなエントリを受け入れ、ハブがダウンロードとともに提供したダイジェストを記録します。

ブート時、ダウンロードはステージングされます。パックは最終的な配置先の隣にある一時ファイルへ書き込まれ、wippy.lock に固定されたダイジェストと、ハブがダウンロードURLとともに提供したダイジェスト(および提供されたサイズ)の両方に対して検証され、その後にのみ所定の位置へリネームされます。検証に失敗したステージングファイルは削除されます。wippy install は検証の前にダウンロードをベンダーパスへリネームし、提供されたダイジェストとサイズに対してのみチェックし、失敗した場合は削除し、提供されたものと異なるロックのダイジェストは強制するのではなく置き換えます。

ダイジェストの不一致は、リトライ不可能な致命的失敗です。ブート時には PermissionDenied、"module integrity verification failed" として発生し、新規ダウンロードと、エントリのロード前にロックのダイジェストに対して再検証されるベンダー化済みのパックの両方が対象です。wippy install はこれを Internal として報告します。ベンダーディレクトリにすでにあるパックでは "failed to store module" が "verify cached WAPP: digest mismatch" を包み、新規ダウンロードでは "failed to download module" が "verify downloaded WAPP: digest mismatch" を包みます。リトライも、不一致を上書きする再ダウンロードも、提供されたコンテンツへのフォールバックも行われません。

同じチェックが解決も保護します。ハブが提供したマニフェストのダイジェストがロックに固定されたものと異なる場合、マニフェストキャッシュが一度更新され、再度比較されます。それでも一致しない場合、解決は両方のダイジェストを示して失敗します。

展開されたディレクトリは自身の記録済みダイジェスト、サイズ、ツリーダイジェストを保持し、記録された値に対して再検証されます。そのため、変更されたベンダーツリーはロードされずに検出されます。

各リコンシリエーション試行では現在のローカルツリーをスナップショットし、ロード前に同じダイジェストとサイズを検証します。並行変更はソース世代を混ぜずに検証を失敗させます。再起動時には不変の履歴アーティファクトを別途プリフェッチし、履歴のローカルリプレースメントを最終的な依存関係宣言と照合します。削除されたリプレースメントは旧ディレクトリを残す必要がありませんが、最終グラフで選択されたものは存在し妥当でなければなりません。

ビルド時アーティファクト

モジュールは、meta.artifact.format が付与されたファイルシステムリソースを同梱できます。消費側はそれを実行時に読むのではなくディスク上へマテリアライズします。全体および対象指定の wippy install と wippy update、コールドブート、実行時の依存関係操作は、モジュールグラフを変更するのと同一のトランザクションの一部としてそれらの出力を整合させます。出力ルートは artifact.materialization_root で設定します。ビルド時アーティファクトを参照してください。

関連項目