go依赖包管理工具对比
写的挺清楚的,备份一下? 转载于:https://www.studygolang.com/articles/10523? vendor一下 当开始真正用go去做项目的时候,不可避免的就会遇到依赖包的问题。go的依赖包管理与java+maven的依赖管理不太一样,我们从GOPATH开始逐渐理解其思想,然后再对比下目前常用的依赖包管理工具。 GOPATH和GOROOT初学者很容易会被这两个环境变量给搞晕。 GOROOT并不是必须要设置的。GOROOT不是必须要设置的。参见Installing to a custom location,默认go会安装在/usr/local/go下,但也允许自定义安装位置,GOROOT的目的就是告知go当前的安装位置,编译的时候从GOROOT去找SDK的system libariry。 例如我用的是ubuntu 16.04,默认go的版本是1.6,如果我想升级为更新的版本,就需要自定义安装,所以我设置了GOROOT: GOPATH必须要设置,但并不是固定不变的GOPATH的目的是为了告知go,需要代码的时候,去哪里查找。注意这里的代码,包括本项目和引用外部项目的代码。GOPATH可以随着项目的不同而重新设置。 GOPATH下会有3个目录:src,bin,pkg。
本项目内部的依赖以kubernetes为例。 import ( "os" "k8s.io/kubernetes/cmd/kubectl/app" )
那么go在编译的时候怎么查找这个包呢? 这就是GOPATH发挥作用的时候了。go编译时会去$GOPATH/src/目录去查找需要的代码,因此只要上面app/kubectl.go在 ├── src
│ ├── k8s.io
│ │?? └── kubernetes
│ │?? ├── cmd
│ │?? │?? ├── kubectl
│ │?? │?? │?? ├── app
│ │?? │?? │?? │?? ├── BUILD
│ │?? │?? │?? │?? └── kubectl.go
│ │?? │?? │?? ├── BUILD
│ │?? │?? │?? ├── kubectl.go
│ │?? │?? │?? └── OWNERS
管理外部的依赖包不可避免的我们会使用外部的依赖包包。go在这方面做的非常飘逸。go没有像java使用maven来管理依赖包、包版本,而是直接使用GOPATH来管理外部依赖。 使用GOPATH来管理外部依赖go允许import不同代码库的代码,例如github.com,k8s.io,golang.org等等;对于需要import的代码,可以使用 go get 命令取下来放到GOPATH对应的目录中去。例如 看到这里也就明白了,对于go来说,其实并不care你的代码是内部还是外部的,总之都在GOPATH里,任何import包的路径都是从GOPATH开始的;唯一的区别,就是内部依赖的包是开发者自己写的,外部依赖的包是go get下来的。 vendor依赖GOPATH来解决go import有个很严重的问题:如果项目依赖的包做了修改,或者干脆删掉了,会影响我的项目。因此在1.5版本以前,为了规避这个问题,通常会将当前使用的依赖包拷贝出来。 为了能让项目继续使用这些依赖包,有这么几个办法:
go作为一个现代化的语言,居然要用这么复杂不直观而又不标准的方法来管理依赖,难怪在早期会有很多人非常不看好go的前景。 为了解决这个问题,go在1.5版本引入了vendor属性(默认关闭,需要设置go环境变量GO15VENDOREXPERIMENT=1),并在1.6版本中默认开启了vendor属性。 简单来说,vendor属性就是让go编译时,优先从项目源码树根目录下的vendor目录查找代码(可以理解为切了一次GOPATH),如果vendor中有,则不再去GOPATH中去查找。 以kube-keepalived-vip为例。该项目会调用k8s.io/kubernetes的库(Client),但如果你用1.5版本的kubernetes代码来编译keepalived,会编译不过: ./controller.go:107: undefined: "k8s.io/kubernetes/pkg/client/unversioned".Client
查下代码会发现1.5版本中代码有变化,已经没有这个Client了。这就是前面说的依赖GOPATH来解决go import所带来的问题,代码不对上了。 kube-keepalived-vip项目用vendor目录解决了这个问题:该项目把所有依赖的包都拷贝到了vendor目录下,对于需要编译该项目的人来说,只要把代码从github上clone到 但是vendor目录又带来了一些新的问题:
社区为了解决这些(工程)问题,在vendor基础上开发了多个管理工具,比较常用的有godep,govendor, glide。go官方也在开发官方dep,目前还是Alpha状态。 下面来看看使用的比较多的gode,glide和 govendor。 godepgodep的使用者众多,如docker,kubernetes, coreos等go项目很多都是使用godep来管理其依赖,当然原因可能是早期也没的工具可选。 godep早期版本并不依赖vendor,所以对go的版本要求很松,go 1.5之前的版本也可以用,只是行为上有所不同。在vendor推出以后,godep也改为使用vendor了。 godep使用很简单:当你的项目编写好了,使用GOPATH的依赖包测试ok了的时候,执行: $ godep save
以hcache为例,执行
一个Godeps.json的例子。 { "ImportPath": "github.com/silenceshell/hcache", "GoVersion": "go1.7", "GodepVersion": "v79", "Deps": [ { "ImportPath": "github.com/tobert/pcstat", "Rev": "91a7346e5b462a61e876c0574cb1ba331a6a5ac5" }, { "ImportPath": "golang.org/x/sys/unix", "Rev": "0b25a408a50076fbbcae6b7ac0ea5fbb0b085e79" } ] }
如果要增加新的依赖包:
如果要更新依赖包:
godep还支持 glideglide也是在vendor之后出来的。glide的依赖包信息在glide.yaml和glide.lock中,前者记录了所有依赖的包,后者记录了依赖包的版本信息(合成一个多好)。 glide使用也不麻烦: glide create # 创建glide工程,生成glide.yaml
glide install # 生成glide.lock,并拷贝依赖包
work,work,work
glide update # 更新依赖包信息,更新glide.lock
glide install会根据glide.lock来更新包的信息,如果没有则会走一把glide update生成glide.lock 最终一个使用glide管理依赖的的工程会是这样: ──$GOPATH/src/myProject (Your project)
├─ glide.yaml
├─ glide.lock
├─ main.go (Your main go code can live here)
├─ mySubpackage (You can create your own subpackages,too)
| ├─ foo.go
├─ vendor
├─ github.com
├─ Masterminds
├─ ... etc.
glide的功能更丰富一些。
govendorgovendor是在vendor之后出来的,功能相对godep多一点,不过就核心问题的解决来说基本是一样的。govendor生成vendor目录的时候需要2条命令:
govendor还可以直接指定依赖包版本来获取包,这也有了点版本管理的影子了。 # Setup your project.
cd "my project in GOPATH"
govendor init
# Add existing GOPATH files to vendor.
govendor add +external
# View your work.
govendor list
# Look at what is using a package
govendor list -v fmt
# Specify a specific version or revision to fetch
govendor fetch golang.org/x/net/context@a4bbce9fcae005b22ae5443f6af064d80a6f5a55
govendor fetch golang.org/x/net/context@v1 # Get latest v1.*.* tag or branch.
govendor fetch golang.org/x/net/context@=v1 # Get the tag or branch named "v1".
相比godep来说,govendor略繁琐一点(比如govendor init有啥用),功能上略丰富一些。 golang官方dep虽说golang的dep还是alpha状态,但也可以用了。 $ dep init
$ dep ensure -update
$ dep ensure github.com/pkg/errors@^0.8.0
没啥特殊要求的话,一条dep init就够用了;如果要升级,或者指定某个tag版本,可以用dep ensure。dep还有个很好用的功能,dep prune,可以删除没有用到的package。 各依赖管理工具对比go官方wiki给了一个比较全面的对比。 godep更直观,使用者也多一些,一些个人的小项目可以用;glide功能更丰富,更接近maven(例如glide.lock跟maven的pom.xml比较类似,可以指定获取某一个版本),新的项目可以考虑使用glide。 当然了,还是期待golang的dep能够更好用,解决目前依赖包管理工具碎片化过多的问题。 gvtglide/godep/govendor都只会拉import的依赖包,对于依赖包的依赖包则不会管。这种情况可以用gvt把所有的依赖全部拉到vendor目录下。是不是很酸爽,但对于解决golang.org库无法访问的问题还是很有帮助的,并且也可以拉平团队使用的所有依赖包。 vendor的问题总的来说glide比较完善了。不过还是有些不太愉快的地方,如代码copy的泛滥:某个包在不同的项目中各有一份copy,而且其版本可能不一样;当依赖的包比较多的时候,vendor目录也会非常庞大。这是vendor的锅(或者说GOPATH的原罪,不能像maven一样对同一个包在本地有多个版本,本地只能有一份代码),似乎没办法避免。 当然了,也别指望go会改善这一点。
拷贝点代码怎么了,对吧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |