英文:
Golang. Replace module path for package that are not real go packages
问题
这是要翻译的内容:
有这个包 https://github.com/open-telemetry/opentelemetry-proto
它只包含protobuf定义。要生成golang代码,必须输入以下命令:
make gen-go
然后go build失败,并显示以下消息:
build opentel: cannot load github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1: module github.com/open-telemetry/opentelemetry-proto@latest found (v0.11.0), but does not contain package github.com/open-telemetry/opentelemetry-proto/gen/go/common/v
我尝试在go.mod文件中将一个路径替换为另一个路径,但显然我不太擅长。我该如何使其工作?
我已将这些生成的文件复制到
$GOPATH/src/opentelemetry-proto/gen/go
在我的主包中的import语句中应该放什么?
英文:
There is this package https://github.com/open-telemetry/opentelemetry-proto
which contains protobuf definitions only. To generate golang code one must type:
make gen-go
and go build fails with following message:
build opentel: cannot load github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1: module github.com/open-telemetry/opentelemetry-proto@latest found (v0.11.0), but does not contain package github.com/open-telemetry/opentelemetry-proto/gen/go/common/v
I've tried to replace one path with another in go.mod file but apparently I'm not too good at it. How can I make it work?
I've copied those generated files to
$GOPATH/src/opentelemetry-proto/gen/go
what should I put in import statement inside my main package?
答案1
得分: 5
Go源代码生成方式存在一些挑战。我猜测仓库的作者们希望在不同语言和使用GOPATH
和GO MODULES
的情况下保持一致性,所以对他们和我们来说都有些复杂。
下面是一个解决方案:
假设你在/path/to/somedir
目录下,该目录包含了opentelemetry-proto
和my-module
的克隆版本,目录结构如下:
.
├── my-module
└── opentelemetry-proto
-
执行
make gen-go
,这将在./opentelemetry-proto
目录下创建gen
文件夹。 -
在
./opentelemetry-proto/gen/go/github.com/open-telemetry/opentelemetry-proto
目录下执行go mod init github.com/open-telemetry/opentelemetry-proto
:
.
├── gen
└── go.mod
- 在
my-module
目录下执行go mod init my-module
,然后修改go.mod
文件如下:
module my-module
go 1.17
require (
github.com/open-telemetry/opentelemetry-proto v0.11.0
)
replace (
github.com/open-telemetry/opentelemetry-proto => ../opentelemetry-proto/gen/go/github.com/open-telemetry/opentelemetry-proto
注意:由于他们没有使用Go Modules,所以需要使用
GOPATH
路径到达包的位置。如果我们使用GOPATH
,我们可以将GOPATH=${GOPATH}:${PROTO_GEN_GO_DIR}/github.com/open-telemetry/opentelemetry-proto
。
然后,例如:
main.go
:
package main
import (
v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1"
)
func main() {
// 例如
_ = v1.ExportMetricsServiceRequest{}
}
解释:
make gen-go
不会创建一个Module,但我们可以手动创建一个。
Module的路径是从gen/go
目录下的路径推断出来的,即github.com/open-telemetry/opentelemetry-proto
。
然后,我们可以在我们的项目中使用replace
指令来提供一个本地路径。该路径是克隆版本的路径,然后回退到我们新创建的go.mod
文件所在的位置。
导入路径是从Module开始的路径(即那个非常复杂的replace路径),指向我们感兴趣的包。
注意:通常,protobuf的导入路径是
pb
,但我使用了v1
。
我的建议是:
我认为生成的代码的Module应该与其仓库匹配。如果opentelemetry-proto
是我的仓库,我会将生成的源代码放在仓库根目录下,而不是gen/go
目录下。
这样做会简化一切,例如:
github.com/open-telemetry/opentelemetry-proto => ../opentelemetry-proto
以及:
import (
v1 "github.com/open-telemetry/opentelemetry-proto/collector/metrics/v1"
)
英文:
There are a couple of challenges with the way the Go sources are generated. I assume that the repo authors are aiming for consistency across languages and for GOPATH
and GO MODULES
use-cases with Go.... so, yes, gnarly for them and us.
Here's a (!?) solution:
Assuming you're in /path/to/somedir
and it contains a clone of the opentelemetry-proto
and ``my-module` at the same level, i.e.:
.
├── my-module
└── opentelemetry-proto
-
make gen-go
as before. This should create./opentelemetry-proto/gen
-
In
./opentelemetry-proto/gen/go/github.com/open-telemetry/opentelemetry-proto
gogo mod init github.com/open-telemetry/opentelemetry-proto
:
.
├── gen
└── go.mod
- From within
my-module
,go mod init my-module
and then:
go.mod
:
module my-module
go 1.17
require (
github.com/open-telemetry/opentelemetry-proto v0.11.0
)
replace (
github.com/open-telemetry/opentelemetry-proto => ../opentelemetry-proto/gen/go/github.com/open-telemetry/opentelemetry-proto
> NOTE With GOPATH
paths down to packages are required (they're not using Go Modules) and so, if we were using GOPATH
, we could GOPATH=${GOPATH}:${PROTO_GEN_GO_DIR}/github.com/open-telemetry/opentelemetry-proto
And then, e.g.
main.go
:
package main
import (
v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1"
)
func main() {
// E.g.
_ = v1.ExportMetricsServiceRequest{}
}
Explanation:
make gen-go
does not create a Module but we can create one.
The Module is implicit from the path under gen/go
i.e. github.com/open-telemetry/opentelemetry-proto
Then, from our project, we can replace
to provide a local path to it. The path is the path to the clone, then back down to our newly-created go.mod
.
The import path is the path from the Module (i.e. that excessively convoluted replace path) to whichever package we're interested in.
> NOTE Commonly protobuf imports are pb but I've used v1
.
What I would do:
I think the Module of generated code should match its repo. If opentelemetry-proto
were mine, I'd generate the sources into the repo root without gen/go
As this would -- IMO -- simplify everything to:
github.com/open-telemetry/opentelemetry-proto => ../opentelemetry-proto
And:
import (
v1 "github.com/open-telemetry/opentelemetry-proto/collector/metrics/v1"
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论