如何获取 Go 模块依赖的路径?

How to get the path to a Go module dependency?

我有两个 Go 模块,我们将它们命名为 example.com/aexample.com/b

设为 example.com/ago.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 modgo 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.

(reference)

-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
}

[以上引用因上下文而改变]

(reference)

你可以这样算模块路径:

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)
}