С помощью списка go, как перечислить только модули Go, используемые в двоичном файле?

Я хочу перечислить модули (и их версии), которые скомпилированы в окончательном исполняемом файле (а не другие зависимости).

Я могу сделать это с помощью:

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

Но как это сделать с помощью списка go (с удобным выводом в формате JSON)?

Я пробовал это:

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

Но в нем перечислены многие транзитивные зависимости, которые используются, например, только в тестовых наборах. Я не понимаю, как мне отфильтровать эти зависимости.

Вот пример проекта, чтобы увидеть проблему (доступен на игровой площадке Go):

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/[email protected]
golang.org/x/[email protected]

person dolmen    schedule 15.10.2020    source источник
comment
Что вы имеете в виду под зависимостями, а не под другими?   -  person Flimzy    schedule 15.10.2020
comment
Но вы, вероятно, хотите, чтобы поле Module пакета было задокументированным.   -  person Flimzy    schedule 15.10.2020
comment
Как указано в отмеченном дубликате, шаблон {{if not .Indirect}}{{.}}{{end}} включает только прямые зависимости.   -  person icza    schedule 15.10.2020
comment
@icza .Indirect не исключает модули, которые используются в тестах. В моем примере github.com/google/[email protected] указан в go list, но не используется в двоичном файле.   -  person dolmen    schedule 16.10.2020
comment
@dolmen Это соответствует вашим потребностям? go list -deps -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}'   -  person icza    schedule 16.10.2020
comment
@icza Нет. Он все еще перечисляет слишком много модулей. Но это помогло мне найти решение моей проблемы. Но я не могу опубликовать его здесь в качестве ответа, потому что мой вопрос неправильно помечен как дубликат.   -  person dolmen    schedule 16.10.2020


Ответы (1)


Вот ответ:

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

Примечание: go list -deps создает по одной строке для каждого пакета. Таким образом, модули, из которых импортировано несколько пакетов, указываются несколько раз. sort -u сортирует и удаляет дубликаты.

Его можно сравнить с:

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

Вот версия с более подробной информацией, в которой перечислены все пакеты, на которые ссылается каждый модуль (также с использованием 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
person dolmen    schedule 16.10.2020