Golang中如何将vendor模式转换为module模式
Golang中如何将vendor模式转换为module模式 大家好,
我是Go语言的新手。我克隆了一个Go代码库,他们使用vendor目录来存储依赖项。我在vendor文件夹中添加了一个自定义包,但是当我执行go build mod=vendor时,出现了cannot find module providing package <package which is present in vendor dir>的错误。
此外,手动将包从$GOPATH/pkg/mod复制到这个vendor目录非常麻烦,感觉永无止境。我该如何将这种"vendor"模式转换为模块模式,并包含我之前编写的自定义包?我最终该如何构建这个项目?
我知道这是一个基础问题,但Go语言的构建/打包机制确实令人困惑,我几乎要放弃了!请帮帮我! 谢谢!
更多关于Golang中如何将vendor模式转换为module模式的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢Holloway!!!你真是我的救星。
更多关于Golang中如何将vendor模式转换为module模式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
请记住,在资源允许时进行长期迁移。请随时为最合适的回复标记"已解决"作为解决方案。
谢谢Halloway,但我还是不太明白。
invalid module path 这个错误是关于 replace 行的——而不是模块的名称。😕
我不确定是否应该将自定义模块推送到 GitHub 仓库?另外,在 Go 代码中,自定义私有模块的 import 语句应该怎么写?
请帮帮忙!能否写下实现这一点的步骤?哪怕是一个大致的提纲也会非常有帮助!
非常感谢!!
satishrao:
module /Users/sanupin/Downloads/admission-controller-webhook-demo-master
这不是一个有效的模块路径。有效的路径应该类似于:github.com/ABC/XYZ/admission-controller-webhook-demo-master。这本质上是 admission-controller-webhook-demo-master 的 import 路径。
satishrao:
这里,couchbase/api/couchbase-cluster/v1 是唯一自定义、自己编写的包 - 它本身可能有一些在 GitHub 上可用的依赖项。但是当我运行
你需要进入 ./vendor/couchbase/api/couchbase-cluster/v1 并像上面那样初始化另一个 go.mod。是的,这是另一个模块。在将其推送到专用仓库之前,名称应为:couchbase/api/couchbase-cluster/v1。
satishrao:
我知道这是个基础问题,但Go语言的构建/打包机制实在太令人困惑,我几乎要放弃了!请帮帮我!
欢迎来到Golang Bridge!🚀🎆
虽然这个问题并不简单,但请不要担心。
satishrao:
另外,手动将包从$GOPATH/pkg/mod复制到这个vendor目录实在太麻烦了。
如果你正在使用模块,就不应该再使用vendor了。这会让所有人都感到困惑。因此,我们的目标是在没有mod=vendor参数的情况下进行go build。
satishrao:
我该如何将这个"vendor"模式转换为模块模式,并包含我之前编写的自定义包?我最终该如何构建这个项目?
根据紧急程度,我建议两种方法。
短期解决方案
vendor对整体仓库有一个主要影响需要考虑:它会影响源代码中的本地导入。例如:
- 与其像
import "github.com/XYZ/abc"这样导入包,将该包放入vendor目录vendor/abc中,允许源代码像import "abc"这样导入包。
因此,我们需要解决这个问题。幸运的是,go.mod有一个replace子句,可以将源代码中的任何导入子句替换为本地目录。基于上面的例子:
replace (
abc => ./vendor/abc
...
)
一旦你相应地替换了所有vendor依赖项,请在没有mod=vendor参数的情况下再次测试运行。如果一切正常,你现在就可以继续了。
长期迁移方案
对于长期迁移,你需要将源代码中的import子句改回其原始仓库点。这将消除对vendor远程包的依赖。至于非远程的vendor包,你可以为其创建一个独立的模块仓库,并将其导入回项目中。
当我说长期时,意味着迁移需要时间,这取决于仓库的大小以及vendor导入语句在所有源代码中的分布范围。可以将其视为一次重构工作。
您好,
如果我的 go.mod 文件如下所示:
module /Users/sanupin/Downloads/admission-controller-webhook-demo-master
go 1.12
require (
github.com/ghodss/yaml v1.0.0
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf
github.com/json-iterator/go v1.1.5
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
github.com/spf13/pflag v1.0.3
golang.org/x/net v0.0.0-20180124060956-0ed95abb35c4
golang.org/x/text v0.3.0
gopkg.in/inf.v0 v0.9.0
gopkg.in/yaml.v2 v2.2.2
k8s.io/api v0.0.0-20180308224125-73d903622b73
k8s.io/apimachinery v0.0.0-20180228050457-302974c03f7e
)
replace (
couchbase/api/couchbase-cluster/v1 => ./vendor/couchbase/api/couchbase-cluster/v1
)
这里,couchbase/api/couchbase-cluster/v1 是唯一自定义、自己编写的包——它本身可能有一些在 GitHub 上可用的依赖项。但是当我运行:
bash-3.2$ GOOS=linux GOARCH=amd64 go build ./cmd/webhook-server/
go: errors parsing go.mod:
/Users/sanupin/Downloads/admission-controller-webhook-demo-master/go.mod:23: invalid module path
我的模块路径有什么问题导致它报错?
satishrao:
不是模块名称的问题
名称确实是个问题,因为你实际上是把模块锁定在了本地机器上。目前能正常工作主要得益于 git 版本控制系统的机制。
satishrao:
我不确定是否应该将自定义模块推送到 GitHub 仓库?另外,在 Go 代码中导入这个自定义私有模块的语句应该怎么写?
从长远来看,你应该把 ./vendor/couchbase/api/couchbase-cluster 推送到它自己专属的代码仓库。这是另一个模块,所以需要有自己的 go.mod 文件。
目前,我们先关注短期解决方案。
satishrao:
invalid module path错误是关于 replace 语句的问题 - 不是模块名称的问题 😕
replace 路径是否正确?也就是说,这个包是在你的 {main repo}/vendor/couchbase/api/couchbase-cluster/v1 还是 {main repo}/vendor/couchbase/api/couchbase-cluster 目录下?
这个错误是因为 replace 指向了一个无效的相对路径。
satishrao:
你能写下完成这个任务的步骤吗?哪怕是个大致提纲也会非常有帮助!
迁移清单相当直接:
- [x] 使用版本控制系统(git commit)冻结版本
- [x] 初始化
go.mod - [x] 检查所有
vendor外部依赖项并将其添加到require子句中 - [ ] 替换所有
vendor内部依赖项并将其添加到replace子句中 - [ ] 构建并测试结果,必须重现步骤 1 的结果
- [ ] 使用版本控制系统(git commit)冻结版本
- [ ] 将所有内部依赖项迁移到外部的独立模块中
- [ ] 修正所有
import语句以使用步骤 7 中创建的外部模块 - [ ] 构建并测试结果,必须重现步骤 1 的结果
- [ ] 使用版本控制系统(git commit)冻结版本
- [ ] 移除
replace子句 - [ ] 构建并测试结果,必须重现步骤 1 的结果
- [ ] 删除
vendor目录 - [ ] 使用版本控制系统(git commit)冻结版本
- [ ] 用双层芝士汉堡 + 可乐犒劳自己 [结束]
步骤 6 之后是长期实施方案。你现在处于步骤 4。如果你想直接跳到长期方案,可以跳到步骤 7。
要解决这个问题,你需要将项目从vendor模式转换为Go模块模式。以下是具体步骤和示例代码:
-
初始化Go模块:在项目根目录运行以下命令,将项目转换为模块模式。假设你的模块路径是
example.com/myproject:go mod init example.com/myproject这会生成一个
go.mod文件。 -
添加依赖项:运行以下命令来自动发现并添加依赖项到
go.mod:go mod tidy这会基于你的代码导入分析依赖,并下载缺失的模块到缓存中(默认在
$GOPATH/pkg/mod)。 -
处理自定义包:如果你在vendor目录中添加了自定义包(例如
mypackage),确保它位于项目内的一个子目录中(如./mypackage/),并在代码中正确导入。例如,如果你的自定义包在项目根目录下的mypackage文件夹中:- 在Go代码中导入它:
import "example.com/myproject/mypackage" - 运行
go mod tidy来验证依赖。
- 在Go代码中导入它:
-
移除vendor目录(可选):模块模式默认使用模块缓存,因此你可以删除vendor目录以简化项目结构:
rm -rf vendor如果你需要保留vendor目录用于离线构建,可以使用
go mod vendor重新生成它:go mod vendor -
构建项目:现在使用标准命令构建项目,无需
-mod=vendor标志:go build或者,如果仍需使用vendor目录构建:
go build -mod=vendor
完整示例过程:
- 假设项目结构如下:
myproject/ ├── main.go └── vendor/ └── mypackage/ └── mypackage.go - 在
main.go中导入自定义包:package main import "example.com/myproject/mypackage" func main() { mypackage.MyFunction() } - 执行命令:
go mod init example.com/myproject go mod tidy go build
如果自定义包不在项目根目录下,确保其路径在模块中可访问。例如,如果自定义包在internal/mypackage,则导入应为import "example.com/myproject/internal/mypackage"。
通过以上步骤,你的项目将成功转换为模块模式,并能够正确构建包含自定义包的代码。

