序言
刚接触GO时有同事问你们项目是怎么管理依赖包的,尴尬的是当时并没有很强的包版本依赖所以。。。蜜汁尴尬。生成环境中的项目,不论使用什么编程语言都或多或少的存在”包“或外部模块的依赖问题,对这些依赖的版本管理也就造就了”版本管理工具“。很多语言都有自己的版本管理工具,像java中的maven,js的npm等等(楼主这是又是不知道其他的意思咯。。。这个。。。python的virtualenv,php的phpenv 还有更多自己Google咯)。
GO包管理演化
GO的两个环境变量-包最初的限定
GOROOT:一般设置为GO语言安装包位置(例如/usr/lib/go-1.10);该目录结构与你后续创建的GO项目结构类似,bin、src及pkg;可以看做是“系统项目”,包含GO语言项目的编译、工具及标准库等。
GOPATH:GO语言的工作目录,官方文档中所谓的workspace。该变量可以是多个目录,但你的项目目录必须在该变量中(至少现在的版本需要基于这样的设置,后续可能会被GO团队魔改,毕竟该限制太痛苦了),该目录制定GO程序从何处开始寻找包及可执行文件。目录结构类似GOROOT中的目录,可以视为”应用项目“目录。
多个目录的切换-手动管理包
Golang 1.5 发布之前不同GOPATH来手动切换工程依赖,一般将项目的编译写成脚本,用脚本来切换GOPATH为当前工作目录。这种情况下依赖包一般都是下载到本地目录,导致项目仓库越来越大。同时,这些依赖包的管理基本就“人肉”处理了。
包管理工具化-“半自动化”
Golang 1.5 release 发布vendor来区分不同版本,至于什么又出现vendor目录呢。想想看如果GOPATH中的多个应用程序使用同一个包的不同版本怎么办?这是一个在Go应用程序中遇到的正常问题,并且已经存在了很长时间。vendor/目录允许不同的代码库具有自己的版本,而不会受到另一个需要不同版本的代码库的干扰。
vendor出现后一个依赖包的解析顺序变成:
当前包中的vendor/目录。
目录树中查找父级中的vendor/目录。
查找GOPATH中的包。
如果存在于GOROOT(标准库所在的位置)中,则使用GOROOT中的包。
项目使用vendor时应该在GOPATH目录下创建目录文件夹,否则vendor不生效。看下vendor源码发现有一个parent的概念,也就是项目需要一个包作为起点。
验证vendor// src/cmd/go/pkg.go
func vendoredImportPath(parent *Package, path string) (found string) {
if parent == nil || parent.Root == "" || !go15VendorExperiment {
return path
}
....
}
挣脱GOPATH-待定
GO1.11及1.12出现了modules来记录和解析对其他模块的依赖,争取摆脱对最初GOPATH的依赖。至于开发者是否认可及能否在生产环境中替换现有的工具管理模式还得再等等(这个是真等等看,非”等等“,或者有比较成熟的解决方案及优势可以联系楼主,电话xxxxx)
GO包版本管理工具Glide
现有很多GO版本管理工具都是基于vendor这点来实现版本及依赖管理的(godep早期版本不是,因为go1.5之前没有vendor)。项目中使用了Glide,以简单的test项目大致介绍下该工具的使用吧。
初始化后会在项目目录自动生成项目中依赖包的相关信息,包括版本及子依赖等等。
init后目录 glide.yaml内容glide create / glide init
update命令会将会创建一个glide.lock文件,这个文件包含了特定commit id的整个依赖关系树。
glide update
install命令将安装整个项目需要的依赖包,如果lock文件存在则根据该文件安装依赖包。如果没有该文件则执行update命令生成lock依赖文件并下载依赖包到项目中。
glide install
获取单个特定包可以用get命令,该命令会将依赖包下载到本地项目并更新glide.yaml。
glide get
获取依赖列表可以用list
glide list
关于“墙”的问题可以参考mirror,反正我们没被墙--)。
glide mirror list, set, remove
glide help
其他
GO语言还有一些其他依赖管理工具比如godep,govendor,dep,gvt(这个说是把全部依赖,依赖的依赖都拉到vendor,外部依赖大的项目慎用吧还是)。
网友评论