go mod vendor 如何使用

1. go vendor

1.1. go mod vendor 如何使用

go mod vendor 的功能是将新增的依赖包自动写入当前项目的 vendor 目录。

  1. 首先写一个 test,在 test 中 “使用新增依赖包的” 代码

  2. go mod tidy

  3. go mod vendor

1.2. vendor 里面的 package 要更新

go get -u gitlab.xxx.com/project_name@dev
go mod vendor
go mod tidy

example: go get -u github.com/GuanceCloud/dockertest/v3@v3.9.3

1.3. Update All Go Modules

Wanting to update all dependencies in a way that it doesn’t break is somewhat more complicated than expected.

I used to only do go get -u all which unfortunately broke, or forgot some dependencies, under certain conditions. After some GitHub issue spelunking, I’ve ended up with the following that works reliably:

$ go get -d -u -t ./...

Specifically the -t flag ensures that test dependencies are updated too.

To ensure that my go.mod and go.sum files contain all necessary checksums and removes the ones I don’t need anymore, I always run the following right after:

$ go mod tidy

Relevant docs:

1.4. replace modules

go.mod:

require (
	github.com/pyroscope-io/pyroscope v0.36.0
)

replace (
	github.com/pyroscope-io/pyroscope v0.36.0 => github.com/GuanceCloud/pyroscope v0.36.1
)

1.5. 包版本降级

直接改版本号不行,tidy 后又会改回原来的新版本号。必须使用 replace。

go.mod:

// replace
replace (
	google.golang.org/grpc => google.golang.org/grpc v1.51.0
)

1.6. go mod 全部操作命令

# go mod 初始化
go mod init 模块名

# go mod 下载到本地Cache
go mod download
# go mod 清理本地Cache
go clean -modcache

# go mod 编辑go.mod文件:更多go mod查看 `go help mod edit`
go mod edit

# go mod 打印依赖图
go mod graph

# go mod 删除错误或者不使用的modules
go mod tidy

# go mod 生成vendor目录
go mod vendor

# go mod 验证依赖是否正确
go mod verify

# go mod 查找依赖
go mod why

# go mod 更新依赖到最新版本
go get -u github.com/golang/protobuf

# go mod 更新到指定版本
go get -u github.com/golang/protobuf@指定版本
# go mod 查看有哪些版本
go list -m -versions github.com/golang/protobuf

# go mod 替换包源
go mod edit -replace=golang.org/x/crypto@v0.0.0=github.com/golang/crypto@latest
go mod edit -replace=golang.org/x/sys@v0.0.0=github.com/golang/sys@latest

2. golang 使用 vendor 目录来管理依赖包

2.1. Vendor 目录介绍

随着 Go 1.5 release 版本的发布, vendor 目录被添加到除了 GOPATHGOROOT 之外的依赖目录查找的解决方案。在 Go 1.6 之前, 你需要手动的设置环境变量 GO15VENDOREXPERIMENT=1 才可以使 Go 找到 Vendor 目录, 然而在 Go 1.6 之后, 这个功能已经不需要配置环境变量就可以实现了。

Note, 即使使用 vendor, 也必须在 GOPATH 中, 在 go 的工具链中, 你逃不掉 GOPATH

那么查找依赖包路径的解决方案 (顺序) 如下:

  • 当前包下的 vendor 目录。
  • 向上级目录查找, 直到找到 src 下的 vendor 目录。
  • GOPATH 下面查找依赖包。
  • GOROOT 目录下查找

2.2. 一些建议

在使用 vendor 中, 给出如下建议:

  1. 一个库工程 (不包含 mainpackage) 不应该在自己的版本控制中存储外部的包在 vendor 目录中, 除非他们有特殊原因并且知道为什么要这么做。
  2. 在一个应用中, (包含 mainpackage), 建议只有一个 vendor 目录在代码库一级目录。

上面建议的原因如下:

  • 在目录结构中的每个包的实例, 即使是同一个包的同一个版本, 都会打到最终的二进制文件中, 如果每个人都单独的存储自己的依赖包, 会迅速导致生成文件的二进制爆发(binary bloat)
  • 在一个目录的某个 pacage 类型, 并不兼容在同一个 package 但是在不同目录的类型, 即便是同一个版本的 package, 那意味着 loggers, 数据库连接, 和其他共享的实例都没法工作。

2.3. 举个例子

工程目录如下:

- $GOPATH/src/github.com/mattfarina/golang-broken-vendor
  - foo.go
  - vendor/
    - a/
    - b/
        - vendor/a/

在这个例子中, 两个 a package 都是完全一样的, b package 在代码库中保存了 a package, 在顶级应用代码中也引用了 a 包。

文件 foo.go 做了很简单的事情:

func main() {
    var it a.A
    it = "foo"

    b.Do(it)
}

那么问题来了, 当我们 build 的时候, 发现出问题了, 返回了下面的错误:

$ GO15VENDOREXPERIMENT=1 go build
./foo.go:12: cannot use it (type "github.com/mattfarina/golang-broken-vendor/vendor/a".A) as type "github.com/mattfarina/golang-broken-vendor/vendor/b/vendor/a".A in argument to b.Do
你可以 clone 这个测试工程到本地重现。

2.4. 为什么用 vendor 目录

如果我们已经使用 GOPATH 去存储 packages 了, 问什么还需要使用 vendor 目录呢? 这是一个很实战的问题。

假如多个应用使用一个依赖包的不同版本? 这个问题不只是 Go 应用, 其他语言也会有这个问题。

vendor 目录允许不同的代码库拥有它自己的依赖包, 并且不同于其他代码库的版本, 这就很好的做到了工程的隔离。

2.5. 推荐

2.5.1. Glide

我们发现 Glide 是非常好的包管理解决方案, 他将依赖包平展开存放在顶级 vendor 目录中, 如果一个包被另一个程序引用了, 那么这个包最好不要存储外部依赖项。如果使用 Glide, 你可以在 glide.yml 文件中指定依赖包, Glide 会帮你管理, 并使用正确的版本。

2.6. golang vendor 使用

使用 golang 编译程序时总遇到找不到包之类的情况, 尤其制作 docker 镜像时候如果全部在 Dockerfile 里面 go get 会很卡, 还必须上网下载依赖包, 使用 golang 的包以来管理可以很轻松的解决这些问题, build 镜像时候把 vendor 拷贝进去, 制作 docker image 也是十分的快。下面是步骤

  1. 先下载 vendor
go get -u github.com/kardianos/govendor
  1. cd 到这个目录编译出二进制

go build 生成 govendor 文件

  1. 把这个可执行文件拷贝到 bin 目录, 或者添加到 gopath(或者知道这个目录地址直接用也行)

  2. cd 到自己的工程目录

  3. 执行 ./govendor init 生成 vendor 目录

  4. 执行 ./vendor add +external 导入依赖包

此时你的工程目录已经导入依赖的编译包, 此时执行 go build 使用的包全在 vendor

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云满笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值