问题描述
我有两个 Go 模块,让我们将它们命名为 example.com/a
和 example.com/b
。
让它成为example.com/a
的{{1}}:
go.mod
在module example.com/a
go 1.12
require (
example.com/b v0.4.2
)
的根目录下,有一个名为example.com/b
的文件。 data.yaml
需要自动生成一些代码作为其构建过程的一部分。此自动生成需要读取 example.com/a
。
如何在data.yaml
的目录中查询example.com/a
的路径来读取那个文件?我知道下载后,该模块将位于 example.com/b
中的某处,但我不知道如何从那里构建路径,因为它包含一些 (go env GOPATH)/pkg/mod
字符不是导入路径的一部分。我希望有一些 !
或 go mod
的子命令可以输出路径,但我没有在文档中找到它。
我曾考虑通过 go list
在 Go 代码中包含 data.yaml
(是的,我知道 go-bindata
但我现在不想要求 Go 1.16)但后来我只有在编译时需要时才能在运行时访问。
解决方法
您可以将 go list
与 -m
标志和 -f
标志一起使用,如下所示:
go list -m -f '{{.Dir}}' example.com/b
-m
标志:
导致 go list 列出模块而不是包。在这种模式下, go list 的参数可能是模块、模块模式(包含 ...通配符)、版本查询或特殊模式 all,其中 匹配构建列表中的所有模块。如果没有指定参数, 列出了主模块。
-f
标志:
指定输出的替代格式,使用的语法为
包模板。传递给模板的结构,使用时
-m
标志是:
type Module struct {
Path string // module path
Version string // module version
Versions []string // available module versions (with -versions)
Replace *Module // replaced by this module
Time *time.Time // time version was created
Update *Module // available update,if any (with -u)
Main bool // is this the main module?
Indirect bool // is this module only an indirect dependency of main module?
Dir string // directory holding files for this module,if any
GoMod string // path to go.mod file for this module,if any
GoVersion string // go version used in module
Error *ModuleError // error loading module }
type ModuleError struct {
Err string // the error itself
}
[以上引用因上下文而改变]
,你可以这样算出模块路径:
package main
import (
"fmt"
"os"
"path"
"golang.org/x/mod/module"
)
func GetModulePath(name,version string) (string,error) {
// first we need GOMODCACHE
cache,ok := os.LookupEnv("GOMODCACHE")
if !ok {
cache = path.Join(os.Getenv("GOPATH"),"pkg","mod")
}
// then we need to escape path
escapedPath,err := module.EscapePath(name)
if err != nil {
return "",err
}
// version also
escapedVersion,err := module.EscapeVersion(version)
if err != nil {
return "",err
}
return path.Join(cache,escapedPath+"@"+escapedVersion),nil
}
func main() {
var path,err = GetModulePath("github.com/jakubDoka/mlok","v0.4.7")
if err != nil {
panic(err)
}
if _,err := os.Stat(path); os.IsNotExist(err) {
fmt.Println("you don't have this module/version installed")
}
fmt.Println("module found in",path)
}