Golang中如何在使用go mod vendor时排除特定包
Golang中如何在使用go mod vendor时排除特定包 你好。
为了在使用 go mod vendor 时排除特定的包,我像这样编写了 go.mod 文件:
module xxx
replace github.com/somepackage => /$GOPATH/pkg/mod/github.com/somepackage@v1.2.3
我不想对任何版本的 somepackage 进行 vendoring。
并且我仅将 go mod 用于 vendoring,所以实际的本地包路径并不重要。
这在 go v1.12 中有效。 但在 go v1.13.x 中无效。
-
如何在
go.mod中使用环境变量$GOPATH? 我无法将$GOPATH替换为真实路径。因为我和我的团队一起工作,成员们的$GOPATH并不相同。 -
如果我像这样替换该行:
replace github.com/somepackage => ../../pkg/mod/github.com/somepackage@v1.2.3
路径不是问题,但出现了 .../pkg/mod/github.com/somepackage@v1.2.3/go.mod: no such file or directory 错误。
此外,如果我只想 vendor somepackage 的某些子包,我该怎么做?
例如,
somepackage 包含 aa、aa/cc 和 bb
somepackage/aa <- 不进行 vendor
somepackage/aa/cc <- 进行 vendor
somepackage/bb <- 不进行 vendor
使用 dep 时,我可以通过 Gopkg.toml 像这样实现:
ignored = [
"github.com/somepackage/aa",
"github.com/somepackage/bb/*"
]
更多关于Golang中如何在使用go mod vendor时排除特定包的实战教程也可以访问 https://www.itying.com/category-94-b0.html
@ hollowaykeanho 谢谢。
我已经知道解决方案,并且在一些项目中已经像你那样做了。 但在这种情况下,由于某些原因,我无法那样做。
我有许多项目使用 ‘somepackage’,并且它们的目录位置差异很大。 所以,那样的话,我就需要有很多个 ‘somepackage’ 的克隆副本。 如果我需要更改(或更新)‘somepackage’,那将会非常麻烦。
我的情况是:
- ‘somepackage’ 没有 go.mod(它使用 ‘dep’)
- ‘somepackage’ 的体积非常大
- 除了 ‘somepackage’ 之外,我还必须 vendor 其他包
- ‘somepackage’ 有很多版本,而我的代码不能绑定到特定版本
- 我在 docker 容器中构建和执行项目 5-1. 每个容器使用不同的镜像 5-2. 每个镜像的 GOPATH 中已经包含了 ‘somepackage’(它们的 GOPATH 并不相同) 5-3. 每个镜像使用不同版本的 ‘somepackage’
- 我是团队协作
- 我只需要 ‘dep’ 的 ‘ignored’ 指令功能
- 有些项目不能在 ‘GOPATH/src’ 下,所以我必须使用 ‘go mod’
你能给我一些建议吗?
更多关于Golang中如何在使用go mod vendor时排除特定包的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Rooney_Programmer:
我以团队形式工作
这是个好消息。至少你不是一个人。 😁
Rooney_Programmer:
你能给我一些建议吗?
Rooney_Programmer:
- ‘somepackage’ 没有 go.mod(它使用 ‘dep’)
- ‘somepackage’ 的体量非常大
我仍然需要一些关于 somepackage 的信息。
- 它是一个停滞的项目吗?(例如缺少维护者)
- 如果有维护者,是否有提出过与此事相关的问题(例如迁移到 go module 等)?如果没有,依我之见,你能就此事向维护者提出问题吗?
- 你的团队探索过
go.mod中的exclude途径吗?(是的,在这种情况下我可能听起来非常愚蠢,但只是为了确认。)
关于 exclude 子句的详细信息:Modules · golang/go Wiki · GitHub
- 你们是否计划在未来对依赖项进行版本控制?(也就是说,到目前为止你们有什么想法吗?)
- 当前
somepackage的发布策略是什么? - 子包(例如
aa/cc)之间是否相互依赖?如果是,你能轻松地映射出它们吗(例如花费少于 15 分钟)? - 是否有分布级别的沙箱环境来测试你已经部署的 Docker 发行版?
somepackage的许可证是否允许在不产生 copyleft 影响的情况下进行分叉和编辑?(例如 MIT,Apache2,…,而不是 GPL… 基本上你拥有这样做的许可,而不会强迫你开源你的代码。)
Rooney_Programmer:
我在 docker 容器中构建和执行项目 5-1. 每个容器使用不同的镜像 5-2. 每个镜像的 GOPATH 中已经包含 ‘somepackage’(它们的 GOPATH 并不相同) 5-3. 每个镜像使用不同版本的 ‘somepackage’
目前,已识别出的问题列表如下:
- 在分发之前,
somepackage依赖项的版本控制不明确。 somepackage是某些经验丰富的 Gopher 所害怕的大型包噩梦。somepackage很可能是一个过时的包?!(取决于上面的问题 1)。- 由于项目已经分发,这是一个需要开发运维谨慎处理的问题。
somepackage是一个关键依赖项(许多项目依赖它)。
Rooney_Programmer:
somepackage 是一个模块还是传统的 GOPATH 包?
Rooney_Programmer:
- 如果我像这样替换这一行
replace github.com/somepackage => ../../pkg/mod/github.com/somepackage@v1.2.3路径不是问题,但出现了
.../pkg/mod/github.com/somepackage@v1.2.3/go.mod: no such file or directory错误。
本质上,replace 子句是将 github.com/somepackage 这个导入关键字别名指向一个本地目录或另一个包模块。换句话说,你可以将 somepackage git clone 到你的项目旁边,文件目录结构如下:
root
+---myProject
| + go.mod
| + ...
+---somePackage
+ go.mod?
+ ...
或者是在 myProject 内部的 vendor 包。
然后,在 myProject/go.mod 文件中,你的 replace 子句应该是:
replace github.com/somepackage => ../somePackage
这样 go 就会在本地目录中寻找 github.com/somepackage 模块。
另外,你不需要手动指向 $GOPATH/pkg/mod 目录,因为那是 go 模块的工作目录。如果你需要指向那里,那么 replace 子句应该是:
replace github.com/somepackage/aa/cc => github.com/anotherPackage/aa/cc vX.Y.Z
如果以上方法都失败了,你可能需要为特定的 vendor 包/子包进行 vendor 到模块的迁移。
更多信息:
replace子句:
- 模块与 Vendor
在 Go 1.13+ 中,使用 go mod vendor 时排除特定包的正确方法是使用 exclude 指令。以下是解决方案:
1. 排除整个包
在 go.mod 文件中使用 exclude 指令:
module xxx
go 1.13
require (
github.com/somepackage v1.2.3
// 其他依赖...
)
exclude github.com/somepackage v1.2.3
这样在执行 go mod vendor 时就不会包含 somepackage。
2. 使用环境变量的替代方案
如果你确实需要使用 replace 并处理不同的 GOPATH,可以使用相对路径:
module xxx
go 1.13
replace github.com/somepackage => ../pkg/mod/github.com/somepackage@v1.2.3
然后在执行命令时设置 GOMODCACHE:
# 确保模块缓存路径一致
export GOMODCACHE=$HOME/go/pkg/mod
go mod vendor
3. 排除特定子包
Go modules 不支持排除特定子包,但你可以通过以下方式实现类似效果:
方案A:使用空目录替换
module xxx
go 1.13
replace github.com/somepackage/aa => ./empty
replace github.com/somepackage/bb => ./empty
创建 empty 目录并添加 go.mod:
mkdir empty
cd empty
go mod init empty
方案B:使用构建标签
在需要排除的包中创建 vendor_exclude.go:
// +build !vendor
package main
import _ "github.com/somepackage/aa"
import _ "github.com/somepackage/bb"
然后 vendoring 时使用标签:
go mod vendor -mod=vendor
4. 完整示例
module example.com/myapp
go 1.13
require (
github.com/somepackage v1.2.3
github.com/otherpackage v1.0.0
)
// 排除整个包
exclude github.com/somepackage v1.2.3
// 或者使用 replace 指向本地空模块
replace github.com/somepackage/aa => ./internal/empty
replace github.com/somepackage/bb => ./internal/empty
创建空模块结构:
mkdir -p internal/empty
cd internal/empty
echo 'module empty' > go.mod
执行 vendoring:
go mod vendor
这样只会 vendor somepackage/aa/cc 子包,而排除 aa 和 bb 子包。

