失宠的Vendor目录

Vendor目录是Golang从1.5版本开始引入的,为项目开发提供了一种离线保存第三方依赖包的方法。但是到了Golang 1.11之后,由于引入了Module功能,在运行go build时,优先引用的是Module依赖包的逻辑,所以Vendor目录就被“无视”了,进而可能会发生以下编译错误(中间一个是因为当前的GOPATH不对,这是个伏笔):

Module说,还是很想他

上篇文章提到过go mod有很多子命令,其中就有个go mod vendor命令,运行试试,不出意外地报错了:

报错信息说找不到main module,应该是每次使用module功能都得先go mod init一把,那么试试go mod init github.com/nevermosby/mydocker,结果令人惊奇:

go mod init命令竟然是respectGodep功能的!!!来看看生成的go.mod文件:

module github.com/nevermosby/mydocker

require (
    github.com/Sirupsen/logrus v0.0.0-20151204141443-446d1c146faa
    github.com/urfave/cli v0.0.0-20161122043610-0bdeddeeb0f6
    golang.org/x/sys v0.0.0-20151211033651-833a04a10549
)

对比Godep.json原文件相关内容:

"Deps": [
        {
            "ImportPath": "github.com/Sirupsen/logrus",
            "Comment": "v0.8.7-53-g446d1c1",
            "Rev": "446d1c146faa8ed3f4218f056fcd165f6bcfda81"
        },
        {
            "ImportPath": "github.com/urfave/cli",
            "Comment": "v1.19.1",
            "Rev": "0bdeddeeb0f650497d603c4ad7b20cfe685682f6"
        },
        {
            "ImportPath": "golang.org/x/sys/unix",
            "Rev": "833a04a10549a95dc34458c195cbad61bbb6cb4d"
        }
    ]

发生了以下映射关系:

  • Deps变成了require
  • ImportPath内容被沿用下来,毕竟是依赖包名称
  • Comment被直接舍弃了,Nice to have的东西一般都是这个下场
  • v0.0.0-20151204141443-446d1c146faa,这段很有趣,v0.0.0是为了符合go module版本控制的规范做的workround; 20151204141443-446d1c146faa是代表了这个依赖包当初被引入时最新一次commit的时间和hash值(取了前12位),应该是通过Rev这个commit反查出来的

这么看来,Godep作为Dependency tools for go的前身,相比go vendor,与go module还是更近一点。那实在喜欢go vendor的我们该如何是好?

Module说,那我们重新开始

还记得刚开始执行的go mod vendor命令么,让我们再试试。。。这次运行完毕没有任何报错了,所以他们俩终于“有情人终成眷属”了?!有疑问找help文档:

$ go mod help vendor
usage: go mod vendor [-v]

Vendor resets the main module's vendor directory to include all packages needed to build and test all the main module's packages.
It does not include test code for vendored packages.

帮助文档告诉我们,这个操作的本质是把原有vendor目录里的内容,reset成当前程序所需的全部依赖包,即把执行go mod init后下载的相关依赖包(都被下载到了GOPATHpkg目录)全部复制到原有vendor目录下了,通过git status可以证明这件事情:

不难发现,原有vendor目录里的依赖包内容发生了改变,选一个看看diff

是权限发生了改变,可以侧面证明文件有被覆盖更新的痕迹。

终于真相大白了,要跟go module重新开始的前提,就是你得先变成他喜欢的样子。。。

好日子终于要开始了?

来吧,试试go build能否成功,这次咱们长个心眼,提前看看帮助文档里有没有与go module相关的内容。。。果不其然,有个可选参数:

go build -mod=vendor

运行试试。。。编译成功了,生成了可执行文件,运行它,结果符合期待。。。

你是不是跟我一样,发现了不得了的事情了,联系文章开头的伏笔,发现了通过go module机制,编译go语言项目竟然可以不用指定GOPATH了。。。

预知后事如何,请看下回——“最终章,引入Go Module的本质”

发表评论

电子邮件地址不会被公开。 必填项已用*标注