前言
随着 Go 语言的深入使用,其依赖管理机制也一直是各位 Gopher 热衷于探讨的话题。Go 语言的源码依赖可通过 go get 命令来获取,但自动化程度不高,于是官方提供了 Dep 这样的自动化批量管理依赖的工具。虽然 Go 语言的依赖管理在很多方面还是不如人意,但整个体系正在日趋完善,本篇就将从最基本的依赖管理场景出发,一同探讨 Go 语言依赖管理的一些最佳实践。
Go 依赖管理的基本思路
在 Go 语言中,我们通过 go get 命令将 GitHub 或者 Google Code 上的代码下载到本地指定目录,然后在开发代码中通过 import 的形式引用本地的代码。
Go 语言可以通过直接分析代码中的 import 语句来查询依赖关系。go get 命令在执行时,就会自动解析 import 来安装所有的依赖。那么下载的依赖在本地是如何存储的呢?
![image.png](https://static.studygolang.com/200612/48f7f7afc36bace6afdabd65a5824d0d.png)
这里就涉及到 Go 语言的 WORKSPACE 概念,简单来说就是通过 GOPATH 环境变量来设置 Go 代码的位置。一般来说,GOPATH 目录下会包含 pkg、src 和 bin 三个子目录,这三个目录各有用处。
bin 目录用来放置编译好的可执行文件,为了使得这里的可执行文件可以方便的运行,在 shell 中设置PATH变量。
src 目录用来放置代码源文件,在进行 import 时,是使用这个位置作为根目录的。自己编写的代码也应该放在这下面,不同的项目放在不同的目录下进行管理。
pkg 用来放置安装的包的链接对象(Object)的。这个概念有点类似于链接库,Go 会将编译出的可连接库放在这里,方便编译时链接。不同的系统和处理器架构的对象会在 pkg 存放在不同的文件夹中。
当项目在 src 目录下管理时,多个项目可能都会使用相同的依赖,如果每个项目都存一份依赖显然会带来大量的冗余,这里我们推荐一个设置 GOPATH 环境变量时的小技巧。
![image.png](https://static.studygolang.com/200612/ba206e1c336f6071141908414e84a9de.png)
这样第三方包就会默认放置在第一个路径中,而你可以在第二个路径下编写自己的代码,多个项目共享一份依赖。
dep - 官方 Go 依赖管理工具
dep 是 Go 语言官方提供的依赖管理工具,跟其他依赖管理工具类似,都是通过一个文件描述依赖的坐标信息,然后批量管理(下载、升级等)依赖包(源码)。dep 是一个开源项目, 大家可以在 https://github.com/golang/dep 了解详细信息,其安装方式大家可以参考官方说明,这里我们主要介绍其使用。
基本操作
通过 dep init 命令来初始化,会创建Gopkg.lock,Gopkg.toml文件和一个空的vendor目录。
我们在代码中通过 import 命令添加依赖后,通过 dep ensure 就可以下载依赖到本地 $GOPATH/src 目录下。
main.go
![image.png](https://static.studygolang.com/200612/1ed18fd32f0818c7a1a84a3c04136b35.png)
Gopkg.lock
![image.png](https://static.studygolang.com/200612/c49db2f18558026db7acd13b95fa337e.png)
通过 dep status 我们可以查看当前依赖引用的情况
![image.png](https://static.studygolang.com/200612/e457bbf0872533f870712deaf2dba6f8.png)
另外有一个 dep check 命令来检查是否存在依赖被引用,但是代码中并没有使用的情况,Go 语言对于依赖的引用比较严格,不允许引用了但是没使用的情况。从软件安全的角度考虑,这是一个很好的实践,避免引入一些安全风险。
![image.png](https://static.studygolang.com/200612/021cacd2212dca044be6beb6be418cb1.png)
当然,这种时候我们就需要移除本地依赖,最好不要手动删除vendor中的内容,而是通过 dep ensure -update 命令来移除。
从 dep 的目录结构,我们可以分析出 dep 的基本工作思路:
这里面有两个关键的步骤:
解析依赖
从当前项目的 import 文件中解析出整个工程的依赖情况,并结合 Gopkg.toml 定义的规则,然后将依赖关系输出给 Gopkg.lock,注意这个 lock 文件最好不要手动修改。
获取依赖
通过 Gopkg.lock 了解整个依赖关系之后,将依赖的具体内容拉取下来放到 vendor 目录中,然后执行 Go build 时从本地的 vendor 读取依赖并完成构建。
这一些都是在 dep ensure 时完成的,其实在执行这个命令时还可以传参数,最主要的是 -no-vendor 和 -vendor-only 这两个参数。
-no-vendor 参数只会导致运行 resolve 函数,结果是创建一个新的Gopkg.lock 文件,不会更新 vendor;而 -vendor-only 参数将跳过 resolve 并仅运行 vendoring 函数,导致 vendor/ 从已存在的Gopkg.lock 重新更新。
关于 dep 更多深入内容,可以参考
https://golang.github.io/dep/docs/introduction.html
总结
Go dep 目前是一款比较好用的依赖管理工具,很多比较大型的项目都在使用,从中可以学习到依赖管理的一些基本思路,对于理解其他语言,比如 NPM 的依赖管理模型也是比较有好处的。
更多精彩内容可以专注我们的在线课堂
微信搜索公众号:jfrogchina 获取课程通知
有疑问加站长微信联系(非本文作者)