:::info
日期:2021 年 02 月 18 日
作者:Jay Conrod
原文链接:https://go.dev/blog/go116-module-changes
:::
我们希望您喜欢 Go 1.16! 这个版本有很多新特性,尤其是模块。 发行说明简要描述了这些更改,但让我们深入探讨其中的一些。
默认的模块
go 命令现在默认以模块感知模式构建包,即使没有 go.mod 存在。 这是朝着在所有项目中使用模块迈出的一大步。
通过将 GO111MODULE 环境变量设置为 off,仍然可以在 GOPATH 模式下构建包。 您还可以将 GO111MODULE 设置为 auto 以仅在当前目录或任何父目录中存在 go.mod 文件时启用模块感知模式。 这是以前的默认设置。 请注意,您可以使用 go env -w 永久设置 GO111MODULE 和其他变量:
go env -w GO111MODULE=auto
我们计划在 Go 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 停止安装命令二进制文件。 有关详细信息,请参阅问题 43684。
模块撤回
你有没有在一个模块版本准备好之前不小心发布了它? 或者您是否在某个版本发布后立即发现了需要快速修复的问题? 已发布版本中的错误很难更正。 为了保持模块构建的确定性,版本发布后不能修改。 即使您删除或更改版本标签,proxy.golang.org 和其他代理也可能已经缓存了原始版本。
模块作者现在可以使用 go.mod 中的撤回指令撤回模块版本。 撤回的版本仍然存在并且可以下载(因此依赖于它的构建不会中断),但是 go 命令在解析 @latest 等版本时不会自动选择它。 go get and go 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 的用户在检查更新或升级依赖包时将收到撤回通知。 通知消息可以包括来自撤回指令上方的评论的文本。
$ 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。 有关语法详细信息,请参阅收回指令文档。
使用 GOVCS 控制版本控制工具
go 命令可以从 proxy.golang.org 等镜像下载模块源代码,也可以使用 git、hg、svn、bzr 或fossil直接从版本控制存储库下载模块源代码。 直接版本控制访问很重要,特别是对于代理不可用的私有模块,但它也可能是一个安全问题:版本控制工具中的错误可能被恶意服务器利用来运行意外代码。
Go 1.16 引入了一个新的配置变量 GOVCS,它允许用户指定允许哪些模块使用特定的版本控制工具。 GOVCS 接受以逗号分隔的 pattern:vcslist 规则列表。 模式是一个路径。匹配模式匹配模块路径的一个或多个前导元素。 特殊模式 public 和 private 匹配 public 和 private 模块(private 定义为与 GOPRIVATE 中的模式匹配的模块;public 是其他一切)。 vcslist 是允许的版本控制命令或关键字 all 或 off 的管道分隔列表。
例如:
GOVCS=github.com:git,evil.com:off,*:git|hg
通过这个设置,可以使用 git 下载 github.com 上有路径的模块; evil.com 上的路径无法使用任何版本控制命令下载,所有其他路径(* 匹配所有内容)可以使用 git 或 hg 下载。
如果未设置 GOVCS,或者模块不匹配任何模式,则 go 命令使用此默认值:公共模块允许使用 git 和 hg,私有模块允许使用所有工具。 只允许 Git 和 Mercurial 背后的基本原理是,这两个系统最关注作为不受信任的服务器的客户端运行的问题。 相比之下,Bazaar、Fossil 和 Subversion 主要用于受信任的、经过身份验证的环境,不像攻击面那样受到严格审查。 也就是说,默认设置是:
GOVCS=public:git|hg,private:all
有关更多详细信息,请参阅使用 GOVCS 控制版本控制工具。
下一步该做什么?
我们希望您发现这些功能很有用。 我们已经在努力开发 Go 1.17 的下一组模块特性,特别是延迟模块加载,这应该会使模块加载过程更快、更稳定。 与往常一样,如果您遇到新的错误,请在问题跟踪器上告诉我们。 快乐编码!