Golang 1.16 中 Modules的主要变化更新
01介绍
Golang 1.16 已经正式发布了,其中 Modules 有一些变化:
- 默认开启 Modules。
- 不自动修改 go.mod 和 go.sum。
- 通过指定 @version 后缀安装特定版本可执行文件。
- 新增 retract 指令撤回 Module 版本。
- 使用新增配置变量 GOVCS 指定特定模块使用特定版本控制工具。
golang 1.16 默认开启 Modules,即使不存在go.mod
,Go 命令现在默认情况下也会在module-aware
(模块感知)模式下构建包。
在 golang 1.16 中,通过设置关闭GO111MODULE
环境变量,在GOPATH
模式下构建包仍然是可能的。您还可以将GO111MODULE
设置为auto
,以便在当前目录或任何父目录中存在go.mod
文件时启用module-aware
(模块感知)模式。您还可以使用go env -w
永久设置GO111MODULE
和其他变量,:
goenv-wGO111MODULE=auto
Go 官方计划在Go 1.17
中放弃对GOPATH
模式的支持。换句话说,Go 1.17
将忽略GO111MODULE
。如果您的项目不在module-aware
(模块感知)模式下构建,则现在是时候迁移至module-aware
(模块感知)模式了。
03不自动修改go.mod和go.sum
在 golang 1.16 之前版本中,当 go 命令发现go.mod
或go.sum
存在问题时,如缺少require
指令或缺少sum
,它将尝试自动解决问题。Go 官方收到很多反馈,这种行为是令人惊讶的,特别是对于 go 命令,如go list
,通常没有副作用。自动修复并不总是可取的:如果任何所需模块不提供导入的包,Go 命令将添加新的依赖项,可能触发常见依赖项的升级。即使输入路径拼写错误,也会导致(失败的)网络查找。
在 golang 1.16 中,module-aware
(模块感知)命令在go.mod
或go.sum
中发现问题后报告错误,而不是尝试自动解决问题。在大多数情况下,错误消息中列出建议命令来解决问题,例如:
$ go build example.go:3:8: no required module provides package golang.org/x/net/html; to add it: go get golang.org/x/net/html $ go get golang.org/x/net/html $ go build
golang 1.16 与 Go 之前版本一样,如果vendor
目录存在,Go 命令可能会使用vendor
目录。go get
和go mod tidy
命令仍然修改go.mod
和go.sum
,因为他们的主要目的是管理依赖关系。
04通过指定@version后缀安装特定版本可执行文件
go install
命令现在可以通过指定@version
后缀安装特定版本的可执行文件,例如:
go install golang.org/x/tools/gopls@v0.6.5
如果使用@version
后缀,go install
命令使用该确切 Module 版本,忽略当前目录和父目录中的任何go.mod
文件中的 Module 版本。
如果没有@version
后缀,go install
继续运行,因为它一直有,建立程序使用当前模块的go.mod
文件中 requirements 列表和 replacements 列表列出的版本。
为了消除使用哪个版本的模糊性,在使用此安装语法go install program@latest
时,Go 程序的 go.mod 文件中可能存在几个限制的指令。特别是,至少目前不允许replace
和exclude
指令。从长远来看,一旦新的go install program@version
在大多数使用情况下工作的很好的前提下,Go 官方计划在未来某个版本中让go get
命令停止安装二进制文件。
05新增retract指令撤回 Module 版本
您是否在模块版本准备好之前意外地发布了该版本?或者,您是否在发布需要快速修复的版本后发现了问题?已发布版本中的错误很难更正。为了保持模块生成的确定性,版本发布后无法修改。即使您删除或更改了版本标签,proxy.golang.org
和其他代理可能已经有原始缓存。
模块作者现在可以使用go.mod
中的retract
指令 retract 模块版本。retract 的版本仍然存在,可以下载(因此依赖于它的构建不会中断),但 go 命令在解决@latest
等版本时不会自动选择它。go get
和go list -m -u
会打印有关现有用途的警告。
例如,假设一个流行的库的作者example.com/lib
发布 v1.0.5,然后发现一个新的安全问题。他们可以添加指令到他们的go.mod
文件,例如:
//Remote-triggeredcrashinpackagefoo.SeeCVE-2021-01234.
retractv1.0.5
接下来,作者可以 tag 和 push 版本 v1.0.6,新的最高版本。在此之后,已依赖 v1.0.5 的用户在检查更新或升级依赖包时将收到撤回通知。通知消息可能包括收回指令上方注释的文本。例如:
$ go list -m -u all example.com/lib v1.0.0 (retracted) $ go get . go: warning: example.com/lib@v1.0.5: retracted by module author: Remote-triggered crash in package foo. See CVE-2021-01234. go: to switch to the latest unretracted version, run: go get example.com/lib@latest
06使用新增配置变量 GOVCS 指定特定模块使用特定版本控制工具
go 命令可以从镜像proxy.golang.org
或直接从版本控制存储库下载模块源代码,使用 git、hg、svn、bzr 或 fossil。直接版本控制访问很重要,尤其是对于代理上不可用的私有模块,但它也可能是一个安全问题:版本控制工具中的错误可能被恶意服务器利用来运行恶意代码。
Go 1.16 引入了一个新的配置变量 GOVCS,它允许用户指定哪些模块允许使用特定的版本控制工具。GOVCS 接受一个逗号分隔的模式列表:vcslist 规则。
模式是一条path.Match
。匹配模式匹配模块路径的一个或多个主要元素。公共和私有的特殊模式匹配公共和私有模块(私有定义为与 GOPRIVATE 中的模式匹配的模块;公共是其他一切模块)。vcslist 是允许版本控制命令或关键字 all 或 off 的管道分隔列表。例如:
GOVCS=github.com:git,evil.com:off,*:git|hg
使用此设置,可以使用 git 下载带有github.com
路径的模块;无法使用任何版本控制命令下载evil.com
上的路径,使用 git 或 hg 下载所有其他路径(*
匹配所有内容)的模块。
如果未设置环境变量 GOVCS,或者如果模块与任何模式不匹配,Go 命令将使用 GOVCS 的默认值:允许 git 和 hg 用于公共模块,并且允许所有工具用于私有模块。
设置只允许使用 Git 和 Mercurial 的理由是,这两个版本控制工具最关注作为不受信任服务器的客户端运行的问题。相比之下,Bazaar、Fossil 和 Subversion 主要用于受信任的、经过验证的环境中,而且没有像 attack surfaces 那样受到很好的审查。即默认设置为:
GOVCS=public:git|hg,private:all
07Module 未来发展
我们希望您发现这些功能很有用。我们已经开始开发 Go 1.17 的模块功能,特别是懒惰的模块加载,这应该使模块加载过程更快,更稳定。
08总结
本文主要介绍了 Golang 1.16 针对 Module 做的一些变化。通过 Go 官方的这些 Module 变化,切实解决了 Go 用户在使用 Go 时的实际问题。Go 官方也表示会在 Golang 1.17 计划彻底去除GOPATH
模式,所以,如果您的项目目前还没有迁移到 Module 模式,是时候开始迁移了。
下一篇:golang切片扩容规则实现