原文地址:http://www.gaoxuan1989.com/2017/07/10/golang-vendor-mange-dependices/
Vendor目錄介紹
隨著Go 1.5 release版本的發布,vendor目錄被添加到除了GOPATH
和GOROOT
之外的依賴目錄查找的解決方案。在Go 1.6之前,你需要手動的設置環境變量GO15VENDOREXPERIMENT=1
才可以使Go找到Vendor目錄,然而在Go 1.6之后,這個功能已經不需要配置環境變量就可以實現了。
Note,即使使用vendor,也必須在
GOPATH
中,在go的工具鏈中,你逃不掉GOPATH
的
那么查找依賴包路徑的解決方案如下:
- 當前包下的
vendor
目錄。 - 向上級目錄查找,直到找到src下的
vendor
目錄。 - 在
GOPATH
下面查找依賴包。 - 在
GOROOT
目錄下查找
一些建議
在使用vendor中,給出如下建議:
- 一個庫工程(不包含
main
的package)不應該在自己的版本控制中存儲外部的包在vendor\
目錄中,除非他們有特殊原因并且知道為什么要這么做。 - 在一個應用中,(包含
main
的package),建議只有一個vendor
目錄在代碼庫一級目錄。
上面建議的原因如下:
- 在目錄結構中的每個包的實例,即使是同一個包的同一個版本,都會打到最終的二進制文件中,如果每個人都單獨的存儲自己的依賴包,會迅速導致生成文件的二進制爆發(binary bloat)
- 在一個目錄的某個pacage類型,并不兼容在同一個package但是在不同目錄的類型,即便是同一個版本的package,那意味著loggers,數據庫連接,和其他共享的實例都沒法工作。
舉個例子
工程目錄如下:
- $GOPATH/src/github.com/mattfarina/golang-broken-vendor
- foo.go
- vendor/
- a/
- b/
- vendor/a/
在這個例子中,兩個a
package都是完全一樣的,b package在代碼庫中保存了a package,在頂級應用代碼中也引用了a包。
文件foo.go
做了很簡單的事情:
func main() {
var it a.A
it = "foo"
b.Do(it)
}
那么問題來了,當我們build的時候,發現出問題了,返回了下面的錯誤:
$ GO15VENDOREXPERIMENT=1 go build
./foo.go:12: cannot use it (type "github.com/mattfarina/golang-broken-vendor/vendor/a".A) as type "github.com/mattfarina/golang-broken-vendor/vendor/b/vendor/a".A in argument to b.Do
你可以clone這個測試工程到本地重現。
為什么用vendor目錄
如果我們已經使用GOPATH
去存儲packages了,問什么還需要使用vendor
目錄呢?這是一個很實戰的問題。
假如多個應用使用一個依賴包的不同版本?這個問題不只是Go應用,其他語言也會有這個問題。
vendor
目錄允許不同的代碼庫擁有它自己的依賴包,并且不同于其他代碼庫的版本,這就很好的做到了工程的隔離。
推薦
我們發現Glide是非常好的包管理解決方案,他將依賴包平展開存放在頂級vendor
目錄中,如果一個包被另一個程序引用了,那么這個包最好不要存儲外部依賴項。如果使用Glide,你可以在glide.yml
文件中指定依賴包,Glide會幫你管理,并使用正確的版本。