...

Source file src/runtime/debug/mod.go

     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 main module information
    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		info := &BuildInfo{}
    51	
    52		var line string
    53		// Reverse of cmd/go/internal/modload.PackageBuildInfo
    54		for len(data) > 0 {
    55			i := strings.IndexByte(data, '\n')
    56			if i < 0 {
    57				break
    58			}
    59			line, data = data[:i], data[i+1:]
    60			switch {
    61			case strings.HasPrefix(line, pathLine):
    62				elem := line[len(pathLine):]
    63				info.Path = elem
    64			case strings.HasPrefix(line, modLine):
    65				elem := strings.Split(line[len(modLine):], "\t")
    66				if len(elem) != 3 {
    67					return nil, false
    68				}
    69				info.Main = Module{
    70					Path:    elem[0],
    71					Version: elem[1],
    72					Sum:     elem[2],
    73				}
    74			case strings.HasPrefix(line, depLine):
    75				elem := strings.Split(line[len(depLine):], "\t")
    76				if len(elem) != 2 && len(elem) != 3 {
    77					return nil, false
    78				}
    79				sum := ""
    80				if len(elem) == 3 {
    81					sum = elem[2]
    82				}
    83				info.Deps = append(info.Deps, &Module{
    84					Path:    elem[0],
    85					Version: elem[1],
    86					Sum:     sum,
    87				})
    88			case strings.HasPrefix(line, repLine):
    89				elem := strings.Split(line[len(repLine):], "\t")
    90				if len(elem) != 3 {
    91					return nil, false
    92				}
    93				last := len(info.Deps) - 1
    94				if last < 0 {
    95					return nil, false
    96				}
    97				info.Deps[last].Replace = &Module{
    98					Path:    elem[0],
    99					Version: elem[1],
   100					Sum:     elem[2],
   101				}
   102			}
   103		}
   104		return info, true
   105	}
   106	

View as plain text