Go 1.16 中 Go Module 功能的更新
杰伊·康罗德(Jay Conrod)
2021年2月18日
我们希望你享受1.16!此版本具有很多新功能,尤其是模块。 发行说明简要描述这些变化,让我们深入探索其中一些更改。
默认情况下打开 Modules
现在,go
命令在默认情况下以模块感知模式构建包,即使不存在go.mod
。这是在所有项目中使用模块的一大步。
将GO111MODULE
环境变量设置为off
,仍然可以在GOPATH模式下构建包。您还可以将GO111MODULE
设置为auto
,以仅在当前目录或任何父目录中存在 go.mod 文件时启用模块感知模式。这是以前的默认设置。请注意,您可以使用go env-w
永久设置 GO111MODULE 和其他变量:
go env -w GO111MODULE=auto
我们计划在1.17中删除对GoPath模式的支持。换句话说,Go 1.17将忽略go111module
。如果您有未在模块感知模式下构建的项目,现在是迁移的时候了。如果遇到迁移的问题,请考虑提交问题或经验报告。
没有自动更改Go.mod和go.sum
以前,当go
命令发现go.mod
或go.sum
的问题, 如缺少require
指令或缺少sum
,它将尝试自动解决问题。 我们收到了很多反馈,认为这种行为令人惊讶,特别是对于像go list
这样通常没有副作用的命令。自动修复并不总是可取的: 如果任何必需的模块都没有提供导入的包,go
命令将添加一个新的依赖项,可能会触发公共依赖项的升级。如果输入路径拼写错误,也会导致网络查找(失败)。
在 Go 1.16 中,模块感知命令在发现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
和以前一样,go
命令可以使用vendor
目录,如果它存在的话(详见Vendoring)。像go get
和go mod tidy
这样的命令仍然会修改go.mod
和go.sum
,因为它们的主要目的是为了管理依赖关系。
安装一个特定版本的可执行文件
go install
命令现在可以通过指定一个@version
后缀来安装一个特定版本的可执行文件。
go install golang.org/x/tools/gopls@v0.6.5
当使用这个语法时,go install
从那个确切的模块版本安装命令,忽略了当前目录和父目录中的任何go.mod
文件。(如果没有@version
后缀,go install
继续像以前一样操作,使用当前模块的go.mod
中列出的版本要求和替换来构建程序。)
我们曾经建议用go get -u program
来安装可执行程序,但这种用法对go get
在go.mod
中添加或改变模块版本要求的意义造成了太多的混淆。而且为了避免意外地修改go.mod
,人们开始建议使用更复杂的命令,比如。
cd $HOME; GO111MODULE=on go get program@latest
现在我们都可以用go install program@latest
代替。详见go install。
为了消除关于使用哪个版本的歧义,在使用这种安装语法时,对程序的go.mod
文件中可能出现的指令有一些限制。特别是,"替换 "和 "排除 "指令是不允许的,至少目前是这样。从长远来看,一旦新的go install program@version
在足够多的使用情况下运行良好,我们计划让go get
停止安装命令二进制文件。详情见issue 43684。
模块撤回
你是否曾经不小心在模块准备好之前就发布了一个版本?或者你是否在一个版本发布后马上发现了一个问题,需要迅速修复?发布的版本中的错误是很难纠正的。为了保持模块构建的确定性,一个版本在发布后不能被修改。即使你删除或改变了一个版本标签,proxy.golang.org和其他代理可能已经有了原始缓存。
模块作者现在可以使用go.mod
中的retract
指令撤回模块版本。被撤回的版本仍然存在并可以被下载(因此依赖于它的构建不会被破坏),但go
命令在解析@latest
等版本时不会自动选择它。 go get
和go list -m -u
将打印关于现有使用的警告。
例如,假设一个流行的库example.com/lib
的作者发布了v1.0.5
,然后发现了一个新的安全问题。他们可以在他们的go.mod
文件中添加一条指令,就像下面这样。
//在软件包foo中发生远程触发的崩溃。参见CVE-2021-01234。
retract v1.0.5
接下来,作者可以标记并推送版本v1.0.6
,新的最高版本。在这之后,已经依赖v1.0.5
的用户在检查更新或升级依赖的软件包时,将被通知撤回的消息。通知信息可能包括retract
指令上面的注释文本。
$ 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
对于一个交互式的、基于浏览器的指南,请查看 play-with-go.dev 上的 Retract Module Versions。语法细节见retract
指令文档。
用 GOVCS 控制版本控制工具
go
命令可以从镜像中下载模块源代码,如proxy.golang.org,或直接从使用git
、hg
、svn
、bzr
或fossil
的版本控制库中下载。直接的版本控制访问是很重要的,特别是对于那些在代理上不可用的私有模块,但这也是一个潜在的安全问题:一个版本控制工具的错误可能被恶意的服务器利用来运行非预期的代码。
Go 1.16 引入了一个新的配置变量GOVCS
,让用户指定哪些模块可以使用特定的版本控制工具。 GOVCS
接受一个以逗号分隔的pattern:vcslist
规则列表。pattern
是一个path.Match模式,匹配模块路径的一个或多个前导元素。特殊模式public
和private
匹配公共和私有模块(private
被定义为由GOPRIVATE
中的模式匹配的模块;public
是其他一切)。vcslist
是一个管道分隔的允许的版本控制命令的列表,或者关键字all
或off
。
比如说。
GOVCS=github.com:git,evil.com:off,*:git|hg
有了这个设置,路径在github.com
的模块可以用git
下载;路径在evil.com
的模块不能用任何版本控制命令下载,所有其他路径(*
匹配所有)可以用git
或hg
下载。
如果没有设置GOVCS
,或者一个模块没有匹配任何模式,go
命令使用这个默认值:git
和hg
允许用于公共模块,所有工具都允许用于私有模块。只允许 Git 和 Mercurial 的理由是,这两个系统作为不受信任的服务器的客户端运行的问题最受关注。相比之下,Bazaar、Fossil 和 Subversion 主要被用于可信的、经过验证的环境中,没有被作为攻击面进行仔细检查。也就是说,默认设置是。
GOVCS=public:git|hg, private:all
更多细节见版本控制工具GOVCS
。
下一步是什么?
我们希望你觉得这些功能很有用。我们已经在为 Go 1.17 的下一组模块功能努力工作了,特别是lazy module loading,它应该使模块加载过程更快、更稳定。像往常一样,如果你遇到新的错误,请在问题跟踪器上告诉我们。编码愉快!
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: