Golang 依赖管理


简述

Go 在做依赖管理时会创建两个文件,go.mod 和 go.sum

go.mod 提供了依赖版本的全部信息,类似php的composer.json

go.sum 具体的版本,类似php的composer.lock

go.sum

格式

<module> <version> <hash>
<module> <version>/go.mod <hash>

module是依赖的路径,version是依赖的版本号。hash是以h1:开头的字符串,表示生成checksum的算法是第一版的hash算法(sha256)

注:有些项目实际上并没有 go.mod 这个文件,所以 Go 文档里提到这个 /go.mod 的 checksum,用了 “possibly synthesized” (也许是合成的)的说法。
估计对于没有 go.mod 的项目,Go 会尝试生成一个可能的 go.mod,并取它的 checksum

如果只有对于 go.mod 的 checksum,那么可能是因为对应的依赖没有单独下载。比如用 vendor 管理起来的依赖,便只有 go.mod 的 checksum

version规则

  • 项目是否打tag?

如果项目没有打 tag,会生成一个版本号,格式如下:
v0.0.0-commit日期-commitID

引用一个项目的特定分支,比如 develop branch,也会生成类似的版本号:
v当前版本+1-commit日期-commitID

  • 项目有没有用 go module?

如果项目有用到 go module,那么就是正常地用 tag 来作为版本号

如果项目打了 tag,但是没有用到 go module,为了跟用了 go module 的项目相区别,需要加个 +incompatible 的标志

  • 项目用的 go module 版本是不是 v2+?

通过让依赖路径带版本号后缀来区分同一个项目里不同版本的依赖

对于使用了 v2+ go module 的项目,项目路径会有个版本号的后缀

实现的目标

  • 提供分布式环境下的包管理依赖内容校验

Go 采用分布式的方式来管理包。这意味着缺乏一个可供信赖的中心来校验每个包的一致性

在主流的包管理机制中,通常存在一个中央仓库来保证每个发布的版本的内容不会被篡改。比如在 pypi 里面,即使发布过的版本存在严重的bug,发布者也不能重新发布一个同样版本,只能发布一个新版本

并没有一个中央仓库。发布者在 GitHub 上给自己的项目打上 0.1 的 tag 之后,依旧可以删掉这个 tag ,提交不同的内容后再重新打个 0.1 的 tag。
哪怕发布者都是老实人,发布平台也可能作恶。所以只能在每个项目里存储自己依赖到的所有组件的 checksum,才能保证每个依赖不会被篡改

  • 作为 transparent log 来加强安全性

它不仅仅记录了当前依赖的checksum,还保留了历史上每次依赖的 checksum

transparent log 旨在维护一个 Append Only 的日志记录,提高篡改者的作案成本,同时方便审查哪些记录是篡改进来的

go.sum 之所以要用 transparent log 的形式记录历史上的每个checksum,是为了便于 sum db 的工作

麻烦

  • 容易产生合并冲突

由于许多项目都没有通过打tag的方式来管理发布,每个commit都相当于新发布一个版本,这导致拉取它们的代码时会偶尔往 go.sum 文件里插入一条新记录。go.sum会记录间接依赖的特性,更是让这种情况雪上加霜

  • 对于胡乱操作的第三方库,缺乏约束能力

如果一个库乱改已经发布的版本,会让依赖这个库的项目构建失败。对此库的使用者除了咒骂几句,在 issue 或别的地方痛斥作者,然后更新go.sum文件,似乎也没别的解决办法。犯错的本来是库的作者,麻烦的却是库的用户

  • 实际情况下,手动编辑go.sum不可避免

有些项目只在go.sum里保留依赖的最新版本的checksum。
如果 go.sum 不是完全由工具管理的,又怎么能保证它一定是 Append Only 呢?如果 go.sum 不是 Append Only 的,又怎么能把它当作 transparent log 使用呢?

演进

GOPATH

GOPATH 模式下,go get 命令使用时,没有版本选择机制,拉下来的依赖代码都会默认当前最新版本,而且如果当项目 A 和项目 B 分别依赖项目 C 的两个不兼容版本时, GOPATH 路径下只有一个版本的 C 将无法同时满足 A 和 B 的依赖需求

  • vendor机制
    Go1.5提出实验性质的,每个项目下都可以有一个vendor目录存放项目所需版本依赖的拷贝

衍生出govendor godep 等版本管理工具

Go modules

vgo 发展而来,Go1.11 发布该功能

  • 相关的环境变量
GO111MODULE="auto"
GOPROXY="https://goproxy.io,direct"
GONOPROXY=""
GOSUMDB="sum.golang.org"
GONOSUMDB=""
GOPRIVATE=""

相关命令操作

go help mod

下载包

获取帮助
go help get

References

https://studygolang.com/articles/25658


文章作者: 江湖义气
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 江湖义气 !
  目录