Featured image of post Go 1.16 中Module功能新变化

Go 1.16 中Module功能新变化

原文地址:https://blog.golang.org/go116-module-changes
原文作者:Jay Conrod
译者:Kevin

希望您喜欢Go 1.16! 这个版本有很多新功能,特别是对Module而言。发行说明中简要介绍了这些变化,但让我们深入发掘一下其中的一些变化。

Module功能默认开启

go命令现在默认以module-aware模式构建包,即使没有go.mod文件存在。这是向在所有项目中使用Module功能迈出的一大步。

通过设置GO111MODULE环境变量为off,仍然可以在GOPATH模式下构建包。你也可以将GO111MODULE设置为auto,只有当当前目录或任何父目录中存在go.mod文件时才启用module-aware模式。这在以前是默认的。请注意,您可以使用go env -w来永久地设置GO111MODULE和其他变量。

go env -w GO111MODULE=auto

我们计划在 Go 1.17 中放弃对GOPATH模式的支持。换句话说,Go 1.17将忽略GO111MODULE。如果您的项目没有以module-aware模式构建,现在是时候迁移了。如果有问题妨碍您迁移,请考虑提交问题体验报告

不会自动更改 go.mod 和 go.sum

在之前的版本中,当go命令发现go.modgo.sum有问题时,比如缺少require指令或缺少sum,它会尝试自动修复问题。我们收到了很多反馈,认为这种行为是出乎大家意料的,尤其是对于像go list这样通常不会产生副作用的命令。自动修复并不总是可取的:如果一个导入的包没有被任何需要的Module提供,go命令会添加一个新的依赖关系,可能会触发普通依赖关系的升级。即使是拼写错误的导入路径也会导致(失败的)网络查找。

在 Go 1.16 中,module-aware命令在发现go.modgo.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

和之前一样,如果存在vendor目录,go命令可能会使用该目录(详见Vendoring)。像go getgo mod tidy这样的命令仍然会修改go.modgo.sum,因为它们的主要目的是管理依赖关系。

在特定版本上安装可执行文件

go install命令现在可以通过指定@version后缀来安装特定版本的可执行文件。

go install golang.org/x/tools/gopls@v0.6.5

当使用这种语法时,go install命令会从该Module的制定版本安装,而忽略当前目录和父目录中的任何 go.mod 文件。(如果没有@version后缀,go install会像往常一样继续运行,使用当前Module的go.mod中列出的版本要求和替换来构建程序。)

我们曾经推荐使用go get -u程序来安装可执行文件,但这种使用方式对go.mod中添加或更改Module版本需求的意义造成了太多的混淆。而为了避免意外修改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

Module撤回

您是否曾经在Module版本准备好之前不小心发布过?或者您是否在版本发布后就发现了一个需要快速修复的问题?发布的版本中的错误是很难纠正的。为了保持Module构建的确定性,一个版本在发布后不能被修改。即使你删除或更改了版本标签,proxy.golang.org和其他代理可能已经有了原始版本的缓存。

Module作者现在可以使用go.mod中的retract指令撤回Module版本。撤回的版本仍然存在,并且可以被下载(所以依赖它的构建不会中断),但在解析@latest这样的版本时,go命令不会自动选择它,go getgo list -m -u会打印关于现有使用版本的警告。

例如,假设一个流行库example.com/lib的作者发布了v1.0.5,然后发现了一个新的安全问题。他们可以在他们的go.mod文件中添加如下指令。

// Remote-triggered crash in package foo. See 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这样的镜像中下载Module源代码,或者直接从使用githgsvnbzrfossil的版本管理仓库中下载。直接的版本控制访问是很重要的,特别是对于那些在代理上无法使用的私有Module,但这也是一个潜在的安全问题:版本控制工具中的一个bug可能会被恶意服务器利用,运行非预期的代码。

Go 1.16引入了一个新的配置变量GOVCS,让用户可以指定哪些Module可以使用特定的版本控制工具。GOVCS接受一个以逗号分隔的pattern:vcslist规则列表。pattern是一个path.Match模式,匹配一个Module路径的一个或多个前缀元素。特殊模式public和private匹配公共和私有Module(private被定义为由GOPRIVATE中的模式匹配的Module;public是其他所有Module)。vcslist是一个以管道符分隔的允许的版本控制命令列表,或关键字alloff

例如

GOVCS=github.com:git,evil.com:off,*:git|hg

在此设置下,路径在github.com上的Module可以使用git下载;路径在evil.com上的Module不能使用任何版本管理程序下载,其他所有路径(*匹配所有)可以使用githg下载。

如果没有设置GOVCS,或者一个Module不符合任何模式,go命令就会使用这个默认值:公共Module允许使用githg,私有Module允许使用所有工具。只允许GitMercurial的理由是,这两个系统作为不受信任的服务器的客户端运行的问题最受关注。相比之下,BazaarFossilSubversion主要是在受信任的、经过认证的环境中使用,作为攻击面的审查程度不高。也就是说,默认的设置是

GOVCS=public:git|hg,private:all

更多细节请参见使用GOVCS控制版本管理工具

下一步?

我们希望您觉得这些功能很有用。我们已经在努力为Go 1.17开发新的Module功能,特别是懒惰Module加载,这将使Module加载过程更快、更稳定。和以往一样,如果您遇到新的bug,请在问题跟踪上告诉我们。Happy coding!

Built with Hugo
主题 StackJimmy 设计