包管理

包管理 #

Go 包管理概述 #

Go 1.4 及之前 #

  • 必须设置 GOPATH 环境变量,且源代码必须存放在 GOPATH
  • 拉取外部依赖包时,总是拉取最新的版本,无法指定需要的版本

设置 GOPATH 环境变量有两个原因:

  • 它规定了 go get 命令下载的依赖包的存储位置($GOPATH/src
  • 通过设置 GOPATH,可以方便 Golang 计算出 import 的路径

Go 1.5 至 Go 1.10 #

每个项目的根目录下可以有一个 vendor 目录,里面存放了该项目的依赖的包

Go 1.11 至 Go 1.12 #

  • 默认使用的还是 GOPATH 的管理方式
  • 运行 export GO111MODULE=on,使用 Go Modules

GO111MODULEoff 时:

  1. 优先使用 vendor 目录下面的包,
  2. 如果 vendor 下面没有搜索到,再搜索 $GOPATH/src 下面的包,
  3. 如果 $GOPATH 下面没有搜索到,那么搜索 $GOROOT/src 下面的包

Go 1.13 及之后 #

Golang 的包管理默认使用 Go Modules


Go 包管理工具发展 #

monorepo #

所有的包都放在 GOPATH 里面,使用类似命名空间的包路径区分包


vendor #

Go 1.5 开始开始引入 vendor 包模式,如果项目目录下有 vendor 目录,那么 go 工具链会优先使用 vendor 内的包进行编译、测试等, 这之后第三方的包管理思路都是通过这种方式来实现,比如说由社区维护准官方包管理工具 dep

Dep #

golang/dep Github stars

Go 1.9 及之后

由于 Golang 作者跟 Dep 作者在 Dep 设计上的分歧,Golang 官方在 2018 年 5 月开始推 Go modules,并在 Go 1.13 中默认启用。 曾今自认为 Golang 官方的实验性工具就此没落,很少再有人维护了。 因此,建议 Dep 用户迁移到 Go modules。

Glide #

Masterminds/glide Github stars

govendor #

kardianos/govendor Github stars


Go Modules #

  • Go 1.11 - Go 1.12,运行 export GO111MODULE=on,使用 Go Modules
  • Go 1.13 之后,默认使用 Go Modules

$GOPATH 不再作为 build 时导入的角色, 依赖包会存放在 $GOPATH/pkg/mod 目录下。


Go Modules 原理 #

命令 #

# 下载所有依赖
go mod download

# 升级次级或补丁版本号
go get -u rsc.io/quote
# 仅升级补丁版本号
go get -u=patch rscio/quote

# 整理并更新 go.mod
go mod tidy
# 仅仅修改 go.mod 配置文件的内容
go mod edit --droprequire=golang.org/x/crypto

# 查看 go.mod 内容
go list -m all
# json 格式输出
go list -m -json all

# 格式化 go.mod
go mod edit -fmt

Module-aware mode vs GOPATH mode #

Module-aware mode is active by default whenever a go.mod file is found in the current directory or in any parent directory.

  • GO111MODULE
    • off
      • the go command never uses module support. Instead it looks in vendor directories and GOPATH to find dependencies
    • on
      • the go command requires the use of modules, never consulting GOPATH.
    • or auto (the default)
      • Module support is enabled only when the current directory contains a go.mod file or is below a directory containing a go.mod file.

In module-aware mode, GOPATH no longer defines the meaning of imports during a build, but it still stores downloaded dependencies (in GOPATH/pkg/mod) and installed commands (in GOPATH/bin, unless GOBIN is set).


replace #

go modules 下 import 不再支持使用相对路径导入包,例如 import "./mypkg",所以需要考虑 replace

本地替换的价值在于它提供了一种使自动生成的代码进入 go modules 系统的途径, 毕竟不管是 go tools 还是 rpc 工具,这些自动生成代码也是项目的一部分,如果不能纳入包管理器的管理范围想必会带来很大的麻烦。

replace 不会生成 go.sum 信息 #

使用本地包进行替换时并不会生成 go.sum 所需的信息,所以 go.sum 文件也没有生成。

replace 命令只能管理顶层依赖 #

一个包是顶层依赖还是间接依赖,取决于它在本 module 中是否被直接 import,而不是在 go.mod 文件中是否包含 // indirect 注释。

不管是直接编辑还是 go mod edit 修改,我们为 go.mod 添加的信息都只是对 go mod 的一种提示而已, 当运行 go build 或是 go mod tidy 时 golang 会自动更新 go.mod 导致某些修改无效,


go.sum #

go.sum 是一个构建状态跟踪文件。它会记录当前 module 所有的顶层和间接依赖,以及这些依赖的校验和,从而提供一个可以 100% 复现的构建过程并对构建对象提供安全性的保证。

应该把 go.sum 和 go.mod 一同添加进版本控制工具的跟踪列表,同时需要随着你的模块一起发布。如果你发布的模块中不包含此文件,使用者在构建时会报错,同时还可能出现安全风险(go.sum 提供了安全性的校验)。

go.sum 不是锁文件 #

npm 的 package-lock.json 是锁文件,go.sum 不是。

go.sum 同时还会保留过去使用的包的版本信息,以便日后可能的版本回退,这一点也与普通的锁文件不同。所以 go.sum 并不是包管理器的锁文件。


go mod vendor #

这个命令并不能让你从 godep 之类的工具迁移到 go modules,它只是单纯地把 go.sum 中的所有依赖下载到 vendor 目录里

使用 go build -mod=vendor 来构建项目

参考:


参考 #