golang 包依赖管理 - govendor

Golang 官方并没有推荐最佳的包管理方案。到了1.5版本时代,官方引入包管理的设计,加了 vendor 目录来支持本地包管理依赖。官方 wiki 推荐了多种支持这种特性的包管理工具,如:Godep、gv、gvt、glide、govendor等。

下面简要介绍一个我在项目中用到的 – govendor
该工具将项目依赖的外部包拷贝到项目下的 vendor 目录下,并通过 vendor.json 文件来记录依赖包的版本,方便用户使用相对稳定的依赖。
对于 govendor 来说,依赖包主要有以下多种类型:

状态缩写状态含义
+locall本地包,即项目自身的包组织
+externale外部包,即被 $GOPATH 管理,但不在 vendor 目录下
+vendorv已被 govendor 管理,即在 vendor 目录下
+stds标准库中的包
+unusedu未使用的包,即包在 vendor 目录下,但项目并没有用到
+missingm代码引用了依赖包,但该包并没有找到
+programp主程序包,意味着可以编译为执行文件
+outside外部包和缺失的包
+all所有的包

Installation

go get -u github.com/kardianos/govendor

命令行执行 govendor,若出现以下信息,则说明安装成功。

➜  ~ govendor
govendor (v1.0.8): record dependencies and copy into vendor folder
    -govendor-licenses    Show govendor's licenses.
    -version              Show govendor version
...
...

Warning: 需要把 $GOPATH/bin/ 加到 PATH 中。

Quickstart

# Setup your project.
cd "my project in GOPATH"
# 初始化 vendor 目录, project 下出现 vendor 目录
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

# Get latest v1.*.* tag or branch.
govendor fetch golang.org/x/net/context@v1   

# Get the tag or branch named "v1".
govendor fetch golang.org/x/net/context@=v1  

# Update a package to latest, given any prior version constraint
govendor fetch golang.org/x/net/context

# Format your repository only
govendor fmt +local

# Build everything in your repository only
govendor install +local

# Test your repository only
govendor test +local

Sub-commands

init     创建 vendor 文件夹和 vendor.json 文件
list     列出已经存在的依赖包
add      从 $GOPATH 中添加依赖包,会加到 vendor.json
update   从 $GOPATH 升级依赖包
remove   从 vendor 文件夹删除依赖
status   列出本地丢失的、过期的和修改的package
fetch    从远端库增加新的,或者更新 vendor 文件中的依赖包
sync     Pull packages into vendor folder from remote repository with revisions
migrate  Move packages from a legacy tool to the vendor folder with metadata.
get      类似 go get,但是会把依赖包拷贝到 vendor 目录
license  List discovered licenses for the given status or import paths.
shell    Run a "shell" to make multiple sub-commands more efficient for large projects.

go tool commands that are wrapped:
      `+<status>` package selection may be used with them
    fmt, build, install, clean, test, vet, generate, tool

warning

  • The project must be within a $GOPATH/src.
  • If using go1.5, ensure you set GO15VENDOREXPERIMENT=1.

Vendor目录介绍

随着Go 1.5 release版本的发布,vendor目录被添加到除了GOPATHGOROOT之外的依赖目录查找的解决方案。在Go 1.6之前,你需要手动的设置环境变量GO15VENDOREXPERIMENT=1才可以使Go找到Vendor目录,然而在Go 1.6之后,这个功能已经不需要配置环境变量就可以实现了。

Note,即使使用vendor,也必须在GOPATH中,在go的工具链中,你逃不掉GOPATH的

那么查找依赖包路径的解决方案如下:

  • 当前包下的vendor目录。
  • 向上级目录查找,直到找到src下的vendor目录。
  • GOPATH下面查找依赖包。
  • GOROOT目录下查找

一些建议

在使用vendor中,给出如下建议:

  1. 一个库工程(不包含main的package)不应该在自己的版本控制中存储外部的包在vendor目录中,除非他们有特殊原因并且知道为什么要这么做。
  2. 在一个应用中,(包含main的package),建议只有一个vendor目录在代码库一级目录。

上面建议的原因如下:

  • 在目录结构中的每个包的实例,即使是同一个包的同一个版本,都会打到最终的二进制文件中,如果每个人都单独的存储自己的依赖包,会迅速导致生成文件的二进制爆发(binary bloat)
  • 在一个目录的某个pacage类型,并不兼容在同一个package但是在不同目录的类型,即便是同一个版本的package,那意味着loggers,数据库连接,和其他共享的实例都没法工作。

举个例子

工程目录如下:

- $GOPATH/src/github.com/mattfarina/golang-broken-vendor
  - foo.go
  - vendor/
    - a/
    - b/
        - vendor/a/

在这个例子中,两个a package都是完全一样的,b package在代码库中保存了a package,在顶级应用代码中也引用了a包。

文件foo.go做了很简单的事情:

func main() {
    var it a.A
    it = "foo"

    b.Do(it)
}

那么问题来了,当我们build的时候,发现出问题了,返回了下面的错误:

$ 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

你可以clone这个测试工程到本地重现。

为什么用vendor目录

如果我们已经使用GOPATH去存储packages了,问什么还需要使用vendor目录呢?这是一个很实战的问题。

假如多个应用使用一个依赖包的不同版本?这个问题不只是Go应用,其他语言也会有这个问题。

vendor目录允许不同的代码库拥有它自己的依赖包,并且不同于其他代码库的版本,这就很好的做到了工程的隔离。

推荐

Glide

我们发现Glide是非常好的包管理解决方案,他将依赖包平展开存放在顶级vendor目录中,如果一个包被另一个程序引用了,那么这个包最好不要存储外部依赖项。如果使用Glide,你可以在glide.yml文件中指定依赖包,Glide会帮你管理,并使用正确的版本。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值