如何获取 Go 模块依赖的路径?
How to get the path to a Go module dependency?
我有两个 Go 模块,我们将它们命名为 example.com/a
和 example.com/b
。
设为 example.com/a
的 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-bindata
在 Go 代码中包含 data.yaml
(是的,我知道 //go:embed
但我现在不想要求 Go 1.16)但是那么我只能在 运行 时访问,当我在编译时需要它时。
您可以将 go list
与 -m
标志和 -f
标志一起使用,如下所示:
go list -m -f '{{.Dir}}' example.com/b
-m
标志:
causes go list to list modules instead of packages. In this mode, the
arguments to go list may be modules, module patterns (containing the
... wildcard), version queries, or the special pattern all, which
matches all modules in the build list. If no arguments are specified,
the main module is listed.
-f
标志:
specifies an alternate format for the output, using the syntax of
package template. The struct being passed to the template, when using
the -m
flag, is:
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)
}
我有两个 Go 模块,我们将它们命名为 example.com/a
和 example.com/b
。
设为 example.com/a
的 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-bindata
在 Go 代码中包含 data.yaml
(是的,我知道 //go:embed
但我现在不想要求 Go 1.16)但是那么我只能在 运行 时访问,当我在编译时需要它时。
您可以将 go list
与 -m
标志和 -f
标志一起使用,如下所示:
go list -m -f '{{.Dir}}' example.com/b
-m
标志:
causes go list to list modules instead of packages. In this mode, the arguments to go list may be modules, module patterns (containing the ... wildcard), version queries, or the special pattern all, which matches all modules in the build list. If no arguments are specified, the main module is listed.
-f
标志:
specifies an alternate format for the output, using the syntax of package template. The struct being passed to the template, when using the
-m
flag, is: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)
}