1. 程式人生 > >Golang的包依賴管理 (package dependency manager)

Golang的包依賴管理 (package dependency manager)

 Golang 的開發者對GOPATH都不陌生, 它是進行go 專案開發的’workspace’。 go專案的原始碼,可執行檔案,以及依賴庫的存放都是通過gopath的相關目錄結構進行組織的,而且go原生的依賴管理也是使用GOPATH進行組織。 如當前專案中import “github.com/helloworld”, 則在使用go get編譯當前專案時,”helloworkd”的原始碼會被download到$GOPATH/src/github.com/hellowrold的目錄中。 而且go get的過程是遞迴的,helloworld中依賴的專案也會被逐一download到gopath當中。go get會呼叫對應的版本控制工具獲取原始碼, 如果被下載的專案使用的git那麼,go get 實際上就是呼叫的gitclone 複製一份原始碼到本地,當然go get 也支援其他的一些版本控制工具。

我們知道GOPATH是可以指定多個目錄的,例如下面這種情況。那麼下面這種設定意味著什麼呢?

GOPATH="/home/ansendong/golang:/var/www/personal/app1:/var/www/personal/app2:/var/www/personal/app3"

1)/home/ansendong/golang  是在GOPATH的第一個目錄,所有的使用’go get’ 下載的依賴包全部會放到這裡。

2)編譯的時候go 會去GOPATH中包含的所有目錄中,查詢依賴的庫, 當所有的目錄都沒有所依賴的庫時,通過go get 去下載依賴包。

3)編譯時,GO會在GOPATH中查詢依賴,如果在GOPATH的目錄中存在多個庫的copy, 則編譯器會使用第一個找到庫的依賴。

這樣第三方包就會預設放置在第一個路徑中,而你可以在第二個路徑下編寫自己的程式碼。 雖然 Go 語言本身已經提供了相當強大的包管理方式了,但是仍然有一些問題:

1)隔離不同專案的環境,  第三方依賴沒有版本控制,如果多個專案同事依賴同一個第三方庫,但是存在版本衝突,就會出現麻煩。

2)控制某個依賴包的版本, go get總是下載最新版本的第三方包,而我們的目的只是想依賴某個穩定版本,如果第三方包的介面更新,就會導致構建失敗。我們不能控制依賴的版本。

3) Go 本身的版本(相對簡單)

結合實際的一些經驗,依賴較多的大的專案建議使用 godep+ 獨立的gopath的方式,即為單個專案建立唯一的gopath(建立單個workspace).

1,  使用獨立的gopath徹底解決了隔離專案環境的問題

2,  使用godep可以記錄當前依賴的版本,godep restore 會根據Godep.json中記錄的依賴的版本,download所有的依賴到當前的GOPATH。

達到可重複構建的目的,同時也可以實現第三方依賴包

但是在一個專案中依賴另外一個使用dep管理依賴包的專案時還是有一些小問題的 , 真TMD繞嘴。

比如我的一個專案中使用到了kube-client,K8S當中的一個包, 而 K8S本身也是使用godep去管理它的依賴。

1)go get 我的專案A,  因為A import 了kube-client, 所有會download整個K8S到 GOPATH, 但是在這一步驟裡並沒有download K8S的依賴包到GOPATH, 為什麼? 因為K8S的vendor目錄中已經包含了kubernetes本身的依賴。

2)godep save ./… , 這個過程會把kubeclient的原始碼還有kubeclient的依賴包從GOPATH copy到專案A的vendor中。這一步報錯,因為缺少kubernetesclient的依賴包,原因是上一步中沒有把kubernetes的依賴包download到GOPATH。

3)回到K8S專案中, 呼叫godep restore. 把k8s的依賴包全部重新download到GOPATH中

4)回到專案A, 重新使用命令godep save ./…,  成功。 會把kubeclient 以及kubeclient的依賴copy到專案A的vendor目錄當中。