github.com/ethereum/go-ethereum@v1.16.1/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/version" 27 ) 28 29 const ourPath = "github.com/ethereum/go-ethereum" // Path to our module 30 31 // Family holds the textual version string for major.minor 32 var Family = fmt.Sprintf("%d.%d", version.Major, version.Minor) 33 34 // Semantic holds the textual version string for major.minor.patch. 35 var Semantic = fmt.Sprintf("%d.%d.%d", version.Major, version.Minor, version.Patch) 36 37 // WithMeta holds the textual version string including the metadata. 38 var WithMeta = func() string { 39 v := Semantic 40 if version.Meta != "" { 41 v += "-" + version.Meta 42 } 43 return v 44 }() 45 46 func WithCommit(gitCommit, gitDate string) string { 47 vsn := WithMeta 48 if len(gitCommit) >= 8 { 49 vsn += "-" + gitCommit[:8] 50 } 51 if (version.Meta != "stable") && (gitDate != "") { 52 vsn += "-" + gitDate 53 } 54 return vsn 55 } 56 57 // Archive holds the textual version string used for Geth archives. e.g. 58 // "1.8.11-dea1ce05" for stable releases, or "1.8.13-unstable-21c059b6" for unstable 59 // releases. 60 func Archive(gitCommit string) string { 61 vsn := Semantic 62 if version.Meta != "stable" { 63 vsn += "-" + version.Meta 64 } 65 if len(gitCommit) >= 8 { 66 vsn += "-" + gitCommit[:8] 67 } 68 return vsn 69 } 70 71 // ClientName creates a software name/version identifier according to common 72 // conventions in the Ethereum p2p network. 73 func ClientName(clientIdentifier string) string { 74 git, _ := VCS() 75 return fmt.Sprintf("%s/v%v/%v-%v/%v", 76 strings.Title(clientIdentifier), 77 WithCommit(git.Commit, git.Date), 78 runtime.GOOS, runtime.GOARCH, 79 runtime.Version(), 80 ) 81 } 82 83 // Info returns build and platform information about the current binary. 84 // 85 // If the package that is currently executing is a prefixed by our go-ethereum 86 // module path, it will print out commit and date VCS information. Otherwise, 87 // it will assume it's imported by a third-party and will return the imported 88 // version and whether it was replaced by another module. 89 func Info() (version, vcs string) { 90 version = WithMeta 91 buildInfo, ok := debug.ReadBuildInfo() 92 if !ok { 93 return version, "" 94 } 95 version = versionInfo(buildInfo) 96 if status, ok := VCS(); ok { 97 modified := "" 98 if status.Dirty { 99 modified = " (dirty)" 100 } 101 commit := status.Commit 102 if len(commit) > 8 { 103 commit = commit[:8] 104 } 105 vcs = commit + "-" + status.Date + modified 106 } 107 return version, vcs 108 } 109 110 // versionInfo returns version information for the currently executing 111 // implementation. 112 // 113 // Depending on how the code is instantiated, it returns different amounts of 114 // information. If it is unable to determine which module is related to our 115 // package it falls back to the hardcoded values in the params package. 116 func versionInfo(info *debug.BuildInfo) string { 117 // If the main package is from our repo, prefix version with "geth". 118 if strings.HasPrefix(info.Path, ourPath) { 119 return fmt.Sprintf("geth %s", info.Main.Version) 120 } 121 // Not our main package, so explicitly print out the module path and 122 // version. 123 var version string 124 if info.Main.Path != "" && info.Main.Version != "" { 125 // These can be empty when invoked with "go run". 126 version = fmt.Sprintf("%s@%s ", info.Main.Path, info.Main.Version) 127 } 128 mod := findModule(info, ourPath) 129 if mod == nil { 130 // If our module path wasn't imported, it's unclear which 131 // version of our code they are running. Fallback to hardcoded 132 // version. 133 return version + fmt.Sprintf("geth %s", WithMeta) 134 } 135 // Our package is a dependency for the main module. Return path and 136 // version data for both. 137 version += fmt.Sprintf("%s@%s", mod.Path, mod.Version) 138 if mod.Replace != nil { 139 // If our package was replaced by something else, also note that. 140 version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) 141 } 142 return version 143 } 144 145 // findModule returns the module at path. 146 func findModule(info *debug.BuildInfo, path string) *debug.Module { 147 if info.Path == ourPath { 148 return &info.Main 149 } 150 for _, mod := range info.Deps { 151 if mod.Path == path { 152 return mod 153 } 154 } 155 return nil 156 }