- 吐槽一下:好多Go教程讲了很多go语法各种框架,居然不讲包管理?
- 在 1.5 版本之前,所有的依赖包都是存放在 GOPATH 下,没有版本控制。(弊端就是无法实现包的多版本控制)
- 1.5 版本推出了 vendor 机制。所谓 vendor 机制,就是每个项目的根目录下可以有一个 vendor 目录,里面存放了该项目的依赖的 package。go build 的时候会先去 vendor 目录查找依赖,如果没有找到会再去 GOPATH 目录下查找。
- 1.9 版本推出了实验性质的 dep,后续没有继续使用,因此不继续提。
- 1.11 版本推出 modules 机制,简称 mod。modules 的原型是 vgo 。
- modules 在 Go 1.13 的版本下是默认开启的。
modules 的使用
在 1.12 版本之前,使用 Go modules 之前需要环境变量 GO111MODULE:
- GO111MODULE=off: 不使用 modules 功能,查找vendor和GOPATH目录
- GO111MODULE=on: 使用 modules 功能,不会去 GOPATH 下面查找依赖包。
- GO111MODULE=auto: Golang 自己检测是不是使用 modules 功能,如果当前目录不在$GOPATH 并且 当前目录(或者父目录)下有go.mod文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode
在 GOPATH 之外创建一个项目 mod-demo,包含一个 main.go 文件,内容如下:
package main
import "fmt"
import "github.com/astaxie/beego"
func main() {
fmt.Println("hello")
beego.Run()
}
初始化 go modules
在项目根目录执行命令 go mod init test-demo ,然后会生成一个 go.mod 文件:标识项目依赖的 package 的版本。执行 init 时还没将所有的依赖管理起来。将程序 run 起来(如 go run/test)或者 build 的时候会触发依赖的解析。
此时再查看 go.mod 文件:
module test-demo
go 1.13
require (
github.com/astaxie/beego v1.12.0 // indirect
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
)
- 有 indirect 注释的代表间接依赖,没有的代表直接依赖,这里是版本号+时间戳+hash
- 在 Goland 中可以用 alt+enter/option+enter 来下载依赖包
项目目录下多了 go.sum 文件用来记录每个 package 的版本和哈希值。go.mod 包含 module, require, replace, exclude 模块。这些 package 并不是直接存储到 GOPATH/src,而是存储到 GOPATH/pkg/mod 下面,不同版本并存的方式。
依赖的升级和降级
查看当前项目依赖的所有的包:
go list -m -u all
//如果我想要升级(降级)某个 package 则只需要 go get 即可,比如:
go get package@version
// eg. go get github.com/astaxie/beego@v1.11.1
在 modules 模式开启和关闭的情况下,go get 的使用方式不是完全相同的。在 modules 模式开启的情况下,可以通过在 package 后面添加 @version 来表明要升级(降级)到某个版本。如果没有指明 version 的情况下,则默认先下载打了 tag 的 release 版本。如果没有 release 版本,则下载最新的 pre release 版本。如果还没有则下载最新的 commit。
在 modules 开启的模式下,go get 还支持 version 模糊查询,比如 > v1.0.0 表示大于 v1.0.0 的可使用版本;< v1.12.0 表示小于 v1.12.0 版本下最近可用的版本。version 的比较规则按照 version 的各个字段来展开。
使用如下命令使用最近的可行的版本:
go get -u 使用最新的 minor 或者 patch 版本
go get -u=patch 使用最新的 patch 版本
vender
go mod 也支持 vendor 机制,将依赖包拷贝到 vendor 目录。但是 test case 里面的依赖包并不会拷贝的 vendor 目录中。
go mod vendor
replace
- replace 主要为了解决某些包发生改名的问题。对于另外一种场景有的时候也是有用的,比如对于有些 http://golang.org/x/ 下面的包由于某些原因在国内是下载不了的,但是对应的包在 github 上面是有一份拷贝的,这个时候我们就可以将 go.mod 中的包进行 replace 操作。
下面是一个 Beego 项目的 go.mod 的 replace 的示例。
replace golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 => github.com/golang/crypto v0.0.0-20181127143415-eb0de9b17e85
replace gopkg.in/yaml.v2 v2.2.1 => github.com/go-yaml/yaml v0.0.0-20180328195020-5420a8b6744d
SubCommand
modules 支持的 subcommand (即输入go mod后面可以跟以下命令):
- download: 下载 modules 到本地缓存
- edit: 提供一种命令行交互修改 go.mod 的方式
- graph: 将 module 的依赖图在命令行打印出来,其实并不是很直观
- init: 初始化 modules,会生成一个 go.mod 文件
- tidy: 清理 go.mod 中的依赖,会添加缺失的依赖,同时移除没有用到的依赖
- vendor: 将依赖包打包拷贝到项目的 vendor 目录下,值得注意的是并不会将 test code 中的依赖包打包到 vendor 中。这种设计在社区也引起过几次争论,但是并没有达成一致。
- verify: verify 用来检测依赖包自下载之后是否被改动过。
- why: 解释为什么 package 或者 module 是需要,但是看上去解释的理由并不是非常的直观。
GOPRIVATE
内部的 package,GoProxy 并不能很好的处理,Go 1.13 推出了 GOPRIVATE 机制。
设置环境变量,标识 package 是 private 的,对于这个 package 的处理将不会从 proxy 下载。
GOPRIVATE=*.corp.example.com,rsc.io/private
GOSUMDB
GOSUMDB 的全称为 Go CheckSum Database,用于下载包的安全性校验。
关闭哈希校验,可以将 GOSUMDB 设置为 off;如果要对部分包关闭哈希校验,则可以将包的前缀设置到环境变量中 GONOSUMDB 中。
GOSUMDB="sum.golang.org"GOSUMDB="sum.golang.org+<publickey>"GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"