From 65f3c1b46fa0f247cc774643aa4cb938bbed184b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 23 Sep 2022 14:08:25 +0200 Subject: [PATCH] internal/version: use gitCommit injection in version handling code (#25851) This changes the CI build to store the git commit and date into package internal/version instead of package main. Doing this essentially merges our two ways of tracking the go-ethereum version into a single place, achieving two objectives: - Bad block reports, which use version.Info(), will now have the git commit information even when geth is built in an environment such as launchpad.net where git access is unavailable. - For geth builds created by `go build ./cmd/geth` (i.e. not using `go run build/ci.go install`), git information stored by the go tool is now used in the p2p node name as well as in `geth version` and `geth version-check`. --- build/ci.go | 4 +-- cmd/abigen/main.go | 11 ++----- cmd/checkpoint-admin/main.go | 9 +----- cmd/clef/main.go | 8 +---- cmd/devp2p/main.go | 18 ++--------- cmd/ethkey/main.go | 6 +--- cmd/evm/main.go | 9 ++---- cmd/faucet/faucet.go | 9 ++---- cmd/geth/config.go | 4 ++- cmd/geth/main.go | 7 ++--- cmd/geth/misccmd.go | 19 +++++------ cmd/p2psim/main.go | 8 +---- internal/flags/helpers.go | 6 ++-- internal/version/vcs_fallback.go | 4 +-- internal/version/vcs_go1.18.go | 29 ++++++++++------- internal/version/version.go | 54 ++++++++++++++++++++++++++------ 16 files changed, 100 insertions(+), 105 deletions(-) diff --git a/build/ci.go b/build/ci.go index 4c8062eaf..043c13b76 100644 --- a/build/ci.go +++ b/build/ci.go @@ -254,8 +254,8 @@ func doInstall(cmdline []string) { func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) { var ld []string if env.Commit != "" { - ld = append(ld, "-X", "main.gitCommit="+env.Commit) - ld = append(ld, "-X", "main.gitDate="+env.Date) + ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitCommit="+env.Commit) + ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitDate="+env.Date) } // Strip DWARF on darwin. This used to be required for certain things, // and there is no downside to this, so we just keep doing it. diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 56ebfa9e9..075e98930 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -33,14 +33,6 @@ import ( "github.com/urfave/cli/v2" ) -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - - app *cli.App -) - var ( // Flags needed by abigen abiFlag = &cli.StringFlag{ @@ -82,8 +74,9 @@ var ( } ) +var app = flags.NewApp("Ethereum ABI wrapper code generator") + func init() { - app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app.Name = "abigen" app.Flags = []cli.Flag{ abiFlag, diff --git a/cmd/checkpoint-admin/main.go b/cmd/checkpoint-admin/main.go index 0604ccaad..ca0bae737 100644 --- a/cmd/checkpoint-admin/main.go +++ b/cmd/checkpoint-admin/main.go @@ -28,16 +28,9 @@ import ( "github.com/urfave/cli/v2" ) -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - - app *cli.App -) +var app = flags.NewApp("ethereum checkpoint helper tool") func init() { - app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app.Commands = []*cli.Command{ commandStatus, commandDeploy, diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 05290f52f..a3e4815ed 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -215,13 +215,7 @@ The gendoc generates example structures of the json-rpc communication types. `} ) -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - - app = flags.NewApp(gitCommit, gitDate, "Manage Ethereum account operations") -) +var app = flags.NewApp("Manage Ethereum account operations") func init() { app.Name = "Clef" diff --git a/cmd/devp2p/main.go b/cmd/devp2p/main.go index 51b9fdb76..9e13d29ab 100644 --- a/cmd/devp2p/main.go +++ b/cmd/devp2p/main.go @@ -19,30 +19,17 @@ package main import ( "fmt" "os" - "path/filepath" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) -var ( - // Git information set by linker when building with ci.go. - gitCommit string - gitDate string - app = &cli.App{ - Name: filepath.Base(os.Args[0]), - Usage: "go-ethereum devp2p tool", - Version: params.VersionWithCommit(gitCommit, gitDate), - Writer: os.Stdout, - HideVersion: true, - } -) +var app = flags.NewApp("go-ethereum devp2p tool") func init() { - // Set up the CLI app. + app.HideVersion = true app.Flags = append(app.Flags, debug.Flags...) app.Before = func(ctx *cli.Context) error { flags.MigrateGlobalFlags(ctx) @@ -56,6 +43,7 @@ func init() { fmt.Fprintf(os.Stderr, "No such command: %s\n", cmd) os.Exit(1) } + // Add subcommands. app.Commands = []*cli.Command{ enrdumpCommand, diff --git a/cmd/ethkey/main.go b/cmd/ethkey/main.go index 2b21f3cd7..25c0d104f 100644 --- a/cmd/ethkey/main.go +++ b/cmd/ethkey/main.go @@ -28,14 +28,10 @@ const ( defaultKeyfileName = "keyfile.json" ) -// Git SHA1 commit hash of the release (set via linker flags) -var gitCommit = "" -var gitDate = "" - var app *cli.App func init() { - app = flags.NewApp(gitCommit, gitDate, "an Ethereum key manager") + app = flags.NewApp("Ethereum key manager") app.Commands = []*cli.Command{ commandGenerate, commandInspect, diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 994b6436a..5f9e75f48 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -27,13 +27,6 @@ import ( "github.com/urfave/cli/v2" ) -var ( - gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) - gitDate = "" - - app = flags.NewApp(gitCommit, gitDate, "the evm command line interface") -) - var ( DebugFlag = &cli.BoolFlag{ Name: "debug", @@ -192,6 +185,8 @@ var blockBuilderCommand = &cli.Command{ }, } +var app = flags.NewApp("the evm command line interface") + func init() { app.Flags = []cli.Flag{ BenchFlag, diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index dfb7d326d..bec1f6d33 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -49,6 +49,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethstats" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -93,11 +94,6 @@ var ( ether = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) ) -var ( - gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) - gitDate = "" // Git commit date YYYYMMDD of the release (set via linker flags) -) - //go:embed faucet.html var websiteTmpl string @@ -226,9 +222,10 @@ type wsConn struct { func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) { // Assemble the raw devp2p protocol stack + git, _ := version.VCS() stack, err := node.New(&node.Config{ Name: "geth", - Version: params.VersionWithCommit(gitCommit, gitDate), + Version: params.VersionWithCommit(git.Commit, git.Date), DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"), P2P: p2p.Config{ NAT: nat.Any(), diff --git a/cmd/geth/config.go b/cmd/geth/config.go index d877e2b5d..a8cee0d13 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" @@ -108,9 +109,10 @@ func loadConfig(file string, cfg *gethConfig) error { } func defaultNodeConfig() node.Config { + git, _ := version.VCS() cfg := node.DefaultConfig cfg.Name = clientIdentifier - cfg.Version = params.VersionWithCommit(gitCommit, gitDate) + cfg.Version = params.VersionWithCommit(git.Commit, git.Date) cfg.HTTPModules = append(cfg.HTTPModules, "eth") cfg.WSModules = append(cfg.WSModules, "eth") cfg.IPCPath = "geth.ipc" diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 70b354ae1..43885ca42 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -52,11 +52,6 @@ const ( ) var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - // The app that holds all commands and flags. - app = flags.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") // flags that configure the node nodeFlags = flags.Merge([]cli.Flag{ utils.IdentityFlag, @@ -205,6 +200,8 @@ var ( } ) +var app = flags.NewApp("the go-ethereum command line interface") + func init() { // Initialize the CLI app and start Geth app.Action = geth diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index cc5feea9f..d8a523c63 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) @@ -38,9 +39,7 @@ var ( VersionCheckVersionFlag = &cli.StringFlag{ Name: "check.version", Usage: "Version to check", - Value: fmt.Sprintf("Geth/v%v/%v-%v/%v", - params.VersionWithCommit(gitCommit, gitDate), - runtime.GOOS, runtime.GOARCH, runtime.Version()), + Value: version.ClientName(clientIdentifier), } makecacheCommand = &cli.Command{ Action: makecache, @@ -67,7 +66,7 @@ Regular users do not need to execute it. `, } versionCommand = &cli.Command{ - Action: version, + Action: printVersion, Name: "version", Usage: "Print version numbers", ArgsUsage: " ", @@ -127,14 +126,16 @@ func makedag(ctx *cli.Context) error { return nil } -func version(ctx *cli.Context) error { +func printVersion(ctx *cli.Context) error { + git, _ := version.VCS() + fmt.Println(strings.Title(clientIdentifier)) fmt.Println("Version:", params.VersionWithMeta) - if gitCommit != "" { - fmt.Println("Git Commit:", gitCommit) + if git.Commit != "" { + fmt.Println("Git Commit:", git.Commit) } - if gitDate != "" { - fmt.Println("Git Commit Date:", gitDate) + if git.Date != "" { + fmt.Println("Git Commit Date:", git.Date) } fmt.Println("Architecture:", runtime.GOARCH) fmt.Println("Go Version:", runtime.Version()) diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go index 8b3cb29b1..a3546d405 100644 --- a/cmd/p2psim/main.go +++ b/cmd/p2psim/main.go @@ -100,14 +100,8 @@ var ( } ) -var ( - // Git information set by linker when building with ci.go. - gitCommit string - gitDate string -) - func main() { - app := flags.NewApp(gitCommit, gitDate, "devp2p simulation command-line client") + app := flags.NewApp("devp2p simulation command-line client") app.Flags = []cli.Flag{ apiFlag, } diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index de1d29ffd..46409f4df 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -20,15 +20,17 @@ import ( "fmt" "strings" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) // NewApp creates an app with sane defaults. -func NewApp(gitCommit, gitDate, usage string) *cli.App { +func NewApp(usage string) *cli.App { + git, _ := version.VCS() app := cli.NewApp() app.EnableBashCompletion = true - app.Version = params.VersionWithCommit(gitCommit, gitDate) + app.Version = params.VersionWithCommit(git.Commit, git.Date) app.Usage = usage app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" app.Before = func(ctx *cli.Context) error { diff --git a/internal/version/vcs_fallback.go b/internal/version/vcs_fallback.go index 6d7f32e73..f792c68cd 100644 --- a/internal/version/vcs_fallback.go +++ b/internal/version/vcs_fallback.go @@ -23,6 +23,6 @@ import "runtime/debug" // In Go versions before 1.18, VCS information is not available. -func vcsInfo(info *debug.BuildInfo) (gitStatus, bool) { - return gitStatus{}, false +func buildInfoVCS(info *debug.BuildInfo) (VCSInfo, bool) { + return VCSInfo{}, false } diff --git a/internal/version/vcs_go1.18.go b/internal/version/vcs_go1.18.go index d5b9c97a1..53cd41fb3 100644 --- a/internal/version/vcs_go1.18.go +++ b/internal/version/vcs_go1.18.go @@ -19,29 +19,36 @@ package version -import "runtime/debug" +import ( + "runtime/debug" + "time" +) // In go 1.18 and beyond, the go tool embeds VCS information into the build. -// vcsInfo returns VCS information of the build. -func vcsInfo(info *debug.BuildInfo) (s gitStatus, ok bool) { +const ( + govcsTimeLayout = "2006-01-02T15:04:05Z" + ourTimeLayout = "20060102" +) + +// buildInfoVCS returns VCS information of the build. +func buildInfoVCS(info *debug.BuildInfo) (s VCSInfo, ok bool) { for _, v := range info.Settings { switch v.Key { case "vcs.revision": - if len(v.Value) < 8 { - s.revision = v.Value - } else { - s.revision = v.Value[:8] - } + s.Commit = v.Value case "vcs.modified": if v.Value == "true" { - s.modified = true + s.Dirty = true } case "vcs.time": - s.time = v.Value + t, err := time.Parse(govcsTimeLayout, v.Value) + if err == nil { + s.Date = t.Format(ourTimeLayout) + } } } - if s.revision != "" && s.time != "" { + if s.Commit != "" && s.Date != "" { ok = true } return diff --git a/internal/version/version.go b/internal/version/version.go index e4b9ee490..4959102f7 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -19,6 +19,7 @@ package version import ( "fmt" + "runtime" "runtime/debug" "strings" @@ -27,6 +28,43 @@ import ( const ourPath = "github.com/ethereum/go-ethereum" // Path to our module +// These variables are set at build-time by the linker when the build is +// done by build/ci.go. +var gitCommit, gitDate string + +// VCSInfo represents the git repository state. +type VCSInfo struct { + Commit string // head commit hash + Date string // commit time in YYYYMMDD format + Dirty bool +} + +// VCS returns version control information of the current executable. +func VCS() (VCSInfo, bool) { + if gitCommit != "" { + // Use information set by the build script if present. + return VCSInfo{Commit: gitCommit, Date: gitDate}, true + } + if buildInfo, ok := debug.ReadBuildInfo(); ok { + if buildInfo.Main.Path == ourPath { + return buildInfoVCS(buildInfo) + } + } + return VCSInfo{}, false +} + +// ClientName creates a software name/version identifier according to common +// conventions in the Ethereum p2p network. +func ClientName(clientIdentifier string) string { + git, _ := VCS() + return fmt.Sprintf("%s/v%v/%v-%v/%v", + strings.Title(clientIdentifier), + params.VersionWithCommit(git.Commit, git.Date), + runtime.GOOS, runtime.GOARCH, + runtime.Version(), + ) +} + // runtimeInfo returns build and platform information about the current binary. // // If the package that is currently executing is a prefixed by our go-ethereum @@ -40,22 +78,20 @@ func Info() (version, vcs string) { return version, "" } version = versionInfo(buildInfo) - if status, ok := vcsInfo(buildInfo); ok { + if status, ok := VCS(); ok { modified := "" - if status.modified { + if status.Dirty { modified = " (dirty)" } - vcs = status.revision + "-" + status.time + modified + commit := status.Commit + if len(commit) > 8 { + commit = commit[:8] + } + vcs = commit + "-" + status.Date + modified } return version, vcs } -type gitStatus struct { - revision string - time string - modified bool -} - // versionInfo returns version information for the currently executing // implementation. //