Goで相互に参照しあうモジュールを同時にタグ付けしないとモジュールの参照がさかのぼってしまう

公開:2020/09/21
更新:2020/09/21
5 min読了の目安(約3400字TECH技術記事

概要

形態素解析器 kagome v2 では、解析部分(解析器)と辞書部分を異なるモジュールに分ける事で、必要な辞書だけをライブラリとして利用したり、バイナリに含める事が出来るようになっています。

そのため、解析器と辞書は相互に依存し合っていて、お互いを go.mod の required に指定しています。

これまで、自分のフローとしては、辞書をリリースして、その後、解析器の方で利用している辞書バージョンを上げてリリース、という手順を踏んでいたのですが、これが間違いでした。

TL;DR;

相互に依存し合うモジュールは同時にタグ付けする必要がある。

なにもしないのに壊れた

kagome の README.md に修正を頂いたのがきっかけでした。README.md の変更だけでコードにはなにも変更がないのに CI がコケています。エラーは次のようなものでした。

go: github.com/ikawaha/kagome-dict-ipa@v1.0.0 requires
	github.com/ikawaha/kagome/v2@v2.0.1-0.20200807150621-84db2b72df77 requires
	github.com/ikawaha/kagome-dict-ipa@v0.0.0-20200804124920-1dc0b3c7045b requires
	github.com/ikawaha/kagome/v2@v2.0.1-0.20200804124132-30d9da933be1 requires
	github.com/ikawaha/kagome-dict-ipa@v0.0.0-20200726115736-178e72a81257 requires
	github.com/ikawaha/kagome/v2@v2.0.1-0.20200726111637-e7a2cfdec05f requires
	github.com/ikawaha/kagome-dict-test@v0.0.0-20200724140631-d8a16f0faeb6: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/travis/gopath/pkg/mod/cache/vcs/a89d4555b1676136027a2419423bf7e72b28b498e9c8051022ab27abde667d41: exit status 128:

	remote: Invalid username or password.
	fatal: Authentication failed for 'https://github.com/ikawaha/kagome-dict-test/'

どうやら kagome-dict-test というリポジトリがなくて依存関係が解決できずにエラーになってしまったようです。この kagome-dict-test は開発途中で辞書リポジトリを別に分けられるかテストするために作成したリポジトリで、今は利用していないのでリポジトリからも削除したものでした。

なぜ過去利用したリポジトリが参照されてしまうのでしょう 🤔

依存関係を図示してみる

モジュールが利用しているライブラリは

go mod graph

でグラフ化できます。・・・できますが、見やすいものではありません。
モジュールグラフの情報をGraphvizのフォーマットで図示してくれるライブラリ(https://github.com/lucasepe/modgv)があるのでこれを利用します。

使い方は、go mod graph の出力結果を modgv に渡して、それをさらに Graphviz に渡すだけです。(iTerm 環境なら imgcat を利用するとコマンドラインで参照できて便利です)

go mod graph|modgv|dot -Tpng|imgcat

circular-reference

みてみると、解析器は辞書を参照していて、その辞書は ひとつ前の!! 形態素解析器を参照していて、と参照がどんどんさかのぼっていってしまって、テストの時に使っていたライブラリにまでたどり着いてしまったのでした。

解決方法

解析器と辞書のバージョンを同時に更新します。

mod-graph

これで依存関係がスッキリと正しくなりました!

相互に参照しあうと go get が失敗するかな?と思ったのですが、大丈夫なようでした。

$ env GO111MODULE=on go get -v github.com/ikawaha/kagome/v2/...@v2.0.6
go: downloading github.com/ikawaha/kagome/v2 v2.0.6
go: found github.com/ikawaha/kagome/v2/... in github.com/ikawaha/kagome/v2 v2.0.6
go: downloading github.com/ikawaha/kagome-dict-ko v1.0.3
go: downloading github.com/ikawaha/kagome-dict-ipa v1.0.3
go: downloading github.com/ikawaha/kagome-dict-uni v1.0.3
github.com/ikawaha/kagome/v2/splitter
github.com/ikawaha/kagome/v2/dict/trie
github.com/ikawaha/kagome/v2/dict
github.com/ikawaha/kagome/v2/dict/builder
github.com/ikawaha/kagome/v2/tokenizer/lattice
github.com/ikawaha/kagome-dict-ipa/internal/data
github.com/ikawaha/kagome/v2/tokenizer
github.com/ikawaha/kagome-dict-ko/internal/data
github.com/ikawaha/kagome-dict-uni/internal/data
github.com/ikawaha/kagome-dict-ipa
github.com/ikawaha/kagome-dict-ko
github.com/ikawaha/kagome-dict-uni
github.com/ikawaha/kagome/v2/cmd/kagome/tokenize
github.com/ikawaha/kagome/v2/cmd/kagome/lattice
github.com/ikawaha/kagome/v2/cmd/kagome/server
github.com/ikawaha/kagome/v2/cmd/kagome

相互参照するモジュール書く事あまりないかも知れませんが、ひとつのモジュールを分割したいケースはありそうなので、なんか変な事になってないか、分割したときは依存関係をチェックしてみるとよさそうです。

Happy hacking!