Go的包管理工具(一)

在前面轉載了系列文章:Golang 須要避免踩的 50 個坑,總得來講閱讀量都挺大。今天這篇文章,我們一塊兒聊聊Go的依賴包管理工具。java

背景

每一門語言都有其依賴的生態,當咱們使用Java語言的時候,使用Maven或者Gradle管理包依賴。早期的Go被不少開發者所詬病的一個問題就是依賴包的管理。Golang 1.5 release版本的發佈以前,只能經過設置多個GOPATH的方式來解決這個問題,例如:我兩個工程都依賴了Beego,但A工程依賴的是Beego 1.1,B工程依賴的是Beego 1.7,我必須設置兩個GOPATH來區分,而且在切換工程的時候GOPATH也得切換,無比痛苦。在Golang 1.5 release 開始支持除了GOROOTGOPATH以外的依賴管理:vender,官方 wiki 推薦了多種支持這種特性的包管理工具,如:Godep、gv、gvt、glide、govendor和官方的dep等。git

環境準備

安裝Go

筆者是Mac系統,安裝Go有多種方式,經過brew、下載源碼安裝go等方式能夠安裝go。github

在bash_profile中自定義GOPATH和GOBIN位置:golang

GOROOT=/usr/local/go
export GOPATH=/Users/user/aoho/go-workspace
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN:$GOROOT/bin
複製代碼

安裝完成以後,查看go的環境變量:go envdocker

GOARCH="amd64"
GOBIN="/usr/local/go/bin/go"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/user/aoho/go-workspace"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/st/gkm45qzd2tv8mc32my38_n_00000gp/T/go-build646095787=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
複製代碼

go的版本爲:go version go1.9.3 darwin/amd64json

GOPATH和GOROOT

GOROOT不是必需要設置的。默認go會安裝在/usr/local/go下,但也容許自定義安裝位置,GOROOT的目的就是告知go當前的安裝位置,編譯的時候從GOROOT去找SDK的system libariry。bash

如上面展現的結果,筆者使用的就是默認的安裝地址,也能夠經過 export GOROOT=$HOME/go1.9.3指定。微信

GOPATH必需要設置,但並非固定不變的。GOPATH的目的是爲了告知go,須要代碼的時候,去哪裏查找。注意這裏的代碼,包括本項目和引用外部項目的代碼。GOPATH能夠隨着項目的不一樣而從新設置。maven

GOPATH下會有3個目錄:src、bin、pkg。ide

  • src目錄:go編譯時查找代碼的地方;
  • bin目錄:go get這種bin工具的時候,二進制文件下載的目的地;
  • pkg目錄:編譯生成的lib文件存儲的地方。

包管理

上面小節提到,依賴的代碼去$GOPATH指定的位置尋找,這部分代碼多是本項目或者外部引用的項目。下面依次介紹這兩種狀況。

內部依賴管理

如筆者示例route_auth.go的引入:

import (
	"gwp/Chapter_2_Go_ChitChat/chitchat/data"
	"net/http"
)
複製代碼

route_auth.go須要引用data/user.go,項目結構以下:

編譯時會去$GOPATH/src/目錄去查找須要的代碼,所以只要上面data/user.go在$GOPATH/src/gwp/Chapter_2_Go_ChitChat/chitchat/data裏面,go編譯的時候就能找到。

外部依賴管理

對於外部依賴的管理,在最開始go沒有像java使用maven來管理依賴包、包版本,而是直接使用GOPATH來管理外部依賴。

GOPATH來管理外部依賴

go容許import不一樣代碼庫的代碼,例如github.com, k8s.io, golang.org等等;對於須要import的代碼,可使用 go get 命令取下來放到GOPATH對應的目錄中去。例如go get github.com/globalsign/mgo,會下載到$GOPATH/src/github.com/globalsign/mgo中去,當其餘項目在import github.com/globalsign/mgo的時候也就能找到對應的代碼了。

看到這裏也就明白了,對於go來講,其實並不在乎你的代碼是內部仍是外部的,總之都在GOPATH裏,任何import包的路徑都是從GOPATH開始的;惟一的區別,就是內部依賴的包是開發者本身寫的,外部依賴的包是go get下來的。Go 語言原生包管理的缺陷:

  • 能拉取源碼的平臺頗有限,絕大多數依賴的是 github.com
  • 不能區分版本,以致於令開發者以最後一項包名做爲版本劃分
  • 依賴 列表/關係 沒法持久化到本地,須要找出全部依賴包而後一個個 go get
  • 只能依賴本地全局倉庫(GOPATH/GOROOT),沒法將庫放置於局部倉庫($PROJECT_HOME/vendor)

vendor

依賴GOPATH來解決go import存在的問題在上面小節已經列舉。爲了解決這個問題,go在1.5版本引入了vendor屬性(默認關閉,須要設置go環境變量GO15VENDOREXPERIMENT=1),並在1.6版本中默認開啓了vendor屬性。

簡單來講,vendor屬性就是讓go編譯時,優先從項目源碼樹根目錄下的vendor目錄查找代碼(能夠理解爲切了一次GOPATH),若是vendor中有,則再也不去GOPATH中去查找。

以kube-keepalived-vip爲例。該項目會調用k8s.io/kubernetes的庫(Client),但若是你用1.5版本的kubernetes代碼來編譯keepalived,會編譯不過。1.5版本中代碼有變化,已經沒有這個Client了。這就是前面說的依賴GOPATH來解決go import所帶來的問題,代碼不對上了。

kube-keepalived-vip項目用vendor目錄解決了這個問題:該項目把全部依賴的包都拷貝到了vendor目錄下,對於須要編譯該項目的人來講,只要把代碼從github上clone到$GOPATH/src之後,就能夠進去go build了(注意,必須將kube-keepalived-vip項目拷貝到$GOPATH/src目錄中,不然go會無視vendor目錄,仍然去$GOPATH/src中去找依賴包)。

經過如上vendor解決了部分問題,然而又引發了新的問題:

  • vendor目錄中依賴包沒有版本信息。這樣依賴包脫離了版本管理,對於升級、問題追溯,會有點困難。
  • 如何方便的獲得本項目依賴了哪些包,並方便的將其拷貝到vendor目錄下?依靠人工實在不現實。

爲了解決這些問題,開源社區在vendor基礎上開發了多個管理工具,比較經常使用的有godep、govendor glide等,go官方發佈了dep。

godep

godep是解決包依賴的管理工具,原理是掃描記錄版本控制的信息,並在go命令前加殼來作到依賴管理。godep早期版本並不依賴vendor,因此對go的版本要求很鬆,go 1.5以前的版本也能夠用,只是行爲上有所不一樣。在vendor推出之後,godep也改成使用vendor了。godep 建議在 golang 1.6 之後使用,且godep 依賴 vendor 。

godep的使用者衆多,如docker,kubernetes, coreos等go項目不少都是使用godep來管理其依賴,固然緣由多是早期也沒的工具可選。

go get -u -v github.com/tools/godep
複製代碼

經過如上的命令安裝,成功安裝後,在$GOPATH的bin目錄下會有一個godep可執行的二進制文件,後面執行的命令都是用這個,建議這個目錄加入到全局環境變量中。

編譯運行

由於go命令是直接到GOPATH目錄下去找第三方庫,且在1.6之後支持vendor方式編譯,而使用godep下載的依賴庫放到Godeps/workspace目錄下的,可是不影響繼續使用依賴GOPATH目錄,因此與三方工具自己不衝突。所以使用:

godep go build main.go
複製代碼

godep中的go命令,就是將原先的go命令加了一層殼,執行godep go的時候,會將當前項目的workspace目錄加入GOPATH變量中。

檢出依賴

若是要增長新的依賴包:

  • 運行 go get github.com/globalsign/mgo
  • 代碼中 import github.com/globalsign/mgo

項目編寫好了,使用GOPATH的依賴包測試ok了的時候,執行:

godep save
複製代碼

如上的命令將會自動掃描當前目錄所屬包中import的全部外部依賴庫(非系統庫),並將全部的依賴庫下來下來到當前工程中,產生文件 Godeps/Godeps.json 文件。

godep save時godep把全部依賴包代碼從GOPATH路徑拷貝到Godeps目錄下,並去除代碼管理目錄。這個用處主要是爲了支撐godep go tool的一系列操做,尤爲是git clone了代碼庫下來後,一般直接用godep go install xxx便可完成編譯,必定程度上可以緩解golang比較嚴格的代碼路徑和包管理帶來的煩惱。在沒有 Godeps 文件的狀況下,生成模組依賴目錄vendor文件夾。若是是開發依賴使用三方庫,須要固定使用某個版本,請徹底提交Godeps和vendor文件夾。

依賴包會有更新,如何更新依賴包?能夠經過以下的命令實現。

  • 運行 go get -u github.com/globalsign/mgo
  • 運行 godep update github.com/globalsign/mgo
拉取依賴 restore

經過命令 godep restore同步依賴庫,若是下載的項目中只有Godeps.json文件,而沒有包含第三庫則可使用godep restore這個命令將全部的依賴庫下來到$GOPATH\src中用於開發。

godep restore執行時,godep會按照Godeps/Godeps.json內列表,依次執行go get -d -v來下載對應依賴包到GOPATH路徑下。

govendor

govendor是在vendor以後出來的,功能相對godep多一點,不過就核心問題的解決來講基本是同樣的。該工具將項目依賴的外部包拷貝到項目下的 vendor 目錄下,並經過 vendor.json 文件來記錄依賴包的版本,方便用戶使用相對穩定的依賴。

go get -u github.com/kardianos/govendor
複製代碼

如上的命令便可安裝govendor,govendor生成vendor目錄的時候須要2條命令:

  • govendor init生成vendor/vendor.json,此時文件中只有本項目的信息
  • govendor add +external更新vendor/vendor.json,並拷貝GOPATH下的代碼到vendor目錄中。 govendor還能夠直接指定依賴包版原本獲取包。

govendor的依賴包主要有如下多種類型:

使用步驟

進入項目的根目錄。

# 建立 vendor 文件夾和 vendor.json 文件
govendor init

# 從 $GOPATH 中添加依賴包,會加到 vendor.json
govendor add +external

# 列出已經存在的依賴包
govendor list

# 找出使用的對應包
govendor list -v fmt

# 拉取指定版本的包
govendor fetch golang.org/x/net/context@a4bbce9fcae005b22ae5443f6af064d80a6f5a55
govendor fetch golang.org/x/net/context@v1   # Get latest v1.*.* tag or branch.
govendor fetch golang.org/x/net/context@=v1  # Get the tag or branch named "v1".
複製代碼

相對上面的工具來講,govendor功能更加豐富。

總結

本文主要介紹了幾種go依賴包管理工具,首先介紹了go的環境安裝,配置對應的環境變量;其次講到包管理的兩種類型:內部依賴和外部依賴的管理。內部依賴包的管理很簡單,go原生的外部依賴包管理存在不少缺陷,隨後介紹了開源社區推出的godep和govendor,在vendor基礎上進行了功能的完善。還有目前經常使用的包依賴管理工具glide和官方的dep,將會在後面的文章介紹,盡請期待。

訂閱最新文章,歡迎關注個人公衆號

微信公衆號

參考

go依賴包管理工具對比

相關文章
相關標籤/搜索