我曾经写了一篇跳出Go module的泥潭, 记录了使用go module的一些坑,随着Go 1.13版本的发布,go module的功能再不断的演化(或者不委婉的说在不断的修补),go module很多功能也发生了变化,这篇文章记录了新版本(go 1.13)下module的使用方法。
不客气地的说,go module的实现不是一个很成功的功能的添加,首先go module的引入就引入了很大的争议,包括dep等多个go依赖工具的作者颇有微词,其次go module的功能并没有很好的设计就开始引入到go的发布版本中,导致Go多个版本module功能在不停的修修补补,第三,虽然go module也一些官方的文档,但是文档并不详细,也没有很好的列出各个版本对相应工具的影响。另外,go module多个版本的实现导致一些工具比如go等不向下兼容,刚入的新的Go开发者感觉不到兼容的变化,但是老的go开发者就很痛苦了,因为执行相同的命令产生了不同的"执行语义"。
如著名的Go布道者 Bill Kennedy 的吐槽:
当然,go module设计初衷还是好的,而且go生态圈也应该有一个强势的库依赖工具避免分片化。
即使你对go module有一件,我的观点是如果你不能改变它,那么就去接收它,所以让我们来了解一下go module对现有的功能的影响。
环境变量
首先,GO111MODULE
环境变量并没有被移除,它的默认值也没有发生了改变,依然是在auto, 但是auto的含义却发生了变化 :(。
在Go 1.13中auto意味着当前目录或者在目录中包含go.mod
文件夹的话,即使当前目前在$GOPATH/src
下,也会开启module模式。
很显然,Go开发者要强推go module功能了,但是如果你不了解的这种变化的化,很可能变得很茫然,因为初次使用go module可能会重新下载很多的依赖库。
相应的,这也对常用的IDE产生影响,幸运地是,主流的IDE都支持了go module功能,不用担心引入的库找不到的问题。
GOPROXY
环境变量设置代理服务器,可以设置多个代理服务器以及direct,已经有很多的代理服务器了,不用担心墙的问题,比如https://goproxy.cn,direct
GOSUMDB
可以用来校验你下载的库的哈希是否和官方的哈希值是否一样,避免被proxy给修改了,万一proxy给你的下载库加上挖矿代码就惨了,毫无疑问也被墙了,即使专为中国区设置的域名/服务器也被墙。你可以使用goproxy.cn
作为GOSUMDB服务器,或者心大使用GOSUMDB=off
进行禁用。
GOPRIVATE
用来设置不使用代理的仓库,比如一些公司内部的仓库等等,如GOPRIVATE=*.corp.example.com,rsc.io/private
。
作为和以前的兼容,还保留着GONOPROXY
,功能和GOPRIVATE
一样。
go env -w
可以为这些值设置为全局变量。有些人不建议你这么做,因为可能你在你的开发环境中编译好好的,但是在服务器或者docker中项目却无法编译,所以建议将这些环境变量写到配置文件如Makefile中。
go help module-auth
了解GOSUMDB
和GONOSUMDB
变量。
go help goproxy
了解proxy的通讯协议。
go help modules
了解module的功能。
go help module-get
了解go get
命令的变化。而go help gopath-get
显示先前的基于GOPATH的go get功能。
go help module-private
了解私有库的设置。
go mod 命令
go help mod
显示go mod
命令的子命令:
- download:下载依赖库到本地缓存中,当前在
$GOPAH/pkg/mod
中 - edit: 命令行中编辑go.mod
- graph: 显示依赖库的关系,包括间接依赖库都会显示,它以行的方式显示,如果能以tree方式显示更好。
- init: 初始化当前文件夹为module方式的go项目,会生成go.mod
- tidy: 增加新的依赖,移除不使用的依赖库
- vendor: 将依赖库放入到vendor文件夹下,如果将来使用module方式,这个命令是不会使用的
- verify: 校验下载到本地缓存中的依赖库自下载后未被修改
- why: 解释为什么需要一个依赖库(肯定是有代码使用它了,
go help mod why
可以看它的详细帮助)
一般新的项目,无论文件夹在哪里,首先go mod init
初始化它,然后go mod tidy
自动将引入的库加入到go.mod文件中。
go action 工具
老司机比较不适应的使用 go xxxx
工具参数和语义的改变。
如何更新go.mod文件中的库的版本到最新版本?如何值更新当前项目?如何更新本地库和依赖库?
go get
当前go get的命令的格式是go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]
。
首先 go get
会寻找依赖库的版本,它会寻找库的最新的tag未release的版本(tagged release version), 如 v0.4.5
或 v1.2.3
, 如果没有,则寻找pre版,如v0.0.1-pre1
,如果都没有,寻找最新的commit版。
当然你也可以指定下载某个库的某个特定的版本,如go get golang.org/x/text@v0.3.0
、go get golang.org/x/text@master
。
-t
是也下载 test 文件中的依赖。
-u
指示下载的库使用最新的minor
或 patch
最新版。'go get -u A'下载最新的A, 以及A依赖的 B v1.3.1 (而不是 B v1.2.3)。假如B依赖C,而C并没有提供任何A所需的包,那么C不会更新。
-u=patch
更新pacth release。'go get -u=patch A@latest'更新A到最新版,依赖的B更新到v1.2.4(而不是 V1.3.1)。go get -u=patch A
把A更新到最新的patch版,而不是minor版。
go get xxxxx/...
可以批量安装工具。 go get golang.org/x/perf/cmd/...
会安装perf的所有的命令行工具到$GOPATH/bin
中。
go get
相当于go get .
,它应用于当前文件夹对应的包,go get -u
和go get -u=patch
同样的处理。
没有-u
的时候,go get
并不会比go install
多做什么,go get -d
也不会比go list
多做什么。
go list
go list
列出所依赖的库,格式如下:go list [-f format] [-json] [-m] [list flags] [build flags] [packages]
-f
指定要显示的字段, -json
指定显示的格式为json格式,否则为每行一条记录的方式。
比如:
|
|
或者 go list -f '\{\{.ImportPath\}\}' ./...
、go list -json ./...
。
-deps
还会列出它们的依赖。
它还有其它一些参数,比如-e
、-compiled
、-test
, 还有-m
参数。
-m
列出所依赖的module,而不是package,比如go list -m all
。
-u
可以列出可升级的库的信息,如go list -m -u -json all
。
-versions
显示库的可用的版本列表。
all
all
现在是go action中一个特殊的语义,代表main module和它的依赖(The special pattern "all" specifies all the active modules, first the main module and then dependencies sorted by module path.
)
而...
代表代表匹配这个模式的所有活动的module(A pattern containing "..." specifies the active modules whose
module paths match the pattern.
)
go get all
、go list all
、go get -u all
、go get ./...
、go get -u ./...
都是合法的。
go保留了四个四个特殊的名字:
main
: 可执行程序的顶层包all
: GOPATH所有的包; module模式下指main module和它的依赖。std
: 标准库的包cmd
: go仓库里的命令行工具和它们的内部库
你可以使用go list std
、go list cmd
看看效果。
...
代表匹配任何字符串,包括空格和斜杠,但是不会匹配vendor文件夹。
乱。