mirror of
https://github.com/golang/go
synced 2024-11-12 07:40:23 -07:00
runtime/debug: add API to read module info in binary
When module is enabled, the go tool embeds build information related to the module in the binary including the dependencies and the replace information (See src/cmd/go/internal/modload.PackageBuildInfo). The newly introduced ReadBuildInfo reads the information and makes it accessible programmatically. Update #26404 Change-Id: Ide37022d609b4a8fb6b5ce02afabb73f04fbb532 Reviewed-on: https://go-review.googlesource.com/c/144220 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
978cfa8e46
commit
45e9c5538b
40
src/cmd/go/testdata/script/mod_modinfo.txt
vendored
Normal file
40
src/cmd/go/testdata/script/mod_modinfo.txt
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
# Test to ensure runtime/debug.ReadBuildInfo parses
|
||||
# the modinfo embedded in a binary by the go tool
|
||||
# when module is enabled.
|
||||
env GO111MODULE=on
|
||||
|
||||
cd x
|
||||
go mod edit -require=rsc.io/quote@v1.5.2
|
||||
go mod edit -replace=rsc.io/quote@v1.5.2=rsc.io/quote@v1.0.0
|
||||
|
||||
go run main.go
|
||||
|
||||
stderr 'Hello, world.'
|
||||
stderr 'mod\s+x\s+\(devel\)'
|
||||
stderr 'dep\s+rsc.io/quote\s+v1.5.2\s+'
|
||||
stderr '=>\s+rsc.io/quote\s+v1.0.0\s+h1:'
|
||||
|
||||
-- x/go.mod --
|
||||
module x
|
||||
|
||||
-- x/main.go --
|
||||
package main
|
||||
|
||||
import "runtime/debug"
|
||||
import "rsc.io/quote"
|
||||
|
||||
func main() {
|
||||
println(quote.Hello())
|
||||
|
||||
m, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
panic("failed debug.ReadBuildInfo")
|
||||
}
|
||||
println("mod", m.Main.Path, m.Main.Version)
|
||||
for _, d := range m.Deps {
|
||||
println("dep", d.Path, d.Version, d.Sum)
|
||||
if r := d.Replace; r != nil {
|
||||
println("=>", r.Path, r.Version, r.Sum)
|
||||
}
|
||||
}
|
||||
}
|
105
src/runtime/debug/mod.go
Normal file
105
src/runtime/debug/mod.go
Normal file
@ -0,0 +1,105 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// set using cmd/go/internal/modload.ModInfoProg
|
||||
var 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 main module information
|
||||
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"
|
||||
)
|
||||
|
||||
info := &BuildInfo{}
|
||||
|
||||
var line string
|
||||
// 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")
|
||||
if len(elem) != 3 {
|
||||
return nil, false
|
||||
}
|
||||
info.Main = Module{
|
||||
Path: elem[0],
|
||||
Version: elem[1],
|
||||
Sum: elem[2],
|
||||
}
|
||||
case strings.HasPrefix(line, depLine):
|
||||
elem := strings.Split(line[len(depLine):], "\t")
|
||||
if len(elem) != 2 && len(elem) != 3 {
|
||||
return nil, false
|
||||
}
|
||||
sum := ""
|
||||
if len(elem) == 3 {
|
||||
sum = elem[2]
|
||||
}
|
||||
info.Deps = append(info.Deps, &Module{
|
||||
Path: elem[0],
|
||||
Version: elem[1],
|
||||
Sum: sum,
|
||||
})
|
||||
case strings.HasPrefix(line, repLine):
|
||||
elem := strings.Split(line[len(repLine):], "\t")
|
||||
if len(elem) != 3 {
|
||||
return nil, false
|
||||
}
|
||||
last := len(info.Deps) - 1
|
||||
if last < 0 {
|
||||
return nil, false
|
||||
}
|
||||
info.Deps[last].Replace = &Module{
|
||||
Path: elem[0],
|
||||
Version: elem[1],
|
||||
Sum: elem[2],
|
||||
}
|
||||
}
|
||||
}
|
||||
return info, true
|
||||
}
|
Loading…
Reference in New Issue
Block a user