Search code examples
gocode-generationgo-modules

How to get the path to a Go module dependency?


I have two Go modules, let's name them example.com/a and example.com/b.

Let this be example.com/a's go.mod:

module example.com/a

go 1.12

require (
  example.com/b v0.4.2
)

In example.com/b's root directory, there is a file named data.yaml. example.com/a needs to autogenerate some code as part of its build process. This autogeneration needs to read data.yaml.

How can I in the directory of example.com/a query for the path of example.com/b to read that file? I know that after downloading, the module will be somewhere in (go env GOPATH)/pkg/mod but I don't know how the path will be constructed from there as it contains some ! characters that are not part of the import path. I hoped that there is some subcommand of go mod or go list that will output the path, but I haven't found it in the documentation.

I have thought about including data.yaml in Go code via go-bindata (yes I'm aware of //go:embed but I don't want to require Go 1.16 for now) but then I would only have access at run-time when I need it at compile-time.


Solution

  • You can use go list with the -m flag and the -f flag like so:

    go list -m -f '{{.Dir}}' example.com/b
    

    The -m flag:

    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)

    The -f flag:

    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
    }
    

    [the above quote was altered for context]

    (reference)