之前 go mod
用的比較少,而且一直聽社區有各種抱怨,所以也興趣寥寥。新公司的項目直接使用了 go mod
,本來覺得無非是個簡單的工具,不需要學習,結果在一個簡單的依賴上卻浪費了很多時間。
先來看看我碰到的例子:
package main
import "fmt"
import registry "github.com/apache/dubbo-go/registry"
import zk "github.com/apache/dubbo-go/registry/zookeeper"
import xds "mosn.io/mosn/pkg/xds"
func main() {
var r registry.Registry
fmt.Println(r)
var z zk.Option
fmt.Println(z)
var x xds.Client
fmt.Println(x)
}
導致衝突的原因,可以隨便找個目錄 go mod init
一下,然後 go build
。然而編譯不過去。實際上是因爲 go mod
幫我選擇了 github.com/envoyproxy/go-control-plane
這個庫的錯誤版本,mosn
中直接依賴了這個庫的 0.6.9
版本,但是在 go build
的時候被非常“好心”地升級到了 0.8.0
,怎麼回事?
圖比較明顯,go mod why
現在顯然是一坨垃圾。只能通過 go mod graph|grep
來找原因。
這裏有個問題,我的程序其實並沒有依賴 dubbo-go
裏的 consul
這部分代碼,我們用 go mod vendor
把程序的外部依賴保存下來,也可以得到驗證:
/Users/xargin/test/gomod/vendor/github.com/apache/dubbo-go
~/t/g/v/g/a/dubbo-go git:master ❯❯❯ grep -iR consul ./
~/t/g/v/g/a/dubbo-go git:master ❯❯❯
所以這裏 go mod
幫我們選擇了一個連間接依賴都算不上的外部庫指定的版本來進行更新。知道原因的話,解決方法也就簡單了,本來對 github.com/envoyproxy/go-control-plane
有依賴的也就只有 mosn
,只要 replace
就好:
replace github.com/envoyproxy/go-control-plane => github.com/envoyproxy/go-control-plane v0.6.9
這裏的問題還算簡單,如果碰上大項目,出了 go build
不出來的問題,還得用 go mod graph
一個一個去 grep
,心累。
現在 go mod
提供的工具其實也並不方便。看看前幾天的一篇文章:《etcd go module 的災難》[1]。
用起來真是不省心。
有一些網友已經做了 go mod graph
的可視化,但是碰上大項目,基本出來的圖不是給人看的:
對於碰到依賴衝突的用戶,其實主要是想看關鍵包的依賴路徑。以及衝突發生的路徑。
簡單寫了一個小工具[2]來支持這個訴求。上面提到的例子會輸出很多可能衝突的 pkg
,找一下 go-control-plane
:
Conflict in pkg github.com/envoyproxy/go-control-plane paths are:
cch.com/c -> github.com/apache/[email protected] -> github.com/hashicorp/[email protected] -> github.com/envoyproxy/[email protected]
cch.com/c -> mosn.io/[email protected] -> github.com/envoyproxy/[email protected]
參考資料
[1]
《etcd go module 的災難》: https://colobu.com/2020/04/09/accidents-of-etcd-and-go-module/
[2]小工具: https://github.com/cch123/gomod-conflict-detect