go module了解
前言
Go 的包管理方式是逐漸演進的, 最初是 monorepo 模式,所有的包都放在 GOPATH 里面,使用類似命名 空間的包路徑區分包,不過這種包管理顯然是有問題,由於包依賴可能會引入破壞性更新,生產環境和測試環 境會出現運行不一致的問題。
從 v1.5 開始開始引入 vendor 包模式,如果項目目錄下有 vendor 目錄,那么 go 工具鏈會優先使 用 vendor 內的包進行編譯、測試等,這之后第三方的包管理思路都是通過這種方式來實現,比如說由社區 維護准官方包管理工具 dep。
不過官方並不認同這種方式,在 v1.11 中加入了 Go Module 作為官方包管理形式,就這樣 dep 無奈的 結束了使命。最初的 Go Module 提案的名稱叫做 vgo,下面為了介紹簡稱為 gomod。不過在 v1.11 和 v1.12 的 Go 版本中 gomod 是不能直接使用的。可以通過 go env 命令返回值的 GOMOD 字段是否為空 來判斷是否已經開啟了 gomod,如果沒有開啟,可以通過設置環境變量 export GO111MODULE=on 開啟。
哈哈,是時候開始使用go module了
開啟go mod
GO111MODULE 有三個值:
- on 打開,不會去 GOPATH 下面查找依賴包。
- off 關閉
- auto Golang 自己檢測是不是使用 modules 功能。
linux:
export GO111MODULE=on // 開啟 export GO111MODULE=of // 關閉
簡單使用
1、初始化
需要注意的是:我們使用go mod不要在GOPATH目錄下面
我們在GOPATH以為的目錄建立一個項目hello,然后在根目錄下面執行
liz@liz-PC:~/goWork/src/hello$ go mod init hello go: creating new go.mod: module hello
可以看到go.mod已經生成在了項目的根木下面,然后我們去看下里面的內容
liz@liz-PC:~/goWork/src/hello$ cat go.mod module hello go 1.13
發現里面還沒有任何的依賴,因外我們的項目代碼還沒有創建,那么接下來去創建代碼,看看mod如何進行 依賴包的管理,創建hello.go
package hello import "rsc.io/quote" func Hello() string { return quote.Hello() }
然后創建testHello.go來測試
package hello import "testing" func TestHello(t *testing.T) { want := "你好,世界。" if got := Hello(); got != want { t.Errorf("Hello() = %q, want %q", got, want) } }
因為我們在GOPATH外,所以rsc.io/quote是找不到的。正常執行test找不到這些包,是會報錯的,但是我們 使用go mod這些就不會發生了,那我們執行go test看下
go test go: finding rsc.io/quote v1.5.2 go: downloading rsc.io/quote v1.5.2 go: extracting rsc.io/quote v1.5.2 go: downloading rsc.io/sampler v1.3.0 go: extracting rsc.io/sampler v1.3.0 go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: finding rsc.io/sampler v1.3.0 go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c --- FAIL: TestHello (0.00s) hello_test.go:8: Hello() = "你好,世界。", want "Hello, world." FAIL exit status 1 FAIL hello 0.003s
發現會主動幫我們下載所需要的依賴包。(go run/test),或者 build(執行命令 go build)的時候都會幫助 我們下載所需要的依賴包。並且這些包都會下載到 $GOPATH/pkg/mod 下面,不同版本並存。
這時候有些包是不能下載的,比如golang.org/x下的包,這時候可以使用代理的方式解決,go也提供了GoProxy 來幫助我們做這些事情,具體看下文GoProxy。
2、依賴升級(降級)
可以使用如下命令來查看當前項目依賴的所有的包。
$ go list -m all hello golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c rsc.io/quote v1.5.2 rsc.io/sampler v1.3.0
如果我們想要升級(降級)某個package則只需要go get就可以了,比如:
go get package@version
同時我們可以可以查看這個包所支持的版本,選擇合適的進行升級
go list -m -versions package
栗子:
版本查看:
$ go list -m -versions rsc.io/sampler rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
查看當前的版本:
$ go list -m all hello golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c rsc.io/quote v1.5.2 rsc.io/sampler v1.3.1
可以發現 rsc.io/sampler 現在的版本是v1.3.1,那么他最高支持的是v1.99.99
版本升級:
$ go get rsc.io/sampler go: finding rsc.io/sampler v1.99.99 go: downloading rsc.io/sampler v1.99.99 go: extracting rsc.io/sampler v1.99.99
當我們沒有選擇升級的版本,默認的版本就是最高的
升級完成之后我們再來查看當前的版本
$ go list -m all hello golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c rsc.io/quote v1.5.2 rsc.io/sampler v1.99.99
rsc.io/sampler的版本已經變成了v1.99.99,同樣我們也可以對它的版本進行降級,方法和升級的方法一樣
$ go get rsc.io/sampler@v1.3.1 $ go list -m all hello golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c rsc.io/quote v1.5.2 rsc.io/sampler v1.3.1
哈哈,已經變成了v1.3.1,降級成功了。
3、更改使用的pkg
讓我們完成使用rsc的轉換。rsc.io/quote 只使用rsc.io/quote/v3。首先我們看下 rsc.io/quote/v3支持的api,因為相比於rsc.io/quote, rsc.io/quote/v3所支持的api可能已經發生了改變。
$ go doc rsc.io/quote/v3 package quote // import "rsc.io/quote" Package quote collects pithy sayings. func Concurrency() string func GlassV3() string func GoV3() string func HelloV3() string func OptV3() string
我們來更新我們的代碼 hello.go
package hello import "rsc.io/quote/v3" func Hello() string { return quote.HelloV3() }
然后執行go test
$ go test go: downloading rsc.io/quote/v3 v3.1.0 go: extracting rsc.io/quote/v3 v3.1.0 PASS ok hello 0.003s
發現下載了rsc.io/quote/v3,並且成功運行
4、清除不需要的依賴包
上面我們把rsc.io/quote換成了rsc.io/quote/v3,那么rsc.io/quote就已經不在需要了,這時候我們可以選擇清除掉這些不需要的包
$ go list -m all hello golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c rsc.io/quote v1.5.2 rsc.io/quote/v3 v3.1.0 rsc.io/sampler v1.3.1 $ cat go.mod module hello go 1.13 require ( rsc.io/quote v1.5.2 rsc.io/quote/v3 v3.1.0 rsc.io/sampler v1.3.1 // indirect )
我們知道go build(test)只會在運行的時候檢查少了那些包,然后進行加載。但是不能確定何時可以安全地刪除某些東西。 僅在檢查模塊中的所有軟 件包以及這些軟件包的所有可能的構建標記組合之后,才能刪除依賴項。普通的build命令不會加載此信息,因此它不能安全地刪除依賴項。
可以使用go mod tidy清除不需要的包
$ go mod tidy $ go list -m all hello golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c rsc.io/quote/v3 v3.1.0 rsc.io/sampler v1.3.1 $ cat go.mod module hello go 1.13 require ( rsc.io/quote/v3 v3.1.0 rsc.io/sampler v1.3.1 // indirect ) $ go test PASS ok hello 0.003s
GoProxy
proxy 顧名思義,代理服務器。對於國內的網絡環境,有些包是下載不下來的,當然有的人會用梯子去解決。go官方也意識到了這一點,提供了GOPROXY 的方法讓我們下載包。要使用 GoProxy 只需要設置環境變量 GOPROXY 即可。目前公開的 GOPROXY 有:
- goproxy.io
- goproxy.cn: 由七牛雲提供,這是一個應屆生發起的項目,好強
當然你也可以實現自己的 GoProxy 服務,比如項目中的依賴包含外部依賴和內部依賴的時候,那么只需要實現 module proxy protocal 協議即可。
值得注意的是,在最新 release 的 Go 1.13 版本中默認將 GOPROXY 設置為 https://proxy.golang.org,這個對於國內的開發者是無法直接 使用的。所以如果升級了 Go 1.13 版本一定要把 GOPROXY 手動改掉。
export GOPROXY=https://goproxy.io
總結
Go 1.11之后的版本都支持go module了, modules 在 Go 1.13 的版本下是默認開啟的。國內使用需要修改GoProxy的代理。
下面是經常使用到的命令:
go mod init 創建初始化go module go build, go test 運行的時候就會加載所需要的依賴項 go list -m all 打印檔當前模塊所有的依賴 go get 更改模塊依賴的版本 go mod tidy 刪除不適用的依賴
參考
【Using Go Modules】https://blog.golang.org/using-go-modules
【Go Modules 不完全教程】https://mp.weixin.qq.com/s/v-NdYEJBgKbiKsdoQaRsQg