Go 语言依赖管理 | 青训营
1. Go Modules简介
Go Modules是Go官方推出的一个Go包管理方案,基于vgo演进而来,具有:可以使得包的管理更加简单;支持版本管理;允许同一个模块多个版本共存;可以校验依赖包的哈希值、确保包的一致性;内置在绝大多数go命令中,包括go get\go build\go install\go run\go test\go list等命令;具有Global Caching特性,不同项目的相同模块版本,只会在服务器上缓存一份。以后Go包管理方案会逐渐统一到Go Modules
2. 包(oackage)和模块(module)
Go 程序被组织到 Go 包中,Go 包是同一目录中一起编译的 Go 源文件的集合。在一个源文件中定义的函数、类型、变量和常量,对于同一包中的所有其他源文件可见。模块是存储在文件树中的 Go 包的集合,并且文件树根目录有 go.mod 文件。go.mod 文件定义了模块的名称及其依赖包,通过导入路径和版本描述一个依赖。
模块和包的关系更像是集合和元素的关系,包属于模块,一个模块是零个或者多个包的集合。下面的代码段,引用了一些包:
例子1 Hello World
import (
"fmt"
"github.com/spf13/pflag"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/marmotedu/iam/internal/apiserver"
)
fmt、github.com/spf13/pflag、github.com/marmotedu/iam/internal/apiserver都是Go包
Go中有4种类型的包:
- Go 标准包:在 Go 源码目录下,随 Go 一起发布的包。
- 第三方包:第三方提供的包,比如来自于 github.com 的包。
- 匿名包:只导入而不使用的包。通常情况下,我们只是想使用导入包产生的副作用,即引用包级别的变量、常量、结构体、接口等,以及执行导入包的init()函数。
- 内部包:项目内部的包,位于项目目录下。
3. Go Modues命令
| 命令 | 含义 |
|---|
| download | 下载go.mod文件中记录的所有依赖包 |
| edit | 编辑go.mod文件 |
| graph | 查看现有的依赖结构 |
| init | 把当前目录初始化一个新的模块 |
| tidy | 添加丢失的模块,并移除无用的模块 |
| vendor | 将所有的依赖包存到当前目录下的vendor目录下 |
| verify | 检查当前模块的依赖是否已经存在本地下载的源代码缓存种,以及检查下载后是否有修改 |
| why | 查看为什么需要依赖某模块 |
4. Go Modules开关
如果要使用Go Modules,可以通过环境变量GO111MODULE来打开或者关闭,下面是GO111MODULE的参数:
| 参数 | 含义 |
|---|
| auto | 在 Go1.14 版本中是默认值,在$GOPATH/src下,且没有包含 go.mod 时则关闭 Go Modules,其他情况下都开启 Go Modules |
| on | 启用 Go Modules,Go1.14 版本推荐打开,未来版本会设为默认值 |
| off | 关闭 Go Modules,不推荐 |
如果要打开Go Modules,建议直接
export GO111MODULE = on
5. go.mod 语句
go.mod文件是Go Modules的核心文件
# go.mod 文件示例
module github.com/marmotedu/iam
go 1.17
require (
github.com/AlekSi/pointer v1.1.0
github.com/appleboy/gin-jwt/v2 v2.6.3
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535
github.com/gin-gonic/gin v1.6.3
github.com/golangci/golangci-lint v1.30.0
github.com/google/uuid v1.0.0
github.com/blang/semver v3.5.0+incompatible
golang.org/x/text v0.3.2
)
replace (
github.com/gin-gonic/gin => /home/colin/gin
golang.org/x/text v0.3.2 => github.com/golang/text v0.3.2
)
exclude (
github.com/google/uuid v1.1.0
)
go.mod 文件中包含了4个语句,go是用来设置预期的Go版本,仅作为标识作用
注:下面的场景可能需要用到 replace:1. 在项目开发初期,A 项目依赖 B 项目的包,但 B 项目因为种种原因没有 push 到仓库,这时也可以在 go.mod 中把依赖包替换为 B 项目的本地磁盘路径;2. 在国内访问 [golang.org/x] 的各个包都需要翻… go.mod 中使用 replace,替换成 GitHub 上对应的库,例如[golang.org/x/text] v0.… => [github.com/golang/text…
go.mod文件修改
- 手动编辑 go.mod 文件,编辑之后可以执行go mod edit -fmt格式化 go.mod 文件
- 执行 go mod 子命令修改。
- 第三种修改方法使用方式如下:
go mod edit -fmt # go.mod 格式化
go mod edit -require=golang.org/x/text@v0.3.3 # 添加一个依赖
go mod edit -droprequire=golang.org/x/text # require的反向操作,移除一个依赖
go mod edit -replace=github.com/gin-gonic/gin=/home/colin/gin # 替换模块版本
go mod edit -dropreplace=github.com/gin-gonic/gin # replace的反向操作
go mod edit -exclude=golang.org/x/text@v0.3.1 # 排除一个特定的模块版本
go mod edit -dropexclude=golang.org/x/text@v0.3.1 # exclude的反向操作
6. go.sum文件
文件内容:go.sum 文件中,每行记录由模块名、版本、哈希算法和哈希值组成,如 [/go.mod] 目前,从 Go1.11 到 Go1.14 版本,只有一个算法 SHA-256,用 h1 表示。正常情况下,每个依赖包会包含两条记录,分别是依赖包所有文件的哈希值和该依赖包 go.mod 的哈希值,例如:
github.com/appleboy/gin-jwt/v2 v2.6.4 h1:4YlMh3AjCFnuIRiL27b7T0RRUI=
github.com/appleboy/gin-jwt/v2 v2.6.4/go.mod h1:CZpq1cRw+kqi0+yD2CwVs=
文件生成:在 Go Modules 开启时,如果我们的项目需要引入一个新的包,通常会执行go get命令go get rsc.io/quote。当执行命令后,go get命令会先将依赖包下载到GOPATH/pkg/mod/cache/download,下载的依赖包文件名格式为$version.zip,例如v1.5.2.zip。下载完成之后,go get会对该 zip 包做哈希运算,并将结果存在version.ziphash文件中,例如v1.5.2.ziphash。如果在项目根目录下执行go get命令,则go get会同时更新 go.mod 和 go.sum 文件。
文件校验:在我们执行构建时,go 命令会从本地缓存中查找所有的依赖包,并计算这些依赖包的哈希值,然后与 go.sum 中记录的哈希值进行对比。如果哈希值不一致,则校验失败,停止构建。
7. 使用Go Module
7.1 在$GOPATH之外初始化project
lomodays@lomodays MINGW64 /f/study/golang/outside/gopath/testproject
$ go mod init insujang.github.io/testproject
go: creating new go.mod: module insujang.github.io/testproject
go: to add module requirements and sums:
go mod tidy
7.2 项目目录结构下,有个子包test
main.go
package main
import "insujang.github.io/testproject/test"
func main() {
test.TestFunc()
}
test/func.go
package test
import "k8s.io/klog"
func TestFunc() {
klog.Infoln("Hello Go Modules!")
}
7.3 下载依赖包
lomodays@lomodays MINGW64 /f/study/golang/outside/gopath/testproject
$ go get k8s.io/klog
go: downloading k8s.io/klog v1.0.0
go get: added k8s.io/klog v1.0.0
7.4 运行程序
lomodays@lomodays MINGW64 /f/study/golang/outside/gopath/testproject
$ GO111MODULE=on go run main.go
I0608 18:48:20.134493 20372 func.go:6] Hello Go Modules!