github.com/jimmyx0x/go-ethereum@v1.10.28/internal/version/version.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package version implements reading of build version information. 18 package version 19 20 import ( 21 "fmt" 22 "runtime" 23 "runtime/debug" 24 "strings" 25 26 "github.com/ethereum/go-ethereum/params" 27 ) 28 29 const ourPath = "github.com/ethereum/go-ethereum" // Path to our module 30 31 // These variables are set at build-time by the linker when the build is 32 // done by build/ci.go. 33 var gitCommit, gitDate string 34 35 // VCSInfo represents the git repository state. 36 type VCSInfo struct { 37 Commit string // head commit hash 38 Date string // commit time in YYYYMMDD format 39 Dirty bool 40 } 41 42 // VCS returns version control information of the current executable. 43 func VCS() (VCSInfo, bool) { 44 if gitCommit != "" { 45 // Use information set by the build script if present. 46 return VCSInfo{Commit: gitCommit, Date: gitDate}, true 47 } 48 if buildInfo, ok := debug.ReadBuildInfo(); ok { 49 if buildInfo.Main.Path == ourPath { 50 return buildInfoVCS(buildInfo) 51 } 52 } 53 return VCSInfo{}, false 54 } 55 56 // ClientName creates a software name/version identifier according to common 57 // conventions in the Ethereum p2p network. 58 func ClientName(clientIdentifier string) string { 59 git, _ := VCS() 60 return fmt.Sprintf("%s/v%v/%v-%v/%v", 61 strings.Title(clientIdentifier), 62 params.VersionWithCommit(git.Commit, git.Date), 63 runtime.GOOS, runtime.GOARCH, 64 runtime.Version(), 65 ) 66 } 67 68 // runtimeInfo returns build and platform information about the current binary. 69 // 70 // If the package that is currently executing is a prefixed by our go-ethereum 71 // module path, it will print out commit and date VCS information. Otherwise, 72 // it will assume it's imported by a third-party and will return the imported 73 // version and whether it was replaced by another module. 74 func Info() (version, vcs string) { 75 version = params.VersionWithMeta 76 buildInfo, ok := debug.ReadBuildInfo() 77 if !ok { 78 return version, "" 79 } 80 version = versionInfo(buildInfo) 81 if status, ok := VCS(); ok { 82 modified := "" 83 if status.Dirty { 84 modified = " (dirty)" 85 } 86 commit := status.Commit 87 if len(commit) > 8 { 88 commit = commit[:8] 89 } 90 vcs = commit + "-" + status.Date + modified 91 } 92 return version, vcs 93 } 94 95 // versionInfo returns version information for the currently executing 96 // implementation. 97 // 98 // Depending on how the code is instantiated, it returns different amounts of 99 // information. If it is unable to determine which module is related to our 100 // package it falls back to the hardcoded values in the params package. 101 func versionInfo(info *debug.BuildInfo) string { 102 // If the main package is from our repo, prefix version with "geth". 103 if strings.HasPrefix(info.Path, ourPath) { 104 return fmt.Sprintf("geth %s", info.Main.Version) 105 } 106 // Not our main package, so explicitly print out the module path and 107 // version. 108 var version string 109 if info.Main.Path != "" && info.Main.Version != "" { 110 // These can be empty when invoked with "go run". 111 version = fmt.Sprintf("%s@%s ", info.Main.Path, info.Main.Version) 112 } 113 mod := findModule(info, ourPath) 114 if mod == nil { 115 // If our module path wasn't imported, it's unclear which 116 // version of our code they are running. Fallback to hardcoded 117 // version. 118 return version + fmt.Sprintf("geth %s", params.VersionWithMeta) 119 } 120 // Our package is a dependency for the main module. Return path and 121 // version data for both. 122 version += fmt.Sprintf("%s@%s", mod.Path, mod.Version) 123 if mod.Replace != nil { 124 // If our package was replaced by something else, also note that. 125 version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) 126 } 127 return version 128 } 129 130 // findModule returns the module at path. 131 func findModule(info *debug.BuildInfo, path string) *debug.Module { 132 if info.Path == ourPath { 133 return &info.Main 134 } 135 for _, mod := range info.Deps { 136 if mod.Path == path { 137 return mod 138 } 139 } 140 return nil 141 }