Golang - How to display modules version from inside of code

Viewed 3021

I'm writing two binaries, and both of them use two libraries (we can call them libA and libB).

Each lib is in a dedicated git repo, with git-tags to declare versions. For example, libA is at v1.0.9 and libB is v0.0.12.

Both binaries have CLI flags, and I would like to add a debug flag to display lib versions like that:

> ./prog -d
Used libraries:
- libA, v1.0.9
- libB, v0.0.12

I don't know how to do that.

The only way I see to set variable from "outside" is to use ldflags (go build -ldflags="-X 'main.Version=v1.0.0'" for example). But this way don't seems scalable, how to add a libC? It also imply to manage tags two times, one time for git, and one time in goreleaser.yml or makefile.

Can you help me to find a solution?

1 Answers

The Go tool includes module and dependency information in the executable binary. You may use runtime/debug.ReadBuildInfo() to acquire it. It returns you a list of dependencies, including module path and version. Each module / dependency is described by a value of type debug.Module which contains these info:

type Module struct {
    Path    string  // module path
    Version string  // module version
    Sum     string  // checksum
    Replace *Module // replaced by this module
}

For example:

package main

import (
    "fmt"
    "log"
    "runtime/debug"

    "github.com/icza/bitio"
)

func main() {
    _ = bitio.NewReader
    bi, ok := debug.ReadBuildInfo()
    if !ok {
        log.Printf("Failed to read build info")
        return
    }

    for _, dep := range bi.Deps {
        fmt.Printf("Dep: %+v\n", dep)
    }
}

This outputs (try it on the Go Playground):

Dep: &{Path:github.com/icza/bitio Version:v1.0.0 Sum:h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8= Replace:<nil>}

Also see related question: How to get Go detailed build logs, with all used packages in GOPATH and "go module" mode?

Related