Go Module 2019 年展望
Russ Cox
19 December 2018
多么伟大的一年
对于Go生态系统来说,2018年是伟大的一年,包管理是我们的主要重点之一。 在2月份,我们开始了关于如何将包管理直接集成到Go工具链中的社区讨论,8月,我们在Go 1.11中提供了该功能的第一个粗略实现,称为Go模块。自Go 1以来,向Go模块的迁移将是Go生态系统中影响最深远的变化。要将整个生态系统(包括代码,用户,工具等)从GOPATH转换到Go模块,将需要在许多不同领域进行工作。反过来,模块系统将帮助我们为Go生态系统提供更好的身份验证和构建速度。
这篇文章是Go团队计划在2019年与模块相关的计划的预览。
发布
2018年8月发布的Go 1.11引入了模块的初步支持。目前,与传统的基于GOPATH的机制一起维护模块支持。在GOPATH / src外部的目录树中运行时,go
命令默认为模块模式,并在其根目录中以go.mod
文件标记。可以通过将过渡环境变量$ GO111MODULE
设置为on
或off
来覆盖此设置;默认行为是auto
模式。我们已经在Go社区中看到了模块的广泛采用,以及许多有用的建议和错误报告,可帮助我们改进模块。
计划于2019年2月发布的Go 1.12将完善模块支持,但默认情况下仍将其保留为auto
模式。除了许多错误修复和其他较小的改进之外,Go 1.12中最重要的变化可能是go
run
x.go
或之类的命令go
get
rsc.io/2fa@v1.1.0
现在可以在GO111MODULE = on
模式下运行,而无需显式的go.mod < aaaa>
文件。
我们的目标是计划于2019年8月发布的Go 1.13默认启用模块模式(即将默认设置从auto
更改为on
),并弃用GOPATH模式。为此,我们一直在致力于提供更好的工具支持以及对开源模块生态系统的更好支持。
工具和IDE集成
在拥有GOPATH的8年中,假设Go源代码存储在GOPATH中,已经创建了数量惊人的工具。转移到modules需要更新所有进行该假设的代码。我们设计了一个新的程序包,golang.org/x/tools/go/packages,该程序包抽象了查找和加载加载有关给定目标的Go源代码信息的操作。这个新的包可以自动适应GOPATH和modules模式,也可以扩展到特定于工具的代码布局,例如Bazel使用的布局。我们一直在与整个Go社区的工具作者合作,以帮助他们在其工具中采用golang.org/x/tools/go/packages。
作为这项工作的一部分,我们还一直在努力将各种源代码查询工具(例如gocode,godef和go-outline)统一为一个可从命令行使用并支持现代IDE使用的语言服务协议的工具。
向modules的过渡以及包加载的变化也促使Go程序分许发生了重大变化。作为对go
vet
进行重做以支持modules的一部分,我们引入了用于Go程序增量分析的通用框架,其中,一个分析器一次只会为一个包调用。在此框架中,对一个包的分析可以写出事实,这个事实对其他导入这个包的分析是可用的。例如, go
vet
对log包的分析确定并记录了log.Printf
是fmt.Printf
的一个包装器。然后,go
vet
可以检查其他调用log.Printf
的软件包中的printf-style格式字符串。该框架应使得许多新的、复杂的程序分析工具成为可能,以帮助开发人员发现错误并更好的理解代码。
Module 索引
go
get
的原始设计中最重要的部分之一是去中心化:我们那时相信—并且今天依然相信—任何人都应该能够发布他们的代码到任何服务器上,与中心化的仓库例如 Perl的CPAN,Java的Maven,或者Node的NPM不同。在go
get
导入空间的开头放置域名可以重用现有的去中心化系统,并且无需重新解决决定谁可以使用哪些名称的问题。它还允许公司将代码从公共服务器上导入到私有服务器上。当我们转向Go modules时,保持这种去中心化至关重要。
Go的依赖项去中心化有很多好处,但同时也带来了一些明显的缺点。首先,要找到所有公开可用的Go软件包太难了。每个要给予有关软件包信息的站点都必须自己进行爬虫,或者等到一个用户来询问特定软件包后再去获取。
我们正在开发一项名为Go Module Index的新服务,该服务将提供进入Go生态系统的软件包的公共日志。诸如godoc.org和goreportcard.com之类的站点将能够在此日志中查看新条目,而不是每一个都独立的写代码来找到新的软件包。我们还希望该服务允许使用简单查询来查找软件包,允许goimports
为尚未下载到本地系统的软件包添加导入。
模块身份验证
今天,go
get
依靠连接级身份验证(HTTPS或SSH)来检查它是否正在与正确的服务器进行通信以下载代码。如果对HTTPS或SSH机制进行某种程度的破坏,则无需对代码本身进行额外的检查,就可以进行中间人攻击。去中心化意味着从许多不同的服务器中获取构建的代码,这意味着该构建依赖于许多系统来提供正确的代码。
Go模块设计通过在每个模块中存储一个go.sum
文件来改善代码身份验证;该文件列出了模块每个依赖项的预期文件树的加密哈希。使用模块时,go
命令使用go.sum
来验证依赖项是否与预期版本逐位相同,然后在构建中使用它们。但是go.sum
文件仅列出该模块使用的特定依赖项的哈希值。如果要添加新的依赖项或使用go
get
-u
更新依赖项,则go.sum
中没有相应的条目,并且因此,无法直接验证下载的位。
对于可公开使用的模块,我们打算在模块索引日志之后运行一个称为公证人''的服务,下载新模块,并以密码形式签署声明,声明形式为
版本V的模块M具有文件树哈希H''。公证服务将以可查询的证书透明-样式防篡改日志发布所有这些经过公证的哈希/sec09/tech/full_papers/crosby.pdf),以便任何人都可以验证公证人的行为是否正确。此日志将用作公共的全局go.sum
文件,在添加或更新依赖项时,go
get
可用于对模块进行身份验证。
我们的目标是从Go 1.13开始,对go.sum
中尚不存在的公开可用模块进行go
命令检查公证哈希。
模块镜像
由于分散的go
get
从多个原始服务器获取代码,因此获取代码的速度和可靠性仅与最慢,最不可靠的服务器一样快和可靠。模块之前唯一可用的防御措施是将供应商依赖项放入您自己的存储库中。尽管将继续支持供应商,但我们希望有一种适用于所有模块的解决方案,而不仅仅是您已经在使用的模块,并且不需要将依赖项复制到每个使用它的存储库中。
Go模块设计引入了模块代理的概念,它是go
命令要求提供模块的服务器,而不是原始服务器。一种重要的代理是模块镜像,它通过从原始服务器获取模块请求然后缓存它们以供将来的请求来响应模块请求。运行良好的镜像即使在某些原始服务器出现故障的情况下也应该是快速而可靠的。我们计划在2019年为公开可用的模块启动镜像服务。其他项目(例如GoCenter和Athens)也在计划镜像服务。 (我们预计公司也将有多种选择来运行自己的内部镜像,但是本文主要针对公共镜像。)
镜像的一个潜在问题是它们恰好是中间人服务器,使其成为攻击的天然目标。 Go开发人员需要确保镜像所提供的位与原始服务器所提供的位相同。我们在上一节中描述的公证过程正好解决了这个问题,它将适用于使用镜像的下载以及使用原始服务器的下载。镜像本身不需要被信任。
我们的目标是从Go 1.13开始的go
命令中,默认情况下可以使用Google运行的模块镜像。使用备用镜像或根本不使用镜像将很容易配置。
模块发现
最后,我们在前面提到模块索引将使构建 godoc.org 之类的站点变得更加容易。我们 2019 年的工作之一将是 godoc.org 的重大改进,以使其对需要发现可用模块然后决定是否依赖给定模块的开发人员更加有用。
大图片
此图显示了本文中模块源代码如何在设计中移动。
以前,所有Go源代码使用者(go
命令和 godoc.org 之类的任何站点)都直接从每个代码主机获取代码。现在,他们可以从快速,可靠的镜像中获取缓存的代码,同时仍然可以验证下载的位是否正确。索引服务使镜像,godoc.org 和其他任何类似的站点都可以轻松地跟上每天添加到 Go 生态系统中的所有出色的新代码。
我们对 2019 年 Go 模块的未来感到兴奋,希望您也是如此。新年快乐!
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。