1
0
mirror of https://github.com/golang/go synced 2024-11-26 08:27:56 -07:00

cmd/go: move module build info formatting into runtime/debug

Previously, modload.PackageBuildInfo returned a string containing
information about modules used to build an executable. This string is
embedded in the binary and can be read with debug.ReadBuildInfo or
'go version -m'.

With this change, debug.BuildInfo now has a MarshalText method that
returns a string in the same format as modload.PackageBuildInfo.

Package.load now calls Package.setBuildInfo, which constructs a
debug.BuildInfo, formats it with MarshalText, then sets
Package.Internal.BuildInfo. This is equivalent to what
modload.PackageBuildInfo did.

modload.PackageBuildInfo is deleted, since it's no longer used.

For #37475

Change-Id: I5875a98cb64737637fec2a450ab2ffa7f1805707
Reviewed-on: https://go-review.googlesource.com/c/go/+/353886
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Jay Conrod 2021-09-30 14:37:30 -07:00
parent 011fd00245
commit 765c9116be
4 changed files with 118 additions and 51 deletions

View File

@ -1,3 +1,4 @@
pkg runtime/debug, method (*BuildInfo) MarshalText() ([]byte, error)
pkg syscall (darwin-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error) pkg syscall (darwin-amd64), func RecvfromInet4(int, []uint8, int, *SockaddrInet4) (int, error)
pkg syscall (darwin-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error) pkg syscall (darwin-amd64), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error

View File

@ -21,6 +21,7 @@ import (
pathpkg "path" pathpkg "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"runtime/debug"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -1921,9 +1922,8 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
} }
p.Internal.Imports = imports p.Internal.Imports = imports
p.collectDeps() p.collectDeps()
if p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
if cfg.ModulesEnabled && p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 { p.setBuildInfo()
p.Internal.BuildInfo = modload.PackageBuildInfo(pkgPath, p.Deps)
} }
// unsafe is a fake package. // unsafe is a fake package.
@ -2195,6 +2195,83 @@ func (p *Package) collectDeps() {
} }
} }
// setBuildInfo gathers build information, formats it as a string to be
// embedded in the binary, then sets p.Internal.BuildInfo to that string.
// setBuildInfo should only be called on a main package with no errors.
//
// This information can be retrieved using debug.ReadBuildInfo.
func (p *Package) setBuildInfo() {
setPkgErrorf := func(format string, args ...interface{}) {
if p.Error == nil {
p.Error = &PackageError{Err: fmt.Errorf(format, args...)}
}
}
var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module
debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module {
dm := &debug.Module{
Path: mi.Path,
Version: mi.Version,
}
if mi.Replace != nil {
dm.Replace = debugModFromModinfo(mi.Replace)
} else {
dm.Sum = modfetch.Sum(module.Version{Path: mi.Path, Version: mi.Version})
}
return dm
}
var main debug.Module
if p.Module != nil {
main = *debugModFromModinfo(p.Module)
}
visited := make(map[*Package]bool)
mdeps := make(map[module.Version]*debug.Module)
var q []*Package
q = append(q, p.Internal.Imports...)
for len(q) > 0 {
p1 := q[0]
q = q[1:]
if visited[p1] {
continue
}
visited[p1] = true
if p1.Module != nil {
m := module.Version{Path: p1.Module.Path, Version: p1.Module.Version}
if p1.Module.Path != main.Path && mdeps[m] == nil {
mdeps[m] = debugModFromModinfo(p1.Module)
}
}
q = append(q, p1.Internal.Imports...)
}
sortedMods := make([]module.Version, 0, len(mdeps))
for mod := range mdeps {
sortedMods = append(sortedMods, mod)
}
module.Sort(sortedMods)
deps := make([]*debug.Module, len(sortedMods))
for i, mod := range sortedMods {
deps[i] = mdeps[mod]
}
pkgPath := p.ImportPath
if p.Internal.CmdlineFiles {
pkgPath = "command-line-arguments"
}
info := &debug.BuildInfo{
Path: pkgPath,
Main: main,
Deps: deps,
}
text, err := info.MarshalText()
if err != nil {
setPkgErrorf("error formatting build info: %v", err)
return
}
p.Internal.BuildInfo = string(text)
}
// SafeArg reports whether arg is a "safe" command-line argument, // SafeArg reports whether arg is a "safe" command-line argument,
// meaning that when it appears in a command-line, it probably // meaning that when it appears in a command-line, it probably
// doesn't have some special meaning other than its own name. // doesn't have some special meaning other than its own name.

View File

@ -5,7 +5,6 @@
package modload package modload
import ( import (
"bytes"
"context" "context"
"encoding/hex" "encoding/hex"
"errors" "errors"
@ -336,53 +335,6 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
return info return info
} }
// PackageBuildInfo returns a string containing module version information
// for modules providing packages named by path and deps. path and deps must
// name packages that were resolved successfully with LoadPackages.
func PackageBuildInfo(path string, deps []string) string {
if !Enabled() {
return ""
}
target, _ := findModule(loaded, path)
mdeps := make(map[module.Version]bool)
for _, dep := range deps {
if m, ok := findModule(loaded, dep); ok {
mdeps[m] = true
}
}
var mods []module.Version
delete(mdeps, target)
for mod := range mdeps {
mods = append(mods, mod)
}
module.Sort(mods)
var buf bytes.Buffer
fmt.Fprintf(&buf, "path\t%s\n", path)
writeEntry := func(token string, m module.Version) {
mv := m.Version
if mv == "" {
mv = "(devel)"
}
fmt.Fprintf(&buf, "%s\t%s\t%s", token, m.Path, mv)
if r, _ := Replacement(m); r.Path == "" {
fmt.Fprintf(&buf, "\t%s\n", modfetch.Sum(m))
} else {
fmt.Fprintf(&buf, "\n=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
}
}
if target.Path != "" {
writeEntry("mod", target)
}
for _, mod := range mods {
writeEntry("dep", mod)
}
return buf.String()
}
// findModule searches for the module that contains the package at path. // findModule searches for the module that contains the package at path.
// If the package was loaded, its containing module and true are returned. // If the package was loaded, its containing module and true are returned.
// Otherwise, module.Version{} and false are returned. // Otherwise, module.Version{} and false are returned.

View File

@ -5,6 +5,8 @@
package debug package debug
import ( import (
"bytes"
"fmt"
"strings" "strings"
) )
@ -34,6 +36,41 @@ type Module struct {
Replace *Module // replaced by this module Replace *Module // replaced by this module
} }
func (bi *BuildInfo) MarshalText() ([]byte, error) {
buf := &bytes.Buffer{}
if bi.Path != "" {
fmt.Fprintf(buf, "path\t%s\n", bi.Path)
}
var formatMod func(string, Module)
formatMod = func(word string, m Module) {
buf.WriteString(word)
buf.WriteByte('\t')
buf.WriteString(m.Path)
mv := m.Version
if mv == "" {
mv = "(devel)"
}
buf.WriteByte('\t')
buf.WriteString(mv)
if m.Replace == nil {
buf.WriteByte('\t')
buf.WriteString(m.Sum)
} else {
buf.WriteByte('\n')
formatMod("=>", *m.Replace)
}
buf.WriteByte('\n')
}
if bi.Main.Path != "" {
formatMod("mod", bi.Main)
}
for _, dep := range bi.Deps {
formatMod("dep", *dep)
}
return buf.Bytes(), nil
}
func readBuildInfo(data string) (*BuildInfo, bool) { func readBuildInfo(data string) (*BuildInfo, bool) {
if len(data) < 32 { if len(data) < 32 {
return nil, false return nil, false