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 中无效。

  1. 如何在 go.mod 中使用环境变量 $GOPATH? 我无法将 $GOPATH 替换为真实路径。因为我和我的团队一起工作,成员们的 $GOPATH 并不相同。

  2. 如果我像这样替换该行:

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 包含 aaaa/ccbb 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

4 回复

@ hollowaykeanho 谢谢。

我已经知道解决方案,并且在一些项目中已经像你那样做了。 但在这种情况下,由于某些原因,我无法那样做。

我有许多项目使用 ‘somepackage’,并且它们的目录位置差异很大。 所以,那样的话,我就需要有很多个 ‘somepackage’ 的克隆副本。 如果我需要更改(或更新)‘somepackage’,那将会非常麻烦。

我的情况是:

  1. ‘somepackage’ 没有 go.mod(它使用 ‘dep’)
  2. ‘somepackage’ 的体积非常大
  3. 除了 ‘somepackage’ 之外,我还必须 vendor 其他包
  4. ‘somepackage’ 有很多版本,而我的代码不能绑定到特定版本
  5. 我在 docker 容器中构建和执行项目 5-1. 每个容器使用不同的镜像 5-2. 每个镜像的 GOPATH 中已经包含了 ‘somepackage’(它们的 GOPATH 并不相同) 5-3. 每个镜像使用不同版本的 ‘somepackage’
  6. 我是团队协作
  7. 我只需要 ‘dep’ 的 ‘ignored’ 指令功能
  8. 有些项目不能在 ‘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 的信息。

  1. 它是一个停滞的项目吗?(例如缺少维护者)
  2. 如果有维护者,是否有提出过与此事相关的问题(例如迁移到 go module 等)?如果没有,依我之见,你能就此事向维护者提出问题吗?
  3. 你的团队探索过 go.mod 中的 exclude 途径吗?(是的,在这种情况下我可能听起来非常愚蠢,但只是为了确认。)

关于 exclude 子句的详细信息:Modules · golang/go Wiki · GitHub

  1. 你们是否计划在未来对依赖项进行版本控制?(也就是说,到目前为止你们有什么想法吗?)
  2. 当前 somepackage 的发布策略是什么?
  3. 子包(例如 aa/cc)之间是否相互依赖?如果是,你能轻松地映射出它们吗(例如花费少于 15 分钟)?
  4. 是否有分布级别的沙箱环境来测试你已经部署的 Docker 发行版?
  5. somepackage 的许可证是否允许在不产生 copyleft 影响的情况下进行分叉和编辑?(例如 MIT,Apache2,…,而不是 GPL… 基本上你拥有这样做的许可,而不会强迫你开源你的代码。)

Rooney_Programmer:

我在 docker 容器中构建和执行项目 5-1. 每个容器使用不同的镜像 5-2. 每个镜像的 GOPATH 中已经包含 ‘somepackage’(它们的 GOPATH 并不相同) 5-3. 每个镜像使用不同版本的 ‘somepackage’

目前,已识别出的问题列表如下:

  1. 在分发之前,somepackage 依赖项的版本控制不明确。
  2. somepackage 是某些经验丰富的 Gopher 所害怕的大型包噩梦。
  3. somepackage 很可能是一个过时的包?!(取决于上面的问题 1)。
  4. 由于项目已经分发,这是一个需要开发运维谨慎处理的问题。
  5. somepackage 是一个关键依赖项(许多项目依赖它)。

Rooney_Programmer:

SomePackage · GitHub

somepackage 是一个模块还是传统的 GOPATH 包?

Rooney_Programmer:

  1. 如果我像这样替换这一行
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 到模块的迁移

更多信息:

  1. replace 子句:

Modules

  1. 模块与 Vendor

Modules

在 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 子包,而排除 aabb 子包。

回到顶部