這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
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
我們發現Glide是非常好的包管理解決方案,他將依賴包平展開存放在頂級vendor目錄中,如果一個包被另一個程式引用了,那麼這個包最好不要儲存外部依賴項。如果使用Glide,你可以在glide.yml檔案中指定依賴包,Glide會幫你管理,並使用正確的版本。