简介
go 1.11以后提供了新的管理依赖的方式, 使得管理依赖,尤其是依赖版本更加的明确且易于管理, 这种方式就是go mod
在项目的根目录有个go.mod
的文件, 文件的内容是所有依赖的go package的集合, 以文件树的形式存在.
文件中中明确的说明了go所有依赖的路径及版本
配置
# 这三个路径一直存在
export GOPATH=$HOME/go
export GOROOT=/usr/local/go
export GOBIN=$GOPATH/bin
# 支持 go mod 需要配置如下两个选项
# 开启go mod
export GO111MODULE=on
# 配置go mod使用的依赖库代理服务器
export GOPROXY=https://goproxy.io
创建一个新的go mod
package hello
import "rsc.io/quote"
func Hello() string {
return quote.Hello()
}
# write a test file
package hello
import "testing"
func TestHello(t *testing.T) {
want := "Hello, world."
if got := Hello(); got != want {
t.Errorf("Hello() = %q, want %q", got, want)
}
}
执行初始化命令
$ go mod init example.com/hello
查看生成的go.mod, 执行完初始化后, 在项目的根目录有go.mod文件生成
$ cat go.mod
module example.com/hello
go 1.13
执行go test
[~/go/src/hello]$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
PASS
ok example.com/hello 0.008s
再次查看go.mod文件
module example.com/hello
go 1.13
require rsc.io/quote v1.5.2
自动增加了 我们依赖的rsc.io/quote 目录
查看我们依赖的module
[~/go/src/hello]$go list -m all
example.com/hello
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
除了自动生成的go.mod文件, go还生成了名为go.sum的文件, 引用模块的hash值
查看go.sum文件,
[~/go/src/hello]$cat go.sum
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
更新go mod 依赖的版本
go get golang.org/x/text
go: finding golang.org/x/text v0.3.0
go: downloading golang.org/x/text v0.3.0
go: extracting golang.org/x/text v0.3.0
$ go test
PASS
ok example.com/hello 0.013s
自动更新
$ go list -m all
example.com/hello
golang.org/x/text v0.3.0
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
$ cat go.mod
module example.com/hello
go 1.12
require (
golang.org/x/text v0.3.0 // indirect
rsc.io/quote v1.5.2
)
$
更新sampler 试一试
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 test
--- FAIL: TestHello (0.00s)
hello_test.go:8: Hello() = "99 bottles of beer on the wall, 99 bottles of beer, ...", want "Hello, world."
FAIL
exit status 1
FAIL example.com/hello 0.014s
$
单测失败了, 说明最新的包和我们本地的代码已经不兼容了, 我们看看sampler的历史版本
$ 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
我们回退到上一版本, v1.3.1 尝试一下
$ go get rsc.io/sampler@v1.3.1
go: finding rsc.io/sampler v1.3.1
go: downloading rsc.io/sampler v1.3.1
go: extracting rsc.io/sampler v1.3.1
$ go test
PASS
ok example.com/hello 0.022s
$
添加一个新版本的依赖
我们升级一下 "rsc.io/quote" 升级为 "rsc.io/quote/v3"
package hello
import (
"rsc.io/quote"
quoteV3 "rsc.io/quote/v3"
)
func Hello() string {
return quote.Hello()
}
func Proverb() string {
return quoteV3.Concurrency()
}
增加新的test
func TestProverb(t *testing.T) {
want := "Concurrency is not parallelism."
if got := Proverb(); got != want {
t.Errorf("Proverb() = %q, want %q", got, want)
}
}
执行test
$go test
go: finding rsc.io/quote/v3 v3.1.0
go: downloading rsc.io/quote/v3 v3.1.0
go: extracting rsc.io/quote/v3 v3.1.0
PASS
ok example.com/hello 0.006s
查看依赖的模块
$ go list -m rsc.io/q...
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
$
增量或者灰度迁移的能力在大型的程序中尤为重要
全部升级为新版本
查看新版本支持的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
$
升级调用的函数
package hello
import quoteV3 "rsc.io/quote/v3"
func Hello() string {
// 放弃使用旧版的接口, 改为V3的接口
return quoteV3.HelloV3()
}
func Proverb() string {
return quoteV3.Concurrency()
}
已经移除了旧版接口, 我们不在需要对V3做别名处理, 所以可以改成如下
package hello
import "rsc.io/quote/v3"
func Hello() string {
return quote.HelloV3()
}
func Proverb() string {
return quote.Concurrency()
}
查看依赖的版本
$go list -m all
example.com/hello
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1
可以看到旧版我们都已经去除了, 但是没有移除, 需要go mod tidy了
go mod tidy 清楚我们不需要的模块
$go mod tidy
$go list -m all
example.com/hello
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1
$cat go.mod
module example.com/hello
go 1.13
require (
golang.org/x/text v0.3.2 // indirect
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1 // indirect
)
结论
- go mod init 初始化一个新的module
- go build, go test, 其它内置的包构建命令来更新我们需要的依赖到go.mod文件
- go list -m all 列出我们当前所有依赖的module
- go get 获取指定的升级版本
- go mod tidy 更新操作, 去除不需要的依赖