Go Wiki:変更されたモジュールパスからの問題解決
予期しないモジュールパス
プロジェクト`my-go-project`に取り組んでいるユーザーは、`go get -u`の実行中に次のようなエラーに遭遇する可能性があります。
$ cd my-go-project
$ go get -u ./...
[...]
go: github.com/golang/lint@v0.0.0-20190313153728-d0100b6bd8b3: parsing go.mod: unexpected module path "golang.org/x/lint"
[...]
Exit code 1
`golang.org/x/lint`は、Gitリポジトリとモジュール名が`github.com/golang/lint`から`golang.org/x/lint`への移行前に`github.com/golang/lint`であったモジュールです。Goツールは現在、新しいGitリポジトリで古いモジュール名を理解しようとしてつまずいています:golang/go#30831。
これは`my-go-project`に表示されました。なぜなら、`my-go-project`またはその推移的な依存関係のいずれかに、古い`github.com/golang/lint`モジュール名へのルートが存在するからです。
たとえば、`my-go-project`自体が古い`github.com/golang/lint`モジュール名に依存している場合
$ GO111MODULE=on go mod graph
my-go-project github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
あるいは、`my-go-project`が古いバージョンの`google.golang.org/grpc`に依存しており、それが古い`github.com/golang/lint`モジュール名に依存している場合
$ GO111MODULE=on go mod graph
my-go-project google.golang.org/grpc@v1.16.0
google.golang.org/grpc@v1.16.0 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
最後に、`my-go-project`が、古いバージョンの`google.golang.org/grpc`を必要とする別の依存関係に依存しており、それが古い`github.com/golang/lint`モジュール名に依存している場合
$ GO111MODULE=on go mod graph
my-go-project some/dep@v1.2.3
...
another/dep@v1.4.2 google.golang.org/grpc@v1.16.0
google.golang.org/grpc@v1.16.0 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
名前への参照の削除
Goツールがモジュールパスの変更されたモジュールを理解するまで(golang/go#30831で追跡中)、これに対する解決策は、古いモジュール名へのパスがなくなるようにグラフを更新することです。
上記の例を使用して、`github.com/golang/lint`へのパスがなくなるようにグラフを更新する方法を説明します。
最初の例を修正するのは簡単です。唯一のリンクはユーザーが制御する`my-go-project`からのものです!`go.mod`で古い場所を新しい場所に置き換えます - `github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7`を`golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f`に置き換えます - グラフからのリンクを削除します。
$ GO111MODULE=on go mod graph
my-go-project golang.org/x/lint@v0.0.0-20190301231843-5614ed5bae6f
2番目の例を修正するには、さらに多くの手順が必要ですが、基本的に同じプロセスです。`google.golang.org/grpc@v1.16.0`は`github.com/golang/lint`へのリンクを提供するため、`google.golang.org/grpc`は`go.mod`を`github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7`から`golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f`に更新する必要があります(これはありがたいことに`v1.17.0`で既に実行されています)。次に、`my-go-project`は`go.mod`を更新して新しいバージョンの`google.golang.org/grpc`を含める必要があります。そのため、次のようになります。
$ GO111MODULE=on go mod graph
my-go-project google.golang.org/grpc@v1.17.0
google.golang.org/grpc@v1.17.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
3番目の例を修正する方法は2番目と似ています。`github.com/golang/lint`への参照を含まない新しいバージョンの`another/dep`に更新します。
やった!問題は解決しました - Goツールが考慮する`github.com/golang/lint`へのパスはもうないので、`go get -u`の実行中にこの問題でつまずくことはありません。
より難しい問題:後続履歴の削除
これですべてうまくいき、ほとんどのユーザーの問題を解決するはずです。
ただし、かなり複雑になる状況が1つあります。モジュールの依存関係グラフにサイクルがある場合です。このモジュールの依存関係グラフを考えてみてください。
そして、`some/lib`が以前は`github.com/golang/lint`に依存していたと想像してみましょう。
バージョンを含むこのモジュールの依存関係グラフを見てみましょう。
$ go mod graph
my-go-lib some/lib@v1.7.0
some/lib@v1.7.0 some-other/lib@v2.5.3
some/lib@v1.7.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.5.3 some/lib@v1.6.0
some/lib@v1.6.0 some-other/lib@v2.5.0
some/lib@v1.6.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.5.0 some/lib@v1.3.1
some/lib@v1.3.1 some-other/lib@v2.4.8
some/lib@v1.3.1 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.4.8 some/lib@v1.3.0
some/lib@v1.3.0 some-other/lib@v2.4.7
some/lib@v1.3.0 github.com/golang/lint@v0.0.0-20180702182130-06c8688daad7
golang.org/x/exp/cmd/modgraphvizで視覚化
ここでは、最新のいくつかのバージョンの`some/lib`が正しく`golang.org/x/lint`に依存しているにもかかわらず、`some/lib`と`some-other/lib`がサイクルを共有しているため、非常に古い時点まで遡るパスが存在する可能性が高いことがわかります。
このようなパスが発生する理由は、バージョンを上げるプロセスが通常個別にアトミックであるためです。`some/lib`が`some-other/lib`のバージョンを上げて自身の新しいバージョンをリリースする場合、`some-other/lib`の最新バージョンは依然として`some/lib`の以前のバージョンに依存します。つまり、これらのライブラリのいずれか1つを上げるだけでは、履歴へのチェーンを削除することはできません。
履歴へのチェーンを削除し、グラフから古い`github.com/golang/lint`参照を完全に削除するには、両方のライブラリが互いのバージョンを同時に上げる必要があります。
2つのライブラリの原子的なバージョンバンプ
`github.com/golang/lint`を削除する解決策は、まず`some/lib`が`github.com/golang/lint`に依存していないことを確認し、次に`some/lib`と`some-other/lib`の両方を互いの存在しない将来のバージョンに上げる(bump)ことです。このようなグラフが欲しいのです。
my-go-lib some/lib@v1.7.1
some/lib@v1.7.1 some-other/lib@v2.5.4
some/lib@v1.7.1 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
some-other/lib@v2.5.4 some/lib@v1.7.1
`some/lib`と`some-other/lib`が同じバージョンで互いに依存しているため、`github.com/golang/lint`が提供されている時点までさかのぼるパスはありません。
この原子的なバージョンバンプを実現する手順を以下に示します。`some/lib`が`v1.7.0`で、`some-other/lib`が`v2.5.3`であると仮定します。
- エラーが実際に存在することを確認します。
- `some/lib`と`some-other/lib`で`GO111MODULE=on go get -u ./...`を実行します。
- 両方のリポジトリで、エラー`go: github.com/golang/lint@v0.0.0-20190313153728-d0100b6bd8b3: parsing go.mod: unexpected module path "golang.org/x/lint"`が表示されます。
- `some/lib`の最新バージョンが`github.com/golang/lint`ではなく`golang.org/x/lint`に依存していることを確認します。履歴の痕跡を削除して、`github.com/golang/lint`への壊れた依存関係を保持するのは残念です!
- アルファタグを使用して、両方のライブラリを互いの存在しない将来のバージョンに上げます(アルファバージョンは、モジュールの最新リリースバージョンを評価する際に、Goモジュールによって新しいバージョンとは見なされないため、より安全です)。
- `some/lib`は`some-other/lib`の依存関係を`v2.5.3`から`v2.5.4-alpha`に変更します。
- `some/lib`はコミット`v1.7.1-alpha`をタグ付けし、コミットとタグをプッシュします。
- `some-other/lib`は`some/lib`の依存関係を`v1.6.0`から`v1.7.1-alpha`に変更します。
- `some-other/lib`はコミット`v2.5.4-alpha`をタグ付けし、コミットとタグをプッシュします。
- まだアルファ状態の間に結果を確認します。
- `some/lib`で`GO111MODULE=on go build ./...` && `go test ./...`を実行します。
- `some-other/lib`で`GO111MODULE=on go build ./...` && `go test ./...`を実行します。
- 両方のリポジトリで`GO111MODULE=on go mod graph`を実行し、`github.com/golang/lint`へのパスがないことを確認します。
- 注:上記で説明したように、アルファバージョンは最新バージョンを評価する際に考慮されないため、`go get -u`は依然として機能しません。
- すべてが問題なければ、もう一度互いの存在しない将来のバージョンに上げます。
- `some/lib`は`some-other/lib`の依存関係を`v2.5.4-alpha`から`v2.5.4`に変更します。
- `some/lib`はコミット`v1.7.1`をタグ付けし、コミットとタグをプッシュします。
- `some-other/lib`は`some/lib`の依存関係を`v1.7.1-alpha`から`v1.7.1`に変更します。
- `some-other/lib`はコミット`v2.5.4`をタグ付けし、コミットとタグをプッシュします。
- エラーがなくなったことを確認します。
- `some/lib`と`some-other/lib`で`GO111MODULE=on go get -u ./...`を実行します。
- `go.mod: unexpected module path "golang.org/x/lint"`という解析エラーは発生しません。
- 現在、`some/lib`と`some-other/lib`の`go.sum`は不完全です。これは、モジュールの存在しない将来のバージョンに依存していたため、プロセスが完了するまで`go.sum`エントリを生成できなかったためです。そのため、これを修正しましょう。
- `some/lib`で`GO111MODULE=on go mod tidy`を実行します。
- コミットし、コミット`v1.7.2`をタグ付けし、コミットとタグの両方をプッシュします。
- `some-other/lib`で`GO111MODULE=on go mod tidy`を実行します。
- コミットし、コミット`v2.5.5`をタグ付けし、コミットとタグの両方をプッシュします。
- 最後に、`my-go-project`が長い履歴のテールを持たないこれらの新しいバージョンの`some/lib`と`some-other/lib`に依存していることを確認しましょう。
- `my-go-project`の`go.mod`エントリを`some/lib v1.7.0`から`some/lib 1.7.2`に変更します。
- `my-go-project`で`GO111MODULE=on go get -u ./...`を実行してテストします。
手順5.bと5.dの間、ユーザーは中断されています。`some/lib`のバージョンがリリースされ、存在しないバージョンの`some-other/lib`に依存しています。したがって、このプロセスは理想的にはリアルタイムで行う必要があります。手順5.dは手順5.bの直後に終了し、可能な限り小さな中断期間を確保します。
より大きなサイクル
この例では、グラフ内で2つのパッケージを含むサイクルが存在する場合の履歴トレイルの削除プロセスについて説明しましたが、より多くのパッケージを含むサイクルがある場合はどうでしょうか? 例えば、以下のグラフを考えてみましょう。
これらのグラフはそれぞれ、サイクル(後者の例)または相互に関連するモジュール(前者の例)を4つのモジュールで含んでおり、以前見た単純な2モジュール例とは異なります。ただし、プロセスはほぼ同じです。ただし、今回はステップ3と5で、4つのモジュールすべてを互いの存在しない将来のバージョンに更新し、同様にステップ4と6で4つのモジュールすべてをテストし、ステップ7で4つのモジュールのgo.sumを修正します。
より一般的には、上記のプロセスは、任意のn個のモジュールを含む相互接続されたモジュールの任意のグループに適用されます。各主要ステップは、n個のモジュールが協調して動作するだけです。
このコンテンツは、Go Wikiの一部です。