golang包管理
什么是vendor
go vendor 是go 1.5 官方引入管理包依赖的方式,1.6正式引入。其基本思路是,将引用的外部包的源代码放在当前工程的vendor目录下面,go 1.6以后编译go代码会优先从vendor目录先寻找依赖包。
在Go 1.6之前,你需要手动的设置环境变量GO15VENDOREXPERIMENT=1才可以使Go找到Vendor目录,然而在Go 1.6之后,这个功能已经不需要配置环境变量就可以实现了。
引入vendor机制后查找依赖包路径的解决方案如下:
- 当前包下的vendor目录。
- 向上级目录查找,直到找到src下的vendor目录。
- 在GOPATH下面查找依赖包。
- 在GOROOT目录下查找。
为什么要引入vendor
golang通过go get命令获取的代码是在gopath/src下的,如果我们有多个项目都引用同一个package就会出现一些问题,比如:项目迁移或新同事加入时,多次go get引入的package版本不一致,导致项目编译不通过。
dep的使用
vendor 机制虽然解决了上面的一些问题,但是无法精确的引用外部包进行版本控制,不能指定引用某个特定版本的外部包;只是在开发时,将其拷贝过来,但是一旦外部包升级,vendor下的代码不会跟着升级,而且vendor下面并没有文件记录引用包的版本信息。
目前为止,golang官方并没有指定的工具,一些第三方开源帮我们解决这个问题。比如:govendor、glide、godep,dep等。dep和godep其实作者是同一人,只不过dep是golang官方非正式版。
dep is a prototype dependency management tool for Go. It requires Go 1.9 or newer to compile. dep is safe for production use.
dep is the official experiment, but not yet the official tool. 这是dep官网上的简介,它要求至少1.9的版本。
安装dep:
go get -u github.com/golang/dep/cmd/dep
dep命令:
dep init set up a new project
dep ensure install the project's dependencies
dep ensure -update update the locked versions of all dependencies
dep ensure -add github.com/pkg/errors add a dependency to the project
执行init命令后,项目根目录中新增了Gopkg.lock、Gopkg.toml和一个目录vendor。
Gopkg.toml可以灵活地描述用户的意图,包括依赖的 source、branch、version等。Gopkg.lock仅仅描述依赖的具体状态,例如各依赖的revision。Gopkg.toml可以通过命令生产,也可以被用户根据 需要手动修改,Gopkg.lock是自动生成的,不可以修改。
要想添加新的依赖可以使用命令
dep ensure -add github.com/bitly/go-simplejson@=0.4.3
也可以在代码中import,然后dep ensure命令即可。
gomod
另外使用 vendor 后,每个项目都完整拷贝一份依赖包,既不方便管理又浪费了本地空间。
此外,Go 项目中的 import 指令后面的 package 路径与项目代码的存放路径相关,项目目录不能随意移动,必须安分守己地趴在 $GOPATH/src 中,否则 import 会找不到项目中的 package,虽然可以通过在容器中编译或者为每个项目准备一套 Go 环境的方式解决,但是麻烦且有额外开销。
Go1.11 和 Go1.12 引入的 Go Modules 机制,提供了统一的依赖包管理工具 go mod,依赖包统一下载在 GOPATH/pkg/mod 中进行集中管理,统一包后面有版本号,所以不会出现问题。 GO111MODULE 有三个值:off, on和auto(默认值)。
GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。 GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。 GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:
- 当前目录在GOPATH/src之外且该目录包含go.mod文件
- 当前文件在包含go.mod文件的目录下面。
gomod 依赖包下载存放目录在GOPATH/pkg/mod
Go Modules 将成为 Go1.13 默认的依赖包管理方法,在 Go1.11 和 Go1.12 中, Go Modules 只能在 $GOPATH 外部使用。
gomod初始化
在 GOPATH 外部创建一个目录,然后初始化,项目的路径设置为 exampe.com/hello:
go mod init example.com/hello # 该项目代码的引用路径是 example.com/hello
增加了 go.mod 和 go.sum 文件。 go.mod 提供了module, require、replace和exclude 四个命令
module 语句指定包的名字(路径) require 语句指定的依赖项模块 replace 语句可以替换依赖项模块 exclude 语句可以忽略依赖项模块
依赖包添加
- 我们可以直接在代码中import包,然后go build时就会自动更新go.mod文件。这个时候下载的是最新的版本。
- go get命令会下载指定版本,并更新到go.mod,不过它是indirect,因为它还没有用到。
go get github.com/lijiaocn/glib@v0.0.2
goproxy
默认情况下,go 命令直接从 VCS 下载模块。GOPROXY 环境变量允许进一步控制下载源。环境变量将 go 命令配置为使用 Go 模 块代理。
- 不怕依赖的库被作者删除了。
- 您不再需要任何 VSC 工具来下载依赖项,因为依赖项是通过 HTTP 提供的 (Go 代理在后台使用 HTTP)。
- 下载和构建 Go 模块的速度明显加快,因为 Go 代理通过 HTTP 分别提供了源代码 ( .zip 存档) 和 go.mod。与从 VCS 进行提取相比,这导致下载花费更少的时间和更快的时间 (由于更少的开销)。
- 国内不用梯子了。
在 Go 1.13 中如何使用 goproxy.cn?
答:一条 go env -w GOPROXY=https://goproxy.cn,direct 即可。之所以在后面拼接一个 ,direct,是因为通过这样做我们可以在一定程度上解决私有库的问题(当然, goproxy.cn 无法访问你的私有库)。这个 GOPROXY 设定的工作原理是:当 go 在抓取目标模块时,若遇见了 404 错误,那么就回退到 direct 也就是直接去目标模块的源头(比如 GitHub) 去抓取。而恰好,GitHub 等类似的代码托管网站的原则基本都是“你无权访问的你来说就是不存在的”,所以我才说通过这样设定可以在一定程度上解决私有库无法通过模块代理访问的问题。
在 Go 1.13 之前如何使用 goproxy.cn?
答:同样也是设置环境变量即可,但是得你手动配置,而且还不能使用上述的那个 ,direct 后缀,因为那是 Go 1.13 刚加的特性。详细配置方法可以参见 goproxy.cn 的 README 文件。
GOPRIVATE
前面也说到对于一些内部的 package,GoProxy 并不能很好的处理,Go 1.13 推出了 GOPRIVATE 机制。只需要设置这个环境变量,然后标识出哪些 package 是 private 的,那么对于这个 package 的处理将不会从 proxy 下载。GOPRIVATE 的值是一个以逗号分隔的列表,支持正则(正则语法遵守 Golang 的 包 path.Match) GOPRIVATE=*.corp.example.com,rsc.io/private