golang没有官方最佳管理方案,在go的世界里存在大量的自制解决方案。
go语言的包是没有中央库统一管理的,通过使用go get
命令从远程代码库(github.com,goolge code 等)拉取,直接跳过中央版本库的约束,让代码的拉取直接基于源代码版本控制库开发者间的协同直接依赖于源代码的版本控制。
这就直接去除了库版本的概念。没有明显的包版本标识,官方的建议是把外部依赖的代码全部复制到自己可控的源代码库中,进行统一管理,从而做到对依赖包的可控管理。
下面是一些推荐的版本管理工具:
版本管理工具
1.5版本的vendor目录特性后,官方wiki推荐了多种支持这种特性的包管理工具如:
- godep
- gv
- gvt
- glide
- govendor
我们在这里推荐使用glide
glide简介
glide(官网)是一个golang项目的包管理工具,非常方便快捷,一般只需要2-3个命令就可以将go依赖包自动下载并 归档到vendor的目录中。
安装
下面提供了几种安装途径:
- 1.命令行安装
curl https://glide.sh/get | sh
- 2.下载release
https://github.com/Masterminds/glide/releases
- 3.使用brew安装
brew install glide
- 4.使用go get安装(推荐方法)
go get -u github.com/Masterminds/glide
使用
1 侦测项目依赖
#进入到项目目录
> cd $GOPATH/src/demo
#glide初始化,初始化配置文件glide.yaml
> glide init
运行上面的命令后,会生成配置文件glide.yaml
,其中包含了依赖库的信息,比如版本号,大致格式如下:
package: github.com/MangoDowner/archive
import:
- package: github.com/astaxie/beego
version: v1.11.1
- package: github.com/fsnotify/fsnotify
version: v1.4.7
运行过程中还可能出现一些交互信息,咨询依赖版本之类的,比如
[INFO] Here are some suggestions...
[INFO] The package github.com/astaxie/beego appears to have Semantic Version releases (http://semver.org).
[INFO] The latest release is v1.11.1. You are currently not using a release. Would you like
[INFO] to use this release? Yes (Y) or No (N)
2 更新项目依赖
# glide加载依赖包,自动归档到vendor目录
glide up -v
glide 会生成一个glide.lock
文件,该文件包含了完整的依赖树信息.
注意: 此处不包括此文件的详细信息,因为不应手动编辑此文件。
为什么这里会有一个 -v
?
--strip-vendor
或者 -v
标识都是为了解决下面的问题.
3. 扁平化依赖关系
glide将所有的依赖关系都迁入项目的顶级vendor文件夹中,原因有二:
- 1.所有引入位置都会编译进可执行文件.如果同样的依赖被三个
vendor
目录引入,
就要变异三次.这会导致编译文件变得臃肿. - 2.同样依赖包,如果在不同的位置,就会生成不同的变量实例.即使他们有着相同的版本.
go把他们看成是不同的包,因为他们在不同的位置.
这对于数据库驱动/日志等其他东西来说都是个大问题.
比如下面的依赖:
- $GOPATH/src/github.com/mattfarina/golang-broken-vendor
- foo.go
- vendor/
- a/
- b/
- vendor/a/
这样的代码就不能运行
func main() {
var it a.A
it = "foo"
b.Do(it)
}
报错信息:
$ GO15VENDOREXPERIMENT=1 go build
./foo.go:12: cannot use it
(type "github.com/mattfarina/golang-broken-vendor/vendor/a".A) as type
"github.com/mattfarina/golang-broken-vendor/vendor/b/vendor/a".
A in argument to b.Do
3 增加项目依赖
可以使用get
命令
> glide get github.com/Masterminds/semver
也可以带上版本
> glide get github.com/Masterminds/semver#~1.2.0
#
用来隔离依赖名称和版本号.
get
命令和go get
类似,只是前者将依赖拉入vendor
目录,
而后者拉入GOPATH
相应目录.
配置文件
配置文件包含了项目的信息还有依赖包
package: github.com/Masterminds/glide
homepage: https://masterminds.github.io/glide
license: MIT
owners:
- name: Matt Butcher
email: technosophos@gmail.com
homepage: http://technosophos.com
- name: Matt Farina
email: matt@mattfarina.com
homepage: https://www.mattfarina.com
ignore:
- appengine
excludeDirs:
- node_modules
import:
- package: gopkg.in/yaml.v2
- package: github.com/Masterminds/vcs
version: ^1.2.0
repo: git@github.com:Masterminds/vcs
vcs: git
- package: github.com/codegangsta/cli
version: f89effe81c1ece9c5b0fda359ebd9cf65f169a51
- package: github.com/Masterminds/semver
version: ^1.0.0
testImport:
- package: github.com/arschles/assert
package
:GOPATH
位置下的顶层包.者用来确保不会在顶层包级再次引入.homepage
: 一般用来指明查看包或者和应用更多内容的地方.比如说, http://k8s.ioowners
: 项目所有人的列表.可以用来联系所有人ignore
: 用来让glide忽略引入.一般是包名而不是目录名.excludeDirs
: 要从依赖项扫描中排除的本地代码库目录列表。import
: 要引入的包列表,包括:package
: 要引入的包名,而且是为唯一的必填项.包名和go tool引入的规则一样. 也就是说:- 包名映射到远程的VCS地址,比如.git, .bzr, .hg, 或者.svn.比如
example.com/foo/pkg.git/subpkg
- GitHub, BitBucket, Launchpad, IBM Bluemix Services还有 Go on Google Source是特殊情形,不需要vcs后缀.
- 包名映射到远程的VCS地址,比如.git, .bzr, .hg, 或者.svn.比如
version
: 语义版本/语义版本范围/分支/tag或提交id,都可以使用repo
: 如果包名不是包的位置,或者属于私有库.这可以从repo指定的位置拉取代码并放入包名指定的位置里面去.这样就可以支持fork,而且可以解决golang.org代码被墙的问题.
vcs
:可以使用的VCS,比如说 git, hg, bzr, 或者 svn. 只有无法从名称侦测到类型的时候才需要.subpackages
: 仓库中被使用的包的记录,也就是说不包括那些没被使用的包.os
: 操作系统列表.如果设置了,它会将当前runtime操作系统与指定的操作系统进行比较,只在存在匹配项时获取依赖项.
名称和go build
以及GOOS
环境变量中使用的相同
testImport
:在tests
中使用,并且未在import中列出包列表.他们和import下面列出的包有着相同的细节.
下面提供一些常用的命令:
常用命令
glide create (别名init)
初始化新的workspace,还会创建glide.yaml文件,同时尝试猜测要放入其中的包和版本。
如果您的项目正在使用godep,它将使用那里指定的版本。
glide很智能,可以扫描代码库并检测正在使用的导入,无论它们是否与其他包管理器一起指定。
glide get [包名]
你可以使用该指令来将包下载到你的vendor
目录下,glide还会将包放入你的glide.yaml
文件中去.
$ glide get github.com/Masterminds/cookoo
glide update (别名up)
下载glide.yaml
文件中列出的所有库,并将他们放到vendor
目录下.
如果要解决前文所说的那个多次引入vendor目录,请使用-v
标志,即:
glide update -v
glide install
如果你想要安装glide.lock
中指定的版本:
$ glide install
glide novendor (别名nv)
当你运行go test
的时候,比如go test ./...
时,go会把你依赖库的test也进行一遍,这不是我们想要的.
这时候就可以使用该命令,只对项目本身的tests进行处理.
go test $(glide novendor)
glide list
这个命令会按序列出项目引入的所有包:
$ glide list
INSTALLED packages:
vendor/github.com/Masterminds/cookoo
vendor/github.com/Masterminds/cookoo/fmt
vendor/github.com/Masterminds/cookoo/io
vendor/github.com/Masterminds/cookoo/web
vendor/github.com/Masterminds/semver
vendor/github.com/Masterminds/vcs
vendor/github.com/codegangsta/cli
vendor/gopkg.in/yaml.v2
glide mirror
镜像用原始镜像的另一个位置替换仓库位置力。
如果希望为持续集成(CI)系统加入缓存,或者希望在本地位置处理依赖项时,这就很有用了。
镜像存储在你的
GLIDE_HOME
目录的mirrors.yaml
目录里
其包含的三个自命令为list
, set
, 还有 remove
.
set命令:
glide mirror set [original] [replacement]
# 或者
glide mirror set [original] [replacement] --vcs [type]
比如说:
glide mirror set https://github.com/example/foo https://git.example.com/example/foo.git
# 又或者
glide mirror set https://github.com/example/foo file:///path/to/local/repo --vcs git
remove命令:
glide mirror remove [original]
比如说:
glide mirror remove https://github.com/example/foo
参考文章:
Golang包管理工具glide简介
Glide: Vendor Package Management for Go