dep使用指南

什么是dep

dep是一款golang的包管理工具,通过将工程中相关依赖的包加载到工程目录下的vendor文件夹的形式,实现包的版本管理。

为什么要使用dep

要解释这个问题,首先要解释为什么要出现vendor目录。在没有vendor目录之前,golang在查找工程中引入的第三方包的时候,会到环境上配置的$GOPATH目录下查找对应目录的包,意味着我们在使用一个包的时候,必须先用 go get 命名下载到$GOPATH中,但是我们知道第三方包会有版本的概念,假如A工程引用了P包的v1.0.0版本,B工程引用了P包的v2.0.0版本,但是每个$GOPATH下面对应的P包只能存放一份,所以每次需要编译不同的AB不同的工程的时候,需要到$GOPATH手工切换第三方包的版本,整个流程就会变得很繁琐。

为了解决这个问题,golang在go1.5版本引入了vendor目录的概念,golang在查找工程中引入的第三方包的时候会优先到当前工程中的vendor目录中查找包,我们只需要将需要用到的包按目录规则存放即可,这样包的版本问题就迎刃而解了。

而dep就是用来做vendor包管理的工具,提供了初始化vendor包和更新vendor包的命令,以及对vendor中的第三方包的约束配置,能帮助开发者更好地管理工程中的包依赖。

如何安装dep

官方文档 提供了详细的安装指南,这里也提供一种我个人比较推荐的做法:
首先先将$GOPATH/bin目录加入到机器的$PATH中,然后使用 go get 命令下载dep包即可,命令执行如下:

1
go get -v github.com/golang/dep/cmd/dep

如何使用dep在工程中初始化依赖

安装上一步安装好dep后,即可开始使用dep命令了。对于一个之前没引入vendor包的项目来说,需要执行一下的命名做初始化:

1
2
3
// -v表示详细打印整个初始化过程,由于很多golang相关的包都需要翻墙下载,网络会存在
// 不稳定的情况,所以最好是带上这个指令打印详细输出信息
dep init -v

执行命令成功后,我们会看到工程目录下除了多了vendor目录外,还会生成两个文件:Gopkg.toml和Gopkg.lock,Gopkg.toml文件是用来做包的约束说明(例如指定某个依赖包的版本),Gopkg.lock文件则是描述了当前vendor目录下所有包的版本信息。

关于Gopkg.toml的配置说明

Gopkg.toml提供了丰富的包约束规则配置,具体介绍如下:
(1) require/ignored 配置

1
2
3
// 示例
require = ["github.com/garyburd/redigo", "github.com/bradfitz/gomemcache"]
ignored = ["github.com/go-ini/ini"]

当包路径出现在require节点中,则表示不管当前工程中有没有用到这个包都将这个包加入到vendor中,这个特性在有些场景下很会用,比如做一些开发脚手架的时候,某些包在外来有极大可能会被引用,则先把它们加入到require节点中,避免未来用到的时候再执行一次包引入;

出现在ignored中的包路径,则表示不管当前工程有没有用到这个包都将不把这个包加入到vendor中,这个特性的用途主要在当出现间接引用的时候,比如A->B->C,如果确定C在当前的工程中没被执行到,则可以考虑将C不加入到vendor包,减少编译生成的文件大小(不过这个做法其实并不常见,建议谨慎使用)。

(2) prune 配置

1
2
3
4
// 示例
[prune]
go-tests = true
unused-packages = true

prune的中文意思是精简的意思,默认生成的Gopkg.toml文件通常会带上示例的配置,go-tests = true 表示vendor目录将不包含包中_test结尾的go文件,unused-packages = true 表示没有被用到的包将不包含在vendor目录中(例如有外部包结构如下:github.com/teroy/stark/a和github.com/teroy/stark/b,假如工程中只引入了a包,则b包不会出现在vendor目录中)。

注意如果要改变精简条件,无需将false赋值给对应项的配置,而是直接将对应项的配置在配置文件中移除。

(3) constraint 配置

1
2
3
4
5
// 示例
[[constraint]]
name = "github.com/teroy/common"
branch = "master"
source = "git@github.com:teroy/common.git"

constraint用来配置当前工程的直接依赖包约束。constraint提供了较多的配置项,具体罗列如下:

1
2
3
4
5
6
7
8
9
[[constraint]]
// 包名(节必须配置)
name = "github.com/teroy/common"
// branch、version和revision 只允许配置一个(必须配置)
branch = "master" // 表示当前包的获取分支
version = "1.0.0" // 表示获取包的版本,"1.0.0"表示获取范围为>="1.0.0", <"2.0.0",参考:(https://golang.github.io/dep/docs/Gopkg.toml.html#version)
revision = "12766cc1f36d22b11887b42740d06ff966534e0a" // 表示指定具体的git的commit SHA1 通常情况下不使用,只有在确定version没有适合的版本的情况下使用
// 源地址(可选配置)
source = "git@github.com:teroy/common.git" // 默认使用http的形式,也可以配置ssh的形式

(4) ovverride 配置

1
2
3
4
5
// 示例
[[override]]
name = "github.com/teroy/common"
branch = "master"
source = "git@github.com:teroy/common.git"

override与constraint相同的配置约束,唯一不同的是override使用来配置当前工程的间接依赖包约束。

dep ensure 命令说明

dep ensure -v 执行的过程中,会做以下两个检查:检查当前工程所需要的包是否和.lock文件中指定的包一致以及检查.toml文件中的约束条件是否和.lock文件中指定的包一致。假如出现了不一致的情况,则dep会执行工程的所有依赖包的重新加载,所以这个命令适合于工程中引入了新的包(不存在于.lock文件中配置的包)的时候执行,或者修改了.toml配置的时候执行。注意只要.lock文件指定的包的版本是在.toml约束范围内,不管.toml文件如何变动,执行这条命令都不会更新包到约束范围内的最新版本。

那如果我们要更新某个包到约束范围内的最新版本要怎么做呢?答案就是执行 dep ensure -v -update 具体的包,当然也可以直接执行 dep ensure -v -update 更新所有的包,但通常这会比较费时,一般也不推荐这种方式。