github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/debug/mod.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package debug 6 7 import ( 8 "strings" 9 ) 10 11 // exported from runtime 12 func modinfo() string 13 14 // ReadBuildInfo returns the build information embedded 15 // in the running binary. The information is available only 16 // in binaries built with module support. 17 func ReadBuildInfo() (info *BuildInfo, ok bool) { 18 return readBuildInfo(modinfo()) 19 } 20 21 // BuildInfo represents the build information read from 22 // the running binary. 23 type BuildInfo struct { 24 Path string // The main package path 25 Main Module // The module containing the main package 26 Deps []*Module // Module dependencies 27 } 28 29 // Module represents a module. 30 type Module struct { 31 Path string // module path 32 Version string // module version 33 Sum string // checksum 34 Replace *Module // replaced by this module 35 } 36 37 func readBuildInfo(data string) (*BuildInfo, bool) { 38 if len(data) < 32 { 39 return nil, false 40 } 41 data = data[16 : len(data)-16] 42 43 const ( 44 pathLine = "path\t" 45 modLine = "mod\t" 46 depLine = "dep\t" 47 repLine = "=>\t" 48 ) 49 50 readEntryFirstLine := func(elem []string) (Module, bool) { 51 if len(elem) != 2 && len(elem) != 3 { 52 return Module{}, false 53 } 54 sum := "" 55 if len(elem) == 3 { 56 sum = elem[2] 57 } 58 return Module{ 59 Path: elem[0], 60 Version: elem[1], 61 Sum: sum, 62 }, true 63 } 64 65 var ( 66 info = &BuildInfo{} 67 last *Module 68 line string 69 ok bool 70 ) 71 // Reverse of cmd/go/internal/modload.PackageBuildInfo 72 for len(data) > 0 { 73 i := strings.IndexByte(data, '\n') 74 if i < 0 { 75 break 76 } 77 line, data = data[:i], data[i+1:] 78 switch { 79 case strings.HasPrefix(line, pathLine): 80 elem := line[len(pathLine):] 81 info.Path = elem 82 case strings.HasPrefix(line, modLine): 83 elem := strings.Split(line[len(modLine):], "\t") 84 last = &info.Main 85 *last, ok = readEntryFirstLine(elem) 86 if !ok { 87 return nil, false 88 } 89 case strings.HasPrefix(line, depLine): 90 elem := strings.Split(line[len(depLine):], "\t") 91 last = new(Module) 92 info.Deps = append(info.Deps, last) 93 *last, ok = readEntryFirstLine(elem) 94 if !ok { 95 return nil, false 96 } 97 case strings.HasPrefix(line, repLine): 98 elem := strings.Split(line[len(repLine):], "\t") 99 if len(elem) != 3 { 100 return nil, false 101 } 102 if last == nil { 103 return nil, false 104 } 105 last.Replace = &Module{ 106 Path: elem[0], 107 Version: elem[1], 108 Sum: elem[2], 109 } 110 last = nil 111 } 112 } 113 return info, true 114 }