1.10 GO 依赖管理工具 go Modules(官方推荐)
以前写过一篇关于go管理依赖包工具 dep的文章,当时认为dep将会成为官方依赖工具,现在看来是自己图样图斯内幕破了,正如官方一直提到dep是“official experiment”官方实验项目的那样,随着go modules 在go1.11版推出,go1.12版功能不断改进,再到go1.13版完善优化,正式扶正。预计dep将来也只能定格在“official experiment”了。
Go Modules有哪些特点:
Go Modules是官方正式推出的包依赖管理项目,由Russ Cox (即Go 现在的掌舵人)推动,dep是“official experiment”仅此而已。
Go modules 出现的目的之一就是为了解决 GOPATH 的问题,也就相当于是抛弃 GOPATH 了。以前项目必须在
$GOPATH/src
里进行,现在Go 允许在$GOPATH/src
外的任何目录下使用 go.mod 创建项目。当然现在随着模块一起推出的还有模块代理协议(Module proxy protocol),通过这个协议我们可以实现 Go 模块代理(Go module proxy),也就是依赖镜像。
Tag必须遵循语义化版本控制,如果没有将忽略 Tag,然后根据你的 Commit 时间和哈希值再为你生成一个假定的符合语义化版本控制的版本号。
Go modules 还默认认为,只要你的主版本号不变,那这个模块版本肯定就不包含 Breaking changes,因为语义化版本控制就是这么规定的啊。
Global Caching 这个主要是针对 Go modules 的全局缓存数据说明,如下:
- 同一个模块版本的数据只缓存一份,所有其他模块共享使用。
- 目前所有模块版本数据均缓存在
$GOPATH/pkg/mod
和$GOPATH/pkg/sum
下,未来或将移至$GOCACHE/mod
和$GOCACHE/sum
下( 可能会在当$GOPATH
被淘汰后)。 - 可以使用
go clean -modcache
清理所有已缓存的模块版本数据。
另外在 Go1.11 之后 GOCACHE 已经不允许设置为 off 了,我想着这也是为了模块数据缓存移动位置做准备,因此大家应该尽快做好适配。
如果你的版本是go1.12或更早版本,这里建议升级到go1.13,来体验一把go modules,看它能给你带来哪些方面身心的愉悦。
本文将介绍使用Go Modules相关操作
1、安装Go 1.13或升级到Go 1.13
安装
2、配置环境变量
#修改 GOBIN 路径(可选)
go env -w GOBIN=$HOME/bin
#打开 Go modules
go env -w GO111MODULE=on
#设置 GOPROXY
go env -w GOPROXY=https://goproxy.cn,direct
go env -w: Go1.13 新增了 go env -w
用于写入环境变量,而写入的地方是 os.UserConfigDir
所返回的路径,需要注意的是 go env -w
不会覆写。需要指出,它不会覆盖系统环境变量。
GO111MODULE:
这个环境变量主要是 Go modules 的开关,主要有以下参数:
- auto:只在项目包含了 go.mod 文件时启用 Go modules,在 Go 1.13 中仍然是默认值,详见 :golang.org/issue/31857。
- on:无脑启用 Go modules,推荐设置,未来版本中的默认值,让 GOPATH 从此成为历史。
- off:禁用 Go modules。
GOPROXY:
这个环境变量主要是用于设置 Go 模块代理,它的值是一个以英文逗号 “,” 分割的 Go module proxy 列表,默认是proxy.golang.org,国内访问不了。这里要感谢盛傲飞和七牛云为中国乃至全世界的 Go 语言开发者提供免费、可靠的、持续在线的且经过CDN加速Go module proxy(goproxy.cn)。
其实值列表中的 “direct” 为特殊指示符,用于指示 Go 回源到模块版本的源地址去抓取(比如 GitHub 等),当值列表中上一个 Go module proxy 返回 404 或 410 错误时,Go 自动尝试列表中的下一个,遇见 “direct” 时回源,遇见 EOF 时终止并抛出类似 “invalid version: unknown revision…” 的错误。
3、创建你的项目
这里我们在$GOPATH/src
外,创建 /var/www/demo实例
mkdir /var/www/demo
cd /var/www/demo
新建main.go
package main
import (
"github.com/gin-gonic/gin"
"fmt"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
fmt.Println("hello world!")
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
4、在/var/www/demo根目录下
#生成go.mod文件
go mod init demo
打开go.mod文件,内容
module demo
go 1.13
go.mod 是启用了 Go moduels 的项目所必须的最重要的文件,它描述了当前项目(也就是当前模块)的元信息,每一行都以一个动词开头,目前有以下 5 个动词:
- module:用于定义当前项目的模块路径。
- go:用于设置预期的 Go 版本。
- require:用于设置一个特定的模块版本。
- exclude:用于从使用中排除一个特定的模块版本。
- replace:用于将一个模块版本替换为另外一个模块版本。
这里的填写格式基本为包引用路径+版本号,另外比较特殊的是 go $version
,目前从 Go1.13 的代码里来看,还只是个标识作用,暂时未知未来是否有更大的作用。
5、在/var/www/demo根目录下,执行 go build
go build
完成后项目
├── demo
├── go.mod
├── go.sum
└── main.go
项目中增加了go.sum、demo文件
go.sum文件内容
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
...
go.sum类似于比如 dep 的 Gopkg.lock 的一类文件,它详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go在今后的操作中保证项目所依赖的那些模块版本不会被篡改。
我们可以看到一个模块路径可能有如下两种:
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
前者为 Go modules 打包整个模块包文件 zip 后再进行 hash 值,而后者为针对 go.mod 的 hash 值。他们两者,要不就是同时存在,要不就是只存在 go.mod hash。
那什么情况下会不存在 zip hash 呢,就是当 Go 认为肯定用不到某个模块版本的时候就会省略它的 zip hash,就会出现不存在 zip hash,只存在 go.mod hash 的情况。
go.mod文件内容发生了变化,增加了
require github.com/gin-gonic/gin v1.4.0
默认使用最新版本的package。
更换依赖版本
查看gin所有历史版本
go list -m -versions github.com/gin-gonic/gin
github.com/gin-gonic/gin v1.1.1 v1.1.2 v1.1.3 v1.1.4 v1.3.0 v1.4.0
如果想更换依赖版本,比如v1.3.0,怎么办?
只需执行如下命令
go mod edit -require="github.com/gin-gonic/gin@v1.3.0"
go tidy #更新现有依赖
@后跟版本号,这个时候go.mod已经修改好了
require github.com/gin-gonic/gin v1.3.0
查看所有项目依赖的包
go list -m all
github.com/davecgh/go-spew v1.1.0
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3
github.com/gin-gonic/gin v1.4.0
github.com/golang/protobuf v1.3.1
github.com/json-iterator/go v1.1.6
github.com/mattn/go-isatty v0.0.7
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
github.com/modern-go/reflect2 v1.0.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.1.0
github.com/stretchr/testify v1.3.0
github.com/ugorji/go v1.1.4
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
golang.org/x/text v0.3.0
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/go-playground/assert.v1 v1.2.1
gopkg.in/go-playground/validator.v8 v8.18.2
gopkg.in/yaml.v2 v2.2.2
注意
使用go.mod管理依赖会对go get命令产生一定影响,
用
go help module-get
和go help gopath-get
分别去了解 Go modules 启用和未启用两种状态下的 go get 的行为用
go get
拉取新的依赖拉取最新的版本(优先择取 tag):
go get golang.org/x/text@latest
拉取
master
分支的最新 commit:go get golang.org/x/text@master
拉取 tag 为 v0.3.2 的 commit:
go get golang.org/x/text@v0.3.2
拉取 hash 为 342b231 的 commit,最终会被转换为 v0.3.2:
go get golang.org/x/text@342b2e
用
go get -u
更新现有的依赖
快速迁移项目至 Go Modules
- 在你项目的根目录下执行
go mod init 项目名
(项目名可不加),以生成 go.mod 文件。 - 执行 go mod tidy` 更新整理现有的依赖,删除未使用的依赖。
go mod 相关命令
go mod download
下载 go.mod 文件中指明的所有依赖
go mod tidy
整理现有的依赖,删除未使用的依赖。
go mod graph
查看现有的依赖结构
go mod init [module]
module为项目目录名,生成 go.mod 文件 (Go 1.13 中唯一一个可以生成 go.mod 文件的子命令)
go mod edit
编辑 go.mod 文件
go mod vendor
导出现有的所有依赖 (事实上 Go modules 正在淡化 Vendor 的概念)
go mod verify
校验一个模块是否被篡改过
go clean -modcache
清理所有已缓存的模块版本数据。
go mod
查看所有 go mod的使用命令。
参考资料:
https://segmentfault.com/a/1190000020522261
https://learnku.com/articles/27401
links
- 目录
- 上一节:
- 下一节: