5

I want to list the modules (and their versions) that are compiled in the final executable (and not other dependencies).

I can do that with:

$ go build -o a.out
$ go version -m a.out

But how can I do that with go list (which has a convenient JSON output)?

I tried this:

$ go list -m -f '{{define "M"}}{{.Path}}@{{.Version}}{{end}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}' all

But it lists many transitive dependencies which are only used in test suites for example. I don't see how I could filter out those dependencies.

Here is a sample project to see the problem (available on The Go Playground):

main.go:

package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

main_test.go:

package main

import (
    "github.com/google/go-cmp/cmp"
    "testing"
)

func TestHelloWorld(t *testing.T) {
    if !cmp.Equal(1, 1) {
        t.Fatal("FAIL")
    }
}

go.mod:

module play.ground

go 1.15

require github.com/google/go-cmp v0.5.2
$ go build -o hello ; go version -m hello
hello: go1.15
    path    play.ground
    mod play.ground (devel)
$ go list -m -f '{{define "M"}}{{.Path}}@{{.Version}}{{end}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}' all
github.com/google/go-cmp@v0.5.2
golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543
blackgreen
  • 34,072
  • 23
  • 111
  • 129
dolmen
  • 8,126
  • 5
  • 40
  • 42
  • What do you mean by "and not other dependencies"? – Jonathan Hall Oct 15 '20 at 12:27
  • But you probably want the `Module` field of the package as [documented](https://golang.org/pkg/cmd/go/internal/list/#pkg-variables). – Jonathan Hall Oct 15 '20 at 12:35
  • As detailed in the marked duplicate, the template `{{if not .Indirect}}{{.}}{{end}}` only includes direct dependencies. – icza Oct 15 '20 at 12:42
  • @icza `.Indirect` do not excludes modules which are used in tests. In my example, `github.com/google/go-cmp@v0.5.2` is listed in `go list` but is not used in the binary. – dolmen Oct 16 '20 at 12:51
  • @dolmen Does this suit your needs? `go list -deps -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}'` – icza Oct 16 '20 at 13:19
  • @icza No. It still list too many modules. But this helped me to find the solution to my problem. But I can't post it here as an answer because my question is incorrectly marked as a duplicate. – dolmen Oct 16 '20 at 13:34

1 Answers1

10

Here is the answer:

go list -deps -f '{{define "M"}}{{.Path}}@{{.Version}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}' | sort -u

Note: go list -deps produces one row for each package. So modules from which multiple packages are imported are listed mutiple times. sort -u sorts and removes duplicates.

It can be compared with:

go version -m hello | perl -ne 's/^\tdep\t([^\t]*)\t([^\t]*).*$/$1\@$2/ && print' | sort

Here is a version with more details that lists each package referenced from each module (also using jq:

go list -deps -f '{{define "mod"}}{{.Path}}@{{.Version}}{{end}}{{if .Module}}{{if not .Module.Main}}{{if .Module.Replace}}{{template "mod" .Module.Replace}}{{else}}{{template "mod" .Module}}{{end}}{{"\t"}}{{.ImportPath}}{{end}}{{end}}' | sort
go list -deps -json | jq -r 'select(.Module and (.Module.Main | not)) | .Module.Path + "@" + .Module.Version + "\t" + .ImportPath' | sort
dolmen
  • 8,126
  • 5
  • 40
  • 42