golang的包管理是一直是爲人詬病之處,從golang1.5引入的vendor機制,到準官方工具dep,目前爲止還沒一個簡便的解決方案。html
不過如今go modules隨着golang1.11的發佈而和咱們見面了,這是官方提倡的新的包管理,乃至項目管理機制,能夠再也不須要GOPATH的存在。git
如今modules機制仍在早期階段,因此golang提供了一個環境變量「GO111MODULE」,默認值爲auto,若是當前目錄裏有go.mod文件,就使用go modules,不然使用舊的GOPATH和vendor機制,由於在modules機制下go get只會下載go modules,這一行爲會在之後版本中成爲默認值,這裏咱們保持auto便可,若是你想直接使用modules而不須要從GOPATH過分,那麼把「GO111MODULE」設置爲on。github
modules和傳統的GOPATH不一樣,不須要包含例如src,bin這樣的子目錄,一個源代碼目錄甚至是空目錄均可以做爲module,只要其中包含有go.mod文件。golang
咱們就用一個空目錄來建立咱們的第一個module:web
要初始化modules,須要使用以下命令(假設已經安裝配置好golang1.11):chrome
go mod init [module name]
咱們的module叫test,因此就是:json
go mod init test
初始完成後會在目錄下生成一個go.mod文件,裏面的內容只有一行「module test」。websocket
那麼咱們怎麼進行包管理呢?別擔憂,當咱們使用go build,go test以及go list時,go會自動得更新go.mod文件,將依賴關係寫入其中。socket
若是你想手動處理依賴關係,那麼使用以下的命令:工具
go mod tidy
這條命令會自動更新依賴關係,而且將包下載放入cache。
下面咱們使用chromedp的一個簡單example做爲實驗代碼main.go,看下go modules是如何處理包的依賴關係的。
咱們手動運行go mod tidy:
查找並下載包
咱們發現多了一個go.sum,咱們看看它裏面是什麼內容:
沒錯,你已經猜到了,這是咱們直接引用的package和它自身須要的以來的版本記錄,go modules就是根據這些去找到須要的packages的。
順帶一提,若是咱們不作任何修改,默認會使用最新的包版本,若是包打過tag,那麼就會使用最新的那個tag對應的版本。
下面咱們使用go build來編譯咱們的代碼:
go build
值得注意的是,新增了一個編譯選項「-mod」,它有以下的可選值:
go build -mod=readonly
在這個模式下任何會致使依賴關係變更的狀況都將致使build失敗,前面提到過build能查找並更新依賴關係,使用這個選項能夠檢查依賴關係的變更。
go build -mod=vendor
意思是忽略cache裏的包,只使用vendor目錄裏的版本。
構建完成後目錄結構以下:
咱們的代碼成功構建了,包管理都由go modules替咱們完成了。
包管理的另一項重要功能就是包的版本控制。modules一樣能夠作到。
在介紹版本控制以前,咱們要先明確一點,若是上層目錄和下層目錄的go.mod裏有相同的package規則,那麼上層目錄的無條件覆蓋下層目錄,目的是爲了main module的構建不會被依賴的package所影響。
那麼咱們看看go.mod長什麼樣:
module test require github.com/chromedp/chromedp v0.1.2
若是有多個依賴,能夠是這樣的:
module github.com/chromedp/chromedp require ( github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013 github.com/disintegration/imaging v1.4.2 github.com/gorilla/websocket v1.2.0 github.com/knq/sysutil v0.0.0-20180306023629-0218e141a794 github.com/mailru/easyjson v0.0.0-20180606163543-3fdea8d05856 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 )
前面部分是包的名字,也就是import時須要寫的部分,而空格以後的是版本號,版本號遵循以下規律:
vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef vX.0.0-yyyymmddhhmmss-abcdefabcdef vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef vX.Y.Z
也就是版本號+時間戳+hash,咱們本身指定版本時只須要制定版本號便可,沒有版本tag的則須要找到對應commit的時間和hash值。
默認使用最新版本的package。
如今咱們要修改依賴關係了,咱們想使用chromedp 的v0.1.0版本,怎麼辦呢?
只須要以下命令:
go mod edit -require="github.com/chromedp/chromedp@v0.1.0"
@後面加上你須要的版本號。go.mod已經修改了:
module test require github.com/chromedp/chromedp v0.1.0
咱們還須要讓go modules更新依賴關係,這裏咱們手動go mod tidy以後:
注意顏色較深的那兩行,咱們已經切換到了v0.1.0版本了。
go modules是一個很大的主題,之後我還將進一步介紹它。
若是想進一步深刻go modules的使用,能夠閱讀個人這篇文章:再探go modules:使用與細節
由於go1.11剛發佈不久,這篇文件做爲探路,一定會有錯誤和疏漏,歡迎你們指正!