116 lines
2.5 KiB
Go
116 lines
2.5 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package debug
|
|
|
|
import (
|
|
"strings"
|
|
_ "unsafe" // for go:linkname
|
|
)
|
|
|
|
// exported from runtime
|
|
func modinfo() string
|
|
|
|
// ReadBuildInfo returns the build information embedded
|
|
// in the running binary. The information is available only
|
|
// in binaries built with module support.
|
|
func ReadBuildInfo() (info *BuildInfo, ok bool) {
|
|
return readBuildInfo(modinfo())
|
|
}
|
|
|
|
// BuildInfo represents the build information read from
|
|
// the running binary.
|
|
type BuildInfo struct {
|
|
Path string // The main package path
|
|
Main Module // The module containing the main package
|
|
Deps []*Module // Module dependencies
|
|
}
|
|
|
|
// Module represents a module.
|
|
type Module struct {
|
|
Path string // module path
|
|
Version string // module version
|
|
Sum string // checksum
|
|
Replace *Module // replaced by this module
|
|
}
|
|
|
|
func readBuildInfo(data string) (*BuildInfo, bool) {
|
|
if len(data) < 32 {
|
|
return nil, false
|
|
}
|
|
data = data[16 : len(data)-16]
|
|
|
|
const (
|
|
pathLine = "path\t"
|
|
modLine = "mod\t"
|
|
depLine = "dep\t"
|
|
repLine = "=>\t"
|
|
)
|
|
|
|
readEntryFirstLine := func(elem []string) (Module, bool) {
|
|
if len(elem) != 2 && len(elem) != 3 {
|
|
return Module{}, false
|
|
}
|
|
sum := ""
|
|
if len(elem) == 3 {
|
|
sum = elem[2]
|
|
}
|
|
return Module{
|
|
Path: elem[0],
|
|
Version: elem[1],
|
|
Sum: sum,
|
|
}, true
|
|
}
|
|
|
|
var (
|
|
info = &BuildInfo{}
|
|
last *Module
|
|
line string
|
|
ok bool
|
|
)
|
|
// Reverse of cmd/go/internal/modload.PackageBuildInfo
|
|
for len(data) > 0 {
|
|
i := strings.IndexByte(data, '\n')
|
|
if i < 0 {
|
|
break
|
|
}
|
|
line, data = data[:i], data[i+1:]
|
|
switch {
|
|
case strings.HasPrefix(line, pathLine):
|
|
elem := line[len(pathLine):]
|
|
info.Path = elem
|
|
case strings.HasPrefix(line, modLine):
|
|
elem := strings.Split(line[len(modLine):], "\t")
|
|
last = &info.Main
|
|
*last, ok = readEntryFirstLine(elem)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
case strings.HasPrefix(line, depLine):
|
|
elem := strings.Split(line[len(depLine):], "\t")
|
|
last = new(Module)
|
|
info.Deps = append(info.Deps, last)
|
|
*last, ok = readEntryFirstLine(elem)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
case strings.HasPrefix(line, repLine):
|
|
elem := strings.Split(line[len(repLine):], "\t")
|
|
if len(elem) != 3 {
|
|
return nil, false
|
|
}
|
|
if last == nil {
|
|
return nil, false
|
|
}
|
|
last.Replace = &Module{
|
|
Path: elem[0],
|
|
Version: elem[1],
|
|
Sum: elem[2],
|
|
}
|
|
last = nil
|
|
}
|
|
}
|
|
return info, true
|
|
}
|