liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
}