Something went wrong. Try again.
Ridiculously simple Go build info 🛠️
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131// Package build provides a simple mechanism for getting at debug.BuildInfo in a more ergonomic way.package build // import "go.followtheprocess.codes/build"
import ( "fmt" "runtime/debug" "strconv" "strings" "text/tabwriter" "time")
// TableWriter config, used for showing build info.const ( minWidth = 1 // Min cell width tabWidth = 8 // Tab width in spaces padding = 2 // Padding padChar = ' ' // Char to pad with flags = 0 // Config flags)
// BuildInfo contains the build information of a Go binary.//
type BuildInfo struct { Main Module `json:"main,omitzero"` // The main module Time time.Time `json:"time,omitzero"` // The modification time associated with Commit Go string `json:"go,omitempty"` // The Go toolchain version used to build the binary Path string `json:"path,omitempty"` // The package path of the main package OS string `json:"os,omitempty"` // The value of $GOOS Arch string `json:"arch,omitempty"` // The value of $GOARCH VCS string `json:"vcs,omitempty"` // The version control system for the source tree where the build ran Commit string `json:"commit,omitempty"` // The SHA1 of the current commit when the build ran Version string `json:"version,omitempty"` // The module version Dirty bool `json:"dirty,omitempty"` // Whether the source tree had local modifications at the time of the build}
// String implements [fmt.Stringer] for [BuildInfo].func (b BuildInfo) String() string { s := &strings.Builder{} tab := tabwriter.NewWriter(s, minWidth, tabWidth, padding, padChar, flags) fmt.Fprintf(tab, "go:\t%s\n", b.Go) fmt.Fprintf(tab, "path:\t%s\n", b.Path) fmt.Fprintf(tab, "os:\t%s\n", b.OS) fmt.Fprintf(tab, "arch:\t%s\n", b.Arch) fmt.Fprintf(tab, "vcs:\t%s\n", b.VCS) fmt.Fprintf(tab, "version:\t%s\n", b.Version) fmt.Fprintf(tab, "commit:\t%s\n", b.Commit) fmt.Fprintf(tab, "dirty:\t%v\n", b.Dirty) fmt.Fprintf(tab, "time:\t%s\n", b.Time.Format(time.RFC3339)) fmt.Fprintf(tab, "main:\t%s\n", writeModule("mod", b.Main))
tab.Flush()
return s.String()}
// A Module describes a single module included in a build.type Module struct { Path string `json:"path,omitempty"` // module path Version string `json:"version,omitempty"` // module version Sum string `json:"sum,omitempty"` // checksum}
// Info returns the Go build info for the current binary.func Info() (info BuildInfo, ok bool) { dbg, ok := debug.ReadBuildInfo() if !ok { return BuildInfo{}, false }
return parseBuildInfo(dbg), true}
func parseBuildInfo(dbg *debug.BuildInfo) BuildInfo { info := BuildInfo{ Main: Module{ Path: dbg.Main.Path, Version: dbg.Main.Version, Sum: dbg.Main.Sum, }, Go: dbg.GoVersion, Path: dbg.Path, Version: dbg.Main.Version, }
for _, setting := range dbg.Settings { switch setting.Key { case "GOOS": info.OS = setting.Value case "GOARCH": info.Arch = setting.Value case "vcs": info.VCS = setting.Value case "vcs.revision": info.Commit = setting.Value case "vcs.time": t, err := time.Parse(time.RFC3339, setting.Value) if err != nil { // Skip this setting continue }
info.Time = t case "vcs.modified": modified, err := strconv.ParseBool(setting.Value) if err != nil { // Skip this setting continue }
info.Dirty = modified } }
return info}
func writeModule(word string, m Module) string { buf := &strings.Builder{} buf.WriteString(word) buf.WriteByte('\t') buf.WriteString(m.Path) buf.WriteByte('\t') buf.WriteString(m.Version) buf.WriteByte('\t') buf.WriteString(m.Sum)
return buf.String()}