Go语言Modules包管理

Go 包管理简介

Go 语言在 1.11 之前都需要把代码放在 $GOPATH/src 中来保证可以引用到外部模块,包管理功能相对较弱,在 1.11 和 1.12 版之后提供了对模块的初步支持 —— Go Modules,相对于使用三方包管理库,使用 Go 自身的包管理功能肯定是优先选择,下面就来看下如何使用这个新的依赖管理工具。

模块是存储在文件树中的 Go 软件包的集合,表现形式为软件根目录中的 go.mod 文件,go.mod 文件定义了模块路径及其依赖关系,所有依赖都由模块路径及模块版本组成,如下:

1
2
3
4
require (
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.6.2
)

在 Go1.11 之后,只要当前目录或父目录具有 go.mod 文件,并且此目录不在 $GOPATH/src 目录中,就可以使用 Go Module,在 $GOPATH/src 内部,出于兼容性考虑,即使存在 go.mod,go 命令仍以旧的 GOPATH 模式运行。从 1.13 开始,Go Module 将是开发的默认模式。

也就是说,现在 Go 代码可以在任何地方运行,只需要添加下面环境变量即可,指的是如果项目不在 $GOPATH 下,则开启 Go Module,从 GoLang 1.13 开始,默认的 auto 意味着,只要当前目录具有 go.mod,那么无论项目在哪里,都开启 Go Module:

1
GO111MODULE=auto

使用 Go Module

下面来看一些 Go Module 的基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
# 初始化 Go Module
go mod init hello
# 注意,后面的 hello 是目标代码包名,通常就是你的项目名
# 此时会发现,在你的项目目录中会创建一个 go.mod 文件
# * 注意,如果你要拉取一些需要科学上网才可以下载的模块,需要在 bash 中配置代理
export http_proxy="socks5://xxx.xxx.xxx.xxx:1080"
export https_proxy="socks5://xxx.xxx.xxx.xxx:1080"

# 接着打开 go.mod 文件看看,里面至少会存在下面两行
module hello
go 1.14
# 此时我们已经建好了第一个 Go Module,接下来看如何加入依赖

使用 Go Module 的优势是,我们不需要关注 go.mod 文件内容,因为 Go 会自动去代码中寻找所需要的模块,然后下载这些模块并重写 go.mod 文件。

当你在项目中使用 go test、go build、go run main.go 时,go 会自动去下载 mod 中依赖的模块。

Go Module 在导入包时将自动使用这个包的最新版本,当检查到本地已经存在包文件时,Go Module 不会有其他操作。

使用下面命令可以列出当前所有依赖及其依赖项:

1
go list -m all

下面展示一个项目的 go.mod 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module hello

go 1.14

require (
github.com/aliyun/aliyun-oss-go-sdk v2.0.8+incompatible
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.6.2
github.com/go-resty/resty/v2 v2.2.0
github.com/gorilla/websocket v1.4.2
github.com/jinzhu/gorm v1.9.12
github.com/satori/go.uuid v1.2.0
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
)

除了 go.mod 之外,Go 还会维护一个名为 go.sum 的文件,其中包含特定模块版本内容的预期加密哈希。

Go 使用 go.sum 文件来确保这些模块在将来被下载时与当前下载的模块的一致性,来确保项目所依赖的模块不会被篡改。

升级 Go Module 依赖

升级某个模块,就像安装一个包一样:

1
go get golang.org/x/text

执行上面命令,会发现 golang.org/x/text 被升级到 v0.3.2,并且 go.sum 文件被重写了。

indirect 作用是表示当前模块不被直接依赖,而是通过其他模块进行间接依赖。

使用下面命令可以列出模块可用的依赖版本:

1
2
go list -m -versions github.com/jinzhu/gorm
# github.com/jinzhu/gorm v1.9.1 v1.9.2 v1.9.3 v1.9.4 v1.9.5 v1.9.6 v1.9.7 v1.9.8 v1.9.9 v1.9.10 v1.9.11 v1.9.12

可以这样来指定安装某版本:

1
go get github.com/jinzhu/gorm@v1.9.12

go 默认会使用 github.com/jinzhu/gorm@latest 形式来获取最新版本的依赖。

移除 Go Module 依赖

当一个包已经不再使用时,可以使用下面命令移除这个包的依赖关系

1
go mod tidy

其他命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# GOPROXY 环境变量可以设置代理服务器
export GOPROXY="https://goproxy.cn,direct"

# GOPRIVATE 与 GONOPROXY 两个环境变量是一样的, 他们定义了哪些仓库是不需要经过代理的,例如:
export GOPRIVATE="*.corp.example.com,rsc.io/private"

# 将模块下载到本地缓存
go mod download

# 从工具或脚本编辑go.mod
go mod edit

# 打印模块需求图
go mod graph

# 生成依赖项的自动生成副本
go mod vendor

# 验证依赖项是否具有预期内容
go mod verify

# 解释为什么需要包或模块
go mod why
◀        
        ▶