Golang 1.16 中 Module 有什么变化?

简介: Golang 1.16 中 Module 有什么变化?

介绍

Golang 1.16 已经正式发布了,其中 Modules 有一些变化:

  • 默认开启 Modules。
  • 不自动修改 go.modgo.sum
  • 通过指定 @version 后缀安装特定版本可执行文件。
  • 新增 retract 指令撤回 Module 版本。
  • 使用新增配置变量 GOVCS 指定特定模块使用特定版本控制工具。

本文来深入探讨一下 golang 1.16 关于 Modules 的一些变化。

默认开启 Modules

golang 1.16 默认开启 Modules,即使不存在 go.mod,Go 命令现在默认情况下也会在 module-aware(模块感知)模式下构建包。

在 golang 1.16 中,通过设置关闭 GO111MODULE 环境变量,在 GOPATH 模式下构建包仍然是可能的。您还可以将 GO111MODULE 设置为 auto,以便在当前目录或任何父目录中存在 go.mod 文件时启用 module-aware (模块感知)模式。您还可以使用 go env -w 永久设置 GO111MODULE 和其他变量,:

go env -w GO111MODULE=auto

Go 官方计划在 Go 1.17 中放弃对 GOPATH 模式的支持。换句话说,Go 1.17 将忽略 GO111MODULE。如果您的项目不在 module-aware (模块感知)模式下构建,则现在是时候迁移至 module-aware (模块感知)模式了。

不自动修改 go.modgo.sum

在 golang 1.16 之前版本中,当 go 命令发现 go.modgo.sum 存在问题时,如缺少 require 指令或缺少 sum,它将尝试自动解决问题。Go 官方收到很多反馈,这种行为是令人惊讶的,特别是对于 go 命令,如 go list,通常没有副作用。自动修复并不总是可取的:如果任何所需模块不提供导入的包,Go 命令将添加新的依赖项,可能触发常见依赖项的升级。即使输入路径拼写错误,也会导致(失败的)网络查找。

在 golang 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

golang 1.16 与 Go 之前版本一样,如果 vendor 目录存在,Go 命令可能会使用 vendor 目录。 go getgo mod tidy 命令仍然修改 go.modgo.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 get -u program 安装一个可执行文件, 但这种使用给 go get 安装或更改在 go.mod文件中 requirements 的 module 版本时造成了太多的混乱。

为了避免意外修改 go.mod,Go 用户开始建议更复杂的命令,如:

cd $HOME; GO111MODULE=on go get program@latest

现在,我们都可以使用 go install program@latest 代替。

为了消除使用哪个版本的模糊性,在使用此安装语法 go install program@latest 时,Go 程序的 go.mod 文件中可能存在几个限制的指令。特别是,至少目前不允许 replaceexclude 指令。从长远来看,一旦新的 go install program@version 在大多数使用情况下工作的很好的前提下,Go 官方计划在未来某个版本中让 go get 命令停止安装二进制文件。

05

新增 retract 指令撤回 Module 版本

您是否在模块版本准备好之前意外地发布了该版本?或者,您是否在发布需要快速修复的版本后发现了问题?已发布版本中的错误很难更正。为了保持模块生成的确定性,版本发布后无法修改。即使您删除或更改了版本标签,proxy.golang.org 和其他代理可能已经有原始缓存。

模块作者现在可以使用 go.mod 中的 retract 指令 retract 模块版本。retract 的版本仍然存在,可以下载(因此依赖于它的构建不会中断),但 go 命令在解决 @latest 等版本时不会自动选择它。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

接下来,作者可以 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

07

Module 未来发展

我们希望您发现这些功能很有用。我们已经开始开发 Go 1.17 的模块功能,特别是懒惰的模块加载,这应该使模块加载过程更快,更稳定。

08

总结

本文主要介绍了 Golang 1.16 针对 Module 做的一些变化。通过 Go 官方的这些 Module 变化,切实解决了 Go 用户在使用 Go 时的实际问题。Go 官方也表示会在 Golang 1.17 计划彻底去除 GOPATH 模式,所以,如果您的项目目前还没有迁移到 Module 模式,是时候开始迁移了。


目录
相关文章
|
2月前
|
存储 Go
Golang语言基于go module方式管理包(package)
这篇文章详细介绍了Golang语言中基于go module方式管理包(package)的方法,包括Go Modules的发展历史、go module的介绍、常用命令和操作步骤,并通过代码示例展示了如何初始化项目、引入第三方包、组织代码结构以及运行测试。
48 3
|
Go
【golang】解决:missing go.sum entry for module providing package
【golang】解决:missing go.sum entry for module providing package
1621 0
|
2月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
114 4
Golang语言之管道channel快速入门篇
|
2月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
67 4
Golang语言文件操作快速入门篇
|
2月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
104 3
Golang语言之gRPC程序设计示例
|
2月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
86 4
|
2月前
|
Go
Golang语言错误处理机制
这篇文章是关于Golang语言错误处理机制的教程,介绍了使用defer结合recover捕获错误、基于errors.New自定义错误以及使用panic抛出自定义错误的方法。
48 3
|
2月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
52 4
Golang语言goroutine协程篇
|
2月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
55 3
Golang语言之Prometheus的日志模块使用案例
|
2月前
|
Go
Golang语言之函数(func)进阶篇
这篇文章是关于Golang语言中函数高级用法的教程,涵盖了初始化函数、匿名函数、闭包函数、高阶函数、defer关键字以及系统函数的使用和案例。
64 3
Golang语言之函数(func)进阶篇