最近,Golang发布了一个新版本1.16。版本引入了很多新功能,其中在模块方面的改进,今天我们就一起来深入学习一下。
go命令现在默认情况下以模块感知模式构建软件包,即使项目中没有go.mod也默认启动,这将对模块的全面使用起到重要作用。但是通过环境变量GO111MODULE设置为 off下,GOPATH模式仍然可用。
如果将GO111MODULE设置为auto,则会检测项目当前目录或任何父目录,如果其中存在go.mod文件,就会启用模块感知模式。这以前是默认设置。
如果要永久设置该选项,可以使用go env -w设置:
go env -w GO111MODULE=auto
据悉,Golang下个版本1.17中将完全放弃对GOPATH模式的支持。Golang1.17会忽略GO111MODULE变量设置。如果项目是以非模块感知模式构建的,请记得迁移。
此前,当go命令发现问题,go.mod或go.sum中的配置为不全的require指令或未设置sum值,go命令会自动尝试补全解决这个问题。但是该机制可能存在问题,会导致副作用:如果必需的模块未提供require所需的软件包,则go命令会添加新的依赖项,这可能会触发常见依赖项的升级。有些明显拼写错误路径也会耗费时间去从进行网络查询。
在Go 1.16中,支持模块的命令在发现问题后,go.mod或go.sum尝试自动修复问题时会报告错误。在大多数情况下,错误消息建议你通过命令来解决。
注意go get和go mod tidy还是会修改go.mod和go.sum。
我们知道可以通过通过指定@version后缀让go install现安装特定版本的可执行文件。比如
go install golang /x/tools/gopls@v0.6.5
使用该语法时,go install使用确切模块版本安装命令,而会忽略go.mod当前目录和父目录中的所有文件。
曾建议go get -u program安装一个可执行文件,但是该用法与go get中添加或更改模块版本要求的含义容易造成了混淆。为了避免意外修改go.mod,一般使用更复杂的命令,例如:
cd $HOME; GO111MODULE=on go get program@latest
在Go 1.16中,默认可以使用go install program@latest的语法。
为了消除关于使用go.mod的歧义,使用此安装语法时,程序文件中可能存在的指令有一些限制。特别是,至少目前不允许使用replace和exclude指令。
大家可能遇到过意外发布了模块版本的尴尬处境,或者在发布需要快速修复的版本后又马上发现问题问题的场景,版本发布中的错误很难纠正。为了保持模块构建的确定性,发布版本后不能对其进行修改。即使删除或更改了版本标签,proxy.golang其他代理也可能对其进行了缓存。
在新版本中,模块作者可以在go.mod中retract指令撤消模块版本。回退的版本仍然存在并且可以下载(因此依赖它的版本不会中断),但是go get和go list命令在解析诸如@latest标签时候,不会再自动选择它,而且会打印一条诸如下面例子的告警信息信息。
例如,假设一个库的cc/lib开发者发布了v1.0.5,然后发现一个新的安全问题。开发者可以将指令添加到其go.mod文件中,如下所示:
// Remote-triggered crash in package cc. See CVE-2021-xxxx.retract v1.0.5
然后可以标记并推送v1.0.6最新修复版本。此后,v1.0.5当检查更新或升级从属软件包时,就会通知已依赖的用户将撤消通知。通知消息可能包含retract语句上面注释中的文本。
go list -m -u allcc/lib v1.0.0 (retracted)go get .go: warning: cc/lib@v1.0.5: retracted by module author:Remote-triggered crash in package cc. See CVE-2021-xxxx.go: to switch to the latest unretracted version, run:go get cc/lib@latest
go命令可以直接从源码镜像下载源码,比如proxy.golang。也可以直接从常见版本管理仓库,比如git,hg,svn,bzr,或fossil。直接从版本控制访问非常重要,尤其是对于代理中不可用的私有模块而言,但这也是个安全风险点,版本控制工具中的bug可能被恶意利用,并运行精心设置的代码。
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来下载git模块。evil.com为禁止使用的站点路径,*可以匹配下载其他模块(使用git和hg。
如果GOVCS未设置,或者模块与任何模式都不匹配,则go命令使用以下默认值:git和hg允许用于公共模块,并且允许使用所有工具用于私有模块。仅允许使用Git和Mercurial的原因是,这两个系统常常默认作为,默认不受信任客户端运行。而Bazaar,Fossil和Subversion主要用于受信任的,经过身份验证的环境,并且没有像攻击面那样受到严格的审查。即,默认设置为:
GOVCS=public:git|hg,private:all