goの依存管理ツールはいろいろありますが、最新はGo Modules(mod)を利用することが多くなってきたと思います。 dep(vendor)を利用した依存解決の場合にはgopath配下にあればある程度柔軟に相対的に依存を解決できましたが、 modは普通に利用するとリポジトリにコミットをした状態を期待しているような振る舞いをします。
モノレポで以下のように複数のモジュールを管理している場合には、modでは利用しづらいように思えましたが、 参照しているモジュールをコミットした状態ではなくとも参照したいという要望があったので解決してみました。
project ├ a_module │ ├ go.mod │ └ main.go ├ b_module │ ├ go.mod │ └ hoge │ └ say.go ...
各モジュールをmod化する
各モジュールをmod化します。 mod init する際に以下のように module 名を設定します。
// a_moduleをmod化 $ cd path/to/project/a_module $ go mod init a_module // b_moduleをmod化 $ cd path/to/project/a_module $ go mod init b_module
作成されたmodファイルは以下のようになります。
a_module/go.mod
module a_module go 1.12
b_module/go.mod
module b_module go 1.12
a_moduleからb_moduleを参照する
a_moduleからb_moduleを利用したい場合、a_moduleのmodファイルを以下のように追記します
a_module/go.mod
module a_module go 1.12 require ( b_module v0.0.0 ) replace b_module => ../b_module
b_moduleを依存として利用します(require)という記述と、
b_moduleは ../b_module
という相対位置にありますという記述が必要になります。
modの相対位置の関係はgo.modファイルがある位置になるようです。
コード側からb_moduleの関数を利用する
先程の記述は依存関係を定義したので、実際にa_moduleのファイルからb_moduleの関数を利用してみます。
a_module/main.go
package main import ( "b_module/hoge" ) func main() { hoge.Say() // b_moduleで実装した関数 // Hello }
main.goが作成できたら go run main.go
などで実行します。
実行の際に依存関係の取得が行われます。
ちなみに b_module/hoge/say.go の中身はこんな感じになるかと思います。
package hoge func Say() string { return "Hello" }
まとめ
このようにmodファイルを構成することでモノレポで管理しているプロジェクトでも 共通のユーティリティモジュールなどを柔軟に参照することができます。
一時 GO111MODULE=off
を利用し、vendor(dep) を引き続き利用していましたが、
こちらの方法でも同じように管理できるようになったのでまとめました。
ツッコミどころなどあればコメントください。
次回作の予告
上記のmodでの相対的なモジュール管理はGAEで利用しようとすると、Appengineのbuildのプロセスでは相対的に取得できるはずのモジュールが取得できないため、デプロイがエラーになります。 その部分も回避策があるため次回の記事で書きます。
参考
go build keeps complaining that: go.mod has post-v0 module path - Stack Overflow