Go包管理的方式有哪些
介绍
早期Go的包管理存在很多缺陷,甚至没有官方统一的包管理工具, 一方面官方在努力发布一些实验性的包管理工具,同时也出现很多社区开发的包管理工具, 比如Godep, dep, Glide, gvt, Govendor。 但是主流的包管理只需要关注以下三种:
- GOPATH(<Go1.5)
- Go Vendor(>=Go1.5)
- Go Modules(>=Go1.11)
GOPATH模式
GOPATH是最早的依赖包管理方式,从Go语言2009.11.10发布的第一个开源版本就有的。
GOPATH本质上不算Go的包管理工具,他只是提供一个存放包的路径的一个环境变量。tips: GOPATH模式缺陷:不支持依赖包的版本控制,因为GOPATH模式下同一个包的导入路径是一样的。
GOPATH模式和GOPATH路径的区别
- GOPATH 模式:一种项目结构和依赖管理模式,要求所有项目和依赖都位于 GOPATH 目录下。
- GOPATH 路径:一个环境变量,指向Go工作区的物理位置,在GOPATH模式下用于组织和存储Go项目和依赖。
tips: 不管我们使用哪种包管理方式都可以有GOPATH路径,而这个包管理方式有可能依赖GOPATH路径来实现,也可能不需要GOPATH路径,并不是设置了GOPATH路径就一定使用了GOPATH 模式来管理我们依赖包。
GOROOT和GOPATH的区别
GOROOT是Golang的安装目录, 存放的是Go语言内置的开发包和工具。 GOPATH是Go语言指定的工作空间,用于存放Go工程代码和第三方依赖包。
tips: GOPATH不能跟GOROOT是同一个目录,这样容易导致项目中的包于标准库重名而造成编译出现问题。
Govendor
- 2015.8.19在Golang1.5版本引入,默认关闭, 通过手动设置环境变量开启:
GO15VENDOREXPERIMENT=1开启
- Golang1.6默认开启
- Golang1.7 vendor作为功能支持,取消
GO15VENDOREXPERIMENT
环境变量 Govendor本质是把源码copy到vendor目录下,通过在vendor目录维护一个vendor.json文件,指定使用的包版本。在同步到 github 时,既可以把代码直接全部包含到项目中,也可以用 .gitignore 忽略依赖的库并通过 govendor sync命令同步。
安装govendor工具
go get -u github.com/kardianos/govendor
在项目根目录下初始化
govendor init
将项目依赖全部加入vendor目录
govendor add +external
移除依赖
govendor remove +unused
优点:第三方依赖包完全整合到项目中,加快build速度,在CI/CD流程中,提升整体构建速度。
缺点:包的依赖不能重用,冗余度提高,对于一些依赖冲突无法很好解决。
Go Modules
- Go1.11发布Go Modules, 默认是关闭的,直到Go1.13才开启。
- 在Go1.11~Go1.12需要通过变量
GO111MODULE
开启。- on 开启
- off 关闭
- auto 当项目路径在
$GOPATH
目录外部时, 为开启状态;当项目路径位于内部时,即使存在go.mod文件,也会为关闭状态。
开启Go Modules:
export GO111MODULE=on (unix环境)
set GO111MODULE=on (windows环境)
# 或者使用go env 指令进行设置
go env -w GO111MODULE=on
关于go mod的几个常用指令需要掌握:
go mod init
用来初始化一个新的go modules工程, 并创建go.mod文件
go mod tidy
用来解决工程中包的依赖关系,如果是缺少的包会下载并将依赖包的信息维护到go.mod和go.sum文件中;如果是项目中没有用到的依赖包则会将依赖包的信息从go.mod和go.sum文件中移除。
go mod download
下载依赖包到本地缓存。如果go.mod和go.sum文件中已经包含依赖包的信息,而依赖包还没下载到本地就可以执行这个指令。
go mod vendor
这个指令是为了兼容Go Vendor模式,在Go Modules发布之前,Go Vendor使用比较普遍,所以go mod也支持将依赖包通过go mod vendor指令复制到项目的vendor目录中。
go.mod文件
执行go mod init之后,在当前目录下会生成一个go.mod文件。每个Go模块都由一个go.mod文件定义,这个文件描述模块的属性,包括它对其他模块和Go版本的依赖性。
// module声明工程名
module awm-api
// go version
go 1.21.5
// 直接依赖
require github.com/gin-gonic/gin v1.9.1 // indirectvrv@300352:P
// 间接依赖(依赖包的依赖)
require (
github.com/bxcodec/faker/v3 v3.5.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
)
go.sum文件
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
go.sum文件使我们触发项目依赖校验时生成,比如go build
, go run
, go get
, go mod tidy
等指令。
它详细的罗列了当前项目的直接依赖和间接依赖的所有模块的版本。
go.sum文件每行由模块导入路径、模块的版本和预期哈希组成。
<module> <version>[/go.mod] <hash>#SHA-256
go.sum是怎么做包校验的
1.记录hash:当第一次下载依赖项是,go会计算该依赖项的hash并存在go.sum文件中。 2.检验依赖:在后续的构建或模块操作中,go会重新计算每个依赖项的hash,并与go.sum文件记录的hash进行比较。如果hash不匹配,go命令会报错。
go.sum文件帮助保证了依赖项的安全性和完整性。即使依赖项的源码仓库被攻击或更改,hash不匹配的警告也会让开发意识到潜在的风险。