Goの依存関係管理

Go は依存関係管理に対して、アーティファクトベースではなくソースベースという珍しいアプローチを取ります。アーティファクトベースの依存関係管理システムでは、パッケージはソースコードから生成されたアーティファクトで構成され、ソースコードとは別のリポジトリシステムに保存されます。たとえば、多くの NodeJS パッケージは、パッケージリポジトリとしてnpmjs.org を使用し、ソースリポジトリとしてgithub.com を使用します。一方、Go のパッケージはソースコードあり、パッケージのリリースにはアーティファクトの生成や別のリポジトリは関係ありません。Goパッケージは、VCSサーバー上のバージョン管理リポジトリに保存する必要があります。依存プロキシは、VCS サーバーから直接取得するか、VCS サーバーから取得する中間プロキシを経由して取得します。

バージョニング

Go 1.11 では、Go エコシステムにモジュールとファーストクラス パッケージのバージョン管理が導入されました。それ以前は、Go にはバージョン管理のための明確に定義されたメカニズムがありませんでした。サード パーティのバージョン管理ツールは存在しましたが、デフォルトの Go エクスペリエンスではバージョン管理はサポートされていませんでした。

Go モジュールはセマンティック バージョン管理を使用します。モジュールのバージョンは VCS (バージョン管理システム) タグとして定義され、有効なセマンティックバージョンには先頭にv が付きます。たとえば、gitlab.com/my/project のバージョン1.0.0 をリリースするには、開発者は Git タグv1.0.0を作成する必要があります。

メジャーバージョンが 0 と 1 以外の場合、モジュール名の末尾に/vX を付けなければなりません。例えば、gitlab.com/my/project のバージョンv2.0.0 は、gitlab.com/my/project/v2 という名前を付けてインポートしなければなりません。

Goは「擬似バージョン」を使用します。これは特定のVCSコミットを参照する特別なセマンティックバージョンです。セマンティックバージョンのプレリリースコンポーネントは、タイムスタンプとコミット識別子の最初の12文字で終わる必要があります:

  • vX.0.0-yyyymmddhhmmss-abcdefabcdefでなければなりません。
  • vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef直近のタグが vX.Y.Z-pre.
  • vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef直近の先行タグがvX.Y.Zの場合。

VCSタグがこれらのパターンのいずれかに一致する場合、そのタグは無視されます。

Go モジュールとバージョニングの完全な理解については、Go 公式ウェブサイトのこの一連のブログ記事を参照してください。

モジュール」と「パッケージ」の違い

  • パッケージは*.go ファイルを含むフォルダです。
  • モジュールは、go.mod ファイルを含むフォルダです。
  • モジュールは通常パッケージでもあり、go.mod ファイルと*.go ファイルを含むフォルダーです。
  • モジュールはサブディレクトリを持つかもしれません。
  • モジュールは通常、VCSリポジトリ(Git、SVN、Hgなど)の形で提供されます。
  • モジュールのサブディレクトリで、それ自身がモジュールであるものは、別個の独立したモジュールであり、コンテナモジュールから除外されます。
    • あるモジュールrepo が与えられたとき、repo/subgo.mod ファイルが含まれていれば、repo/sub とそこに含まれるファイルは別個のモジュールであり、repoの一部ではありません。

命名

標準ライブラリを除くモジュールやパッケージの名前は、(sub.)*domain.tld(/path)* という形式でなければなりません。これは URL に似ていますが、URL ではありません。パッケージ名はスキーム(https:// など)を持たず、ポート番号を持つことはできません。example.com:8443/my/package は有効な名前ではありません。

パッケージの取得

Go 1.12以前では、パッケージのフェッチは以下のようなプロセスでした:

  1. クエリhttps://{package name}?go-get=1.
  2. レスポンスをスキャンして、go-import メタタグを探します。
  3. 指定された VCS を使用して、メタタグが示すリポジトリを取得します。

meta タグは<meta name="go-import" content="{prefix} {vcs} {url}"> のような形式で指定します。たとえば、gitlab.com/my/project git https://gitlab.com/my/project.git は、gitlab.com/my/project で始まるパッケージを Git を使ってhttps://gitlab.com/my/project.git から取得することを示します。

モジュールの取得

Go 1.12 ではチェックサムデータベースとモジュールプロキシが導入されました。

チェックサム

go.mod に加えて、モジュールにはgo.sum ファイルがあります。このファイルには、コードの SHA-256 チェックサムと、モジュールまたはモジュールの依存関係から参照される依存関係のすべてのバージョンのgo.mod ファイルが記録されています。新しい依存関係が参照されると、Go はgo.sum を継続的に更新します。

Go がモジュールの依存関係をフェッチするとき、それらの依存関係がgo.sum にすでにエントリを持っている場合、Go はこれらの依存関係のチェックサムを検証します。チェックサムがgo.sum にあるものと一致しない場合、ビルドは失敗します。これにより、あるモジュールのあるバージョンが、開発者や悪意のある者によって、ビルドに失敗することなく変更されないことが保証されます。

Go 1.12+ では、チェックサムデータベースを使用するように設定できます。このように設定すると、Go が依存関係をフェッチし、go.sum に対応するエントリがない場合、ダウンロードされた依存関係からチェックサムを計算する代わりに、設定されたチェックサムデータベースに依存関係のチェックサムをクエリします。依存関係がチェックサムデータベースで見つからない場合、ビルドは失敗します。ダウンロードした依存関係のチェックサムがチェックサムデータベースの結果と一致しない場合、ビルドは失敗します。以下の環境変数がこれを制御します:

  • GOSUMDB は、クエリするチェックサムデータベースの名前、および公開鍵とサーバー URL を指定します。
    • 値をoff とすると、チェックサム・データベースのクエリは完全に無効になります。
    • Go 1.13+では、GOSUMDB が定義されていない場合、sum.golang.org を使用します。
  • GONOSUMDB は、チェックサムデータベースのクエリを無効にするモジュールの接尾辞のカンマ区切りのリストです。ワイルドカードが使えます。
  • GOPRIVATE はカンマ区切りのモジュール名のリストで、GONOSUMDB と同じ機能に加えて、他の機能も無効にします。

プロキシ

Go 1.12+ では、モジュールをモジュールの VCS から直接取得するのではなく、Go プロキシから取得するように設定できます。このように設定すると、Go が依存プロキシをフェッチするとき、設定されたプロキシから順番に依存プロキシをフェッチしようとします。次の環境変数がこれを制御します:

  • GOPROXY はクエリするモジュールプロキシのカンマ区切りのリストです。
    • direct を指定すると、モジュールプロキシへのクエリを完全に無効にします。
    • リストの最後のエントリがdirectの場合、どのプロキシも依存プロキシを提供できない場合、Go は前述のプロセスにフォールバックします。
    • Go 1.13+では、GOPROXY が定義されていない場合、proxy.golang.org,direct を使用します。
  • GONOPROXY はカンマで区切られたモジュールの接尾辞のリストです。ワイルドカードが使えます。
  • GOPRIVATE はカンマ区切りのモジュール名のリストで、GONOPROXY と同じ機能に加えて、他の機能も無効にします。

フェッチ

Go 1.12以降では、モジュールやパッケージの取得は以下のようになります:

  1. GOPROXY がプロキシのリストで、モジュールがGONOPROXYGOPRIVATE で除外されていない場合、それらを順番にクエリし、最初の有効なレスポンスで停止します。
  2. GOPROXYdirect であるか、モジュールが除外されているか、GOPROXY,direct で終わっていて、モジュールを提供したプロキシがない場合、フォールバックします。
    1. クエリhttps://{module or package name}?go-get=1.
    2. レスポンスをスキャンして、go-import メタタグを探します。
    3. 指定された VCS を使用して、メタタグが示すリポジトリを取得します。
    4. {vcs} フィールドがmod の場合、URL は VCS ではなくモジュールプロキシとして扱われます。
  3. モジュールが依存関係としてではなく、直接取得されている場合は、停止してください。
  4. go.sum にモジュールに対応するエントリがある場合は、チェックサムを検証して停止します。
  5. GOSUMDB がチェックサム・データベースを識別し、モジュールがGONOSUMDB またはGOPRIVATE によって除外されていない場合、モジュールのチェックサムを取得してgo.sum に追加し、ダウンロードしたソースをこれと照合して検証します。
  6. GOSUMDBoff の場合、またはモジュールが除外されている場合は、ダウンロードしたソースからチェックサムを計算し、それをgo.sum に追加します。

ダウンロードされたソースにはgo.mod ファイルが go.mod含まれている必要があります。go.mod この go.modファイルには、モジュール名を指定するmodule 指示子が含まれていなければなりません。go.mod で指定されたモジュール名が、モジュールのフェッチに使用された名前と一致しない場合、モジュールのコンパイルに失敗します。

モジュールが直接取得され、バージョンが指定されていない場合、またはモジュールが依存関係として追加され、バージョンが指定されていない場合、Go はモジュールの最新バージョンを使用します。モジュールがプロキシから取得された場合、Go はプロキシにバージョンのリストをクエリし、最新のものを選択します。モジュールが直接取得された場合、Go はリポジトリにタグのリストをクエリし、有効なセマンティックバージョンでもある最新のものを選択します。

認証

Go 1.13 より前のバージョンでは、Go によるリクエストの認証のサポートに一貫性がありませんでした。Go 1.13 では、認証のサポートが改善されました.netrc 。リクエストが HTTPS 経由で行われ、一致する .netrcエントリが見つかると、リクエストに HTTP Basic 認証の資格情報が追加されます。HTTP でのリクエストは認証されません。認証情報を埋め込んだGOPROXY の HTTP 専用エントリは拒否されます。

将来のバージョンでは、任意の認証ヘッダのサポートが追加される可能性があります。詳細はgolang/go#26232 を参照してください。