Go 语言依赖管理 | 青训营

84 阅读1分钟

依赖管理

Go依赖管理体系的演进:

  1. GOPATH
  2. Go Vendor
  3. Go Module

GOPATH

环境变量$GOPATH通常为~/go

$GOPATH目录用于存储:

  • $GOPATH/bin:Go 项目编译产生的二进制文件
  • $GOPATH/pkg:项目编译的中间产物
  • $GOPATH/src依赖包的源码

这样的设计使得开发环境中所有的项目都依赖$GOPATH/src中的同一份源码,使多个项目依赖一个包时必须依赖同一个版本

Go Vendor

  • 在项目目录下增加vendor目录,用于存储所有依赖包的副本
  • 寻找依赖时,vendor中的包会被优先使用,如果没有再到$GOPATH/src中寻找

解决GOPATH的问题后,仍然有以下问题:

  • 如果该项目依赖的两个包分别又依赖一个包的不同版本,那么无法在vendor目录中找到合适的版本,因为vendor目录只能为每个包存储一个特定版本。

Go Module

  • 通过项目目录下的go.mod文件管理依赖包版本
  • 支持go getgo mod命令管理依赖包

项目配置文件go.mod

module <module_path>

go <go_version>

require (
    <module_path1> <module_version1>
    <module_path2> <module_version2>
    ...
)

第一行定义当前目录下的项目名称<module_path>

  • 本地依赖:path/to/library
  • GitHub依赖:github.com/user_name/repo_name

然后定义Go语言版本<go_version>

依赖项列表:

  • <module_pathn>为依赖项的名称,和<module_path>格式相同
  • <module_pathn>为依赖项的版本
    • 版本号允许以下任意一种格式:
      • 语义化版本号:v{MAJOR}.{MINOR}.{PATCH}
      • 基于git commit的伪版本:v{MAJOR}.{MINOR}.{PATCH}-yyyymmddhhmmss-COMMIT_HASH
    • 其它信息
      • // indirect表示该依赖项为间接依赖,是本项目直接依赖项中的某个包依赖的包
      • +incompatible表示没有使用go.mod的旧仓库中的依赖,可能与使用新的依赖系统的包不兼容

如果出现两个或多个不同版本的间接依赖项,那么Go会选择其中的最低兼容版本,即同一个{MAJOR}版本中,{MINOR}.{PATCH}最大的版本。

本地命令工具

go get <module_path>下载最新版本,可以添加后缀:

  • @update 默认行为
  • @none删除包
  • @v{MAJOR}.{MINOR}.{PATCH}指定版本
  • @COMMIT_HASH指定commit的伪版本
  • @BRANCH指定分支上的最新commit

go mod

  • go mod init初始化项目,创建go.mod文件
  • go mod download根据go.mod下载模块到本地缓存
  • go tidy根据代码增加需要的依赖,并删除不需要的依赖

依赖分发

依赖包可能托管在GitHub等平台上,如果每次需要下载依赖时直接访问这些源站,那么可能出现以下问题:

  • 无法保证构建稳定性:托管平台上的代码随时可能变动
  • 无法保证依赖可用性:作者可能删除包或仓库
  • 增加第三方平台压力

为了避免以上问题,Go通过代理服务器(Proxy)下载需要的依赖项,代理服务器会缓存源站上所有注册的包,以及所有的版本,保证依赖项稳定可用。

  • 可以通过${GOPROXY}环境变量配置代理服务器地址,格式为"URL1,URL2,...,direct"(越靠前优先级越高)
    • URLn为一个代理服务器地址
    • direct表示源站