Golang一直以来都缺少一个包管理工具,在Go mod出现之前安装软件依赖包只能使用go get,后来出现了vender(Golang1.5版本后),但并不理想vender类似node modules会在工程下建立一个目录然后把所有的依赖放在目录下,依赖越多这个目录也就越大,而且每个工程都需建立一个目录,比较浪费资源,但也确实解决了一些问题。自从Go 1.11引入Go mod摒弃vendor和GOPATH,用本地缓存库的管理方式(类似java maven),才算真正拥有一个包管理工具。
我这里使用Go1.11.5版本测试,首先需要设置环境变量来激活modules,GO111MODULE
off: GOPATH mode,查找vendor和GOPATH目录
on:module-aware mode,使用 go module,忽略GOPATH目录
auto:默认值,如果当前目录不在$GOPATH 并且当前目录(或者父目录)下有go.mod文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。
对于国内用户可能会被墙,需要设置另一个环境变量 GOPROXY
Go1.11后新增了go mod命令,查看帮助可以使用 go help mod 命令
go mod tidy 拉取缺少的模块,移除不用的模块。
go mod download 下载依赖包
go mod graph 打印模块依赖图
go mod vendor 将依赖复制到vendor下
go mod verify 校验依赖
go mod why 解释为什么需要依赖
go list -m -json all 依赖包及详情
go mod init 当前目录下初始化mod
go.mod 提供了四个指令,如下:
首先创建一个项目并设置好环境变量
mkdir test
export GO111MODULE=on
export GOPROXY=https://goproxy.io
vim main.go
package main
import (
"fmt"
_ "github.com/toolkits/sys"
_ "github.com/toolkits/file"
_ "golang.org/x/text"
)
func main(){
fmt.Println("hello world")
}
go mod init test
cat go.mod
module test
go mod init命令在当前目录下生成一个go.mod文件,内容只有一行,描述了该module为test(记录依赖包及版本号)
go run main.go
Go命令build、test、run、list 时,都会去修改go.mod文件(保持最新状态)
同时生成go.sum文件,go.sum记录了每一个依赖包的版本及校验值,包含了直接依赖和间接依赖的包的信息。每当增加一个依赖项时,如果go.sum中没有,则会将该依赖项的版本和内容校验添加到go.sum中。go命令会使用这些校验和与缓存在本地的依赖包副本元信息进行比对校验。
go mod verify
all modules verified
如果没有被修改过,会显示verify成功。
go mod tidy
清理go.mod和go.sum中无用的依赖,并且如果有新增的依赖也会添加。
对依赖包的版本进行“升降级”(upgrade或downgrade)
go list -m -versions golang.org/x/text #查看依赖包的可用版本
golang.org/x/text v0.1.0 v0.2.0 v0.3.0 v0.3.1 v0.3.2
将golang.org/x/text从v0.3.0降级到v0.1.0
go get golang.org/x/text@v0.1.0
go: finding golang.org/x/text v0.1.0
go: downloading golang.org/x/text v0.1.0
在查看go.mod中依赖的golang.org/x/text已经从v0.3.0自动变成了v0.1.0了。go.sum中也增加了golang.org/x/text v0.1.0的条目,不过v0.3.0的条目依旧存在,可以通过go mod tidy清理一下。
Go1.11中的go get也是支持两套工作模式的: 一是传统GOPATH mode的,另一个是module-aware。
如果我们在GOPATH之外的路径,且该路径下没有go.mod,那么go get还是回归GOPATH mode,在module-aware模式下,go get -u会更新依赖,升级到依赖的最新minor或patch release。
我们看到降级回v0.1.0的依赖项又自动变回v0.3.0了(注意仅minor号变更),如果仅仅要升级patch号,而不升级minor号,可以使用go get -u=patch A 。比如:如果golang.org/x/text有v0.1.1版本,那么go get -u=patch golang.org/x/text会将go.mod中的text后面的版本号变为v0.1.1,而不是v0.3.0,如果go get后面不接具体package,则go get仅针对于main package,处于module-aware工作模式下的go get更新某个依赖(无论是升版本还是降版本)时,会自动计算并更新其间接依赖的包的版本。
go mod vendor -v
# github.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07
github.com/toolkits/file
# github.com/toolkits/sys v0.0.0-20170615103026-1f33b217ffaf
github.com/toolkits/sys
# golang.org/x/text v0.1.0
golang.org/x/text
兼容vendor,这样老版本的go compiler就可以使用vendor进行build了
PS1:go modules 下载的包在 GOPATH/pkg/mod,安装的命令仍在 GOPATH/bin下。
PS2: 其他的包管理工具如;govendor、dep、glide、godep都是基于GOPATH或vendor的。