GO 依赖管理 | 青训营笔记

271 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

简介

在使用 java、python 等语言开发项目时,我们往往需要使用 Maven/Gradle、pip 等依赖管理工具来管理项目依赖。 在 Golang 中,目前广泛使用 Go Module 进行依赖管理。 使用 go env 命令查看 go 环境。

Go 依赖管理演进

GOPATH -> GO Vendor -> Go Module

GOPATH

在环境变量中设置 $GOPATH 为 Go 项目的工作区,目录结构如下:

  • src:存放 Go 项目的源码
  • pkg:项目编译的中间产物,用于加速编译
  • src:项目源码

导入依赖时,使用 go get 会下载最新版本或者指定版本(go get packages@version)的包到 src 目录下。

弊端:GOPATH 一个包只能保存一个版本,不能很好解决多个项目依赖同一个包的不同版本的问题。

Go Vendor

Go 1.5 引入,用于解决多个项目需要同一个 package 依赖的冲突问题。 Vendor是当前项目中的一个目录,其中存放了当前项目依赖的副本。在Vendor机制下,如果当前项目存在Vendor目录,会优先使用该目录下的依赖,如果依赖不存在,会从GOPATH中寻找。

问题

  • Vendor 下保存的时当前项目依赖的副本,无法控制依赖的版本
  • 更新项目有可能出现依赖冲突

Go Module

Go Modules 是Go语言官方推出的依赖管理系统,解决了之前依赖管理系统存在的诸如无法依赖同一个库的多个版本等问题,go module从Go 1.11开始实验性引入,Go 1.16默认开启。

使用 go env 命令可以查看环境变量,其中,GO111MODULE="on" 表示 go module 已开启。

依赖管理三要素

  • 配置文件,描述依赖:使用 go.mod 文件描述依赖
  • 中心仓库管理依赖库:中心仓库(Proxy)可以看作是依赖的托管平台,类似 Github
  • 本地工具:使用 go get/mod 等命令进行依赖下载/管理等
配置依赖- go.mod

在项目的根目录下

示例

// 模块路径
module example/project/app

// go 原生库
go 1.16 

// 单元依赖
require (
    example/lib1 v1.0.2
    example/lib2 v1.0.0 // indirect
    example/lib3 v0.1.0-20190725025543-5a5fe074e612
    example/lib4 v0.0.0-20180306012644-bacd9c7ef1dd // indirect
    example/lib5/v3 v3.0.2
    example/lib6 v3.2.0+incompatible
)

go.mod 组成

  • 模块路径:用于标识一个模块
  • go 原生库:指定项目所使用 go 版本
  • 单元依赖:单元依赖使用模块路径+版本来唯一标识

单元依赖中的特殊标识符:

  • indirect:间接依赖

  • +incompatible:go module 在 1.11 实验性引入,为了兼容 1.16 之前,1.11 之后的模块。 版本号 分为语义化版本和基于commit的伪版本

  • 语义化版本:一个语义版本由三个非负整数(主要、次要和补丁版本,从左到右)用点分隔组成。补丁版本后面可以跟一个以连字符开头的标识符(例如 -pre 或 -beta,表示预发布或者测试版本)。主要版本可以不兼容旧的版本。

  • 伪版本:vX.0.0-yyyymmddhhmmss-abcdefabcdef,组成为:主要版本-时间-commit哈希12位前缀

同一个项目对包的不同版本存在依赖,go 使用 做小版本抉择 算法来选择一组模块版本。参考:最小版本抉择(MVS) |《Go Modules 中文文档 1.17》| Go 技术论坛 (learnku.com) 其流程可以简化为:先广度优先列出 main 的 go.mod 的直接依赖,再深度优先这些依赖,最后,对于存在多个版本的依赖,选择最低的兼容版本

依赖分发-Proxy

使用 go env 命令查看

GOPROXY="https://proxy1.cn,https://proxy2.cn,direct"

GOPROXY是一个 Go Proxy 站点URL列表,可以使用"direct"表示源站。对于示例配置,整体的依赖寻址路径,会优先从proxy1下载依赖,如果proxy1不存在,后下钻proxy2寻找,如果proxy2,中不存在则会回源到源站直接下载依赖,缓存到proxy站点中。

配置 GOPROXY。下面是在 linux 中配置七牛云作为 GOPROXY

export GO111MODULE=on
export GOPROXY=https://goproxy.cn
依赖管理工具
  • go get 通常使用 go get example.org/pkg[option] 为项目拉取依赖,其中,option 可选: | option | 说明| | -------|-----| |@update | 默认,拉取最新版本| |@none | 删除依赖| |@latest | 拉取最新的版本| |@master | 指定分支的最新commit| |@tag | commit 的 tag ,拉取指定tag的commmit| |@23dfdd5| 指定commit|

  • go mod 参考 go help mod 常用命令: | 命令 | 说明| |------|-----| |go mod init| 初始化模块并生成 go.mod | |go mod download| 下载 go.mod 文件中的模块,放到本地仓库| |go mod tidy| 整理 go.mod 中的依赖,增加需要的模块,删除不需要的模块| |go mod graph| 图结构显示所有依赖结构|

ps: go mod graph 命令输出每一行的格式为:模块 依赖模块,此外,还可以借助第三方工具图形化显示依赖图。下面介绍的是 gmgraph 项目地址:go-mod-graph-chart 安装:

$ go get -u github.com/PaulXu-cn/go-mod-graph-chart/gmchart

使用:

$ cd goProject
$ go mod graph | gmchart

之后浏览器访问命令行中给出的端口就可以看到依赖图了,示例如下: image.png

总结

课上学习了 go 的依赖管理,包括 go 依赖管理的演进、Go Module 的讲解等。

参考