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/sub
にgo.mod
ファイルが含まれていれば、repo/sub
とそこに含まれるファイルは別個のモジュールであり、repo
の一部ではありません。
- あるモジュール
命名
標準ライブラリを除くモジュールやパッケージの名前は、(sub.)*domain.tld(/path)*
という形式でなければなりません。これは URL に似ていますが、URL ではありません。パッケージ名はスキーム(https://
など)を持たず、ポート番号を持つことはできません。example.com:8443/my/package
は有効な名前ではありません。
パッケージの取得
Go 1.12以前では、パッケージのフェッチは以下のようなプロセスでした:
- クエリ
https://{package name}?go-get=1
. - レスポンスをスキャンして、
go-import
メタタグを探します。 - 指定された 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以降では、モジュールやパッケージの取得は以下のようになります:
-
GOPROXY
がプロキシのリストで、モジュールがGONOPROXY
やGOPRIVATE
で除外されていない場合、それらを順番にクエリし、最初の有効なレスポンスで停止します。 -
GOPROXY
がdirect
であるか、モジュールが除外されているか、GOPROXY
が,direct
で終わっていて、モジュールを提供したプロキシがない場合、フォールバックします。- クエリ
https://{module or package name}?go-get=1
. - レスポンスをスキャンして、
go-import
メタタグを探します。 - 指定された VCS を使用して、メタタグが示すリポジトリを取得します。
-
{vcs}
フィールドがmod
の場合、URL は VCS ではなくモジュールプロキシとして扱われます。
- クエリ
- モジュールが依存関係としてではなく、直接取得されている場合は、停止してください。
-
go.sum
にモジュールに対応するエントリがある場合は、チェックサムを検証して停止します。 -
GOSUMDB
がチェックサム・データベースを識別し、モジュールがGONOSUMDB
またはGOPRIVATE
によって除外されていない場合、モジュールのチェックサムを取得してgo.sum
に追加し、ダウンロードしたソースをこれと照合して検証します。 -
GOSUMDB
がoff
の場合、またはモジュールが除外されている場合は、ダウンロードしたソースからチェックサムを計算し、それを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
を参照してください。