+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 RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
pathpkg "path"
"path/filepath"
"runtime"
+ "runtime/debug"
"sort"
"strconv"
"strings"
}
p.Internal.Imports = imports
p.collectDeps()
-
- if cfg.ModulesEnabled && p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
- p.Internal.BuildInfo = modload.PackageBuildInfo(pkgPath, p.Deps)
+ if p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
+ p.setBuildInfo()
}
// unsafe is a fake package.
}
}
+// 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,
// meaning that when it appears in a command-line, it probably
// doesn't have some special meaning other than its own name.
package modload
import (
- "bytes"
"context"
"encoding/hex"
"errors"
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.
// If the package was loaded, its containing module and true are returned.
// Otherwise, module.Version{} and false are returned.
package debug
import (
+ "bytes"
+ "fmt"
"strings"
)
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) {
if len(data) < 32 {
return nil, false