github.com/ava-labs/subnet-evm@v0.6.4/internal/version/version.go (about)

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