github.com/prysmaticlabs/prysm@v1.4.4/shared/prereq/prereq.go (about) 1 package prereq 2 3 import ( 4 "context" 5 "os/exec" 6 "runtime" 7 "strconv" 8 "strings" 9 10 "github.com/pkg/errors" 11 log "github.com/sirupsen/logrus" 12 ) 13 14 type platform struct { 15 os string 16 arch string 17 majorVersion int 18 minorVersion int 19 } 20 21 var ( 22 // execShellOutput has execShellOutputFunc as the default but can be changed for testing purposes. 23 execShellOutput = execShellOutputFunc 24 runtimeOS = runtime.GOOS 25 runtimeArch = runtime.GOARCH 26 ) 27 28 // execShellOutputFunc passes a command and args to exec.CommandContext and returns the result as a string 29 func execShellOutputFunc(ctx context.Context, command string, args ...string) (string, error) { 30 result, err := exec.CommandContext(ctx, command, args...).Output() 31 if err != nil { 32 return "", errors.Wrap(err, "error in command execution") 33 } 34 return string(result), nil 35 } 36 37 func supportedPlatforms() []platform { 38 return []platform{ 39 {os: "linux", arch: "amd64"}, 40 {os: "linux", arch: "arm64"}, 41 {os: "darwin", arch: "amd64", majorVersion: 10, minorVersion: 14}, 42 {os: "windows", arch: "amd64"}, 43 } 44 } 45 46 // parseVersion takes a string and splits it using sep separator, and outputs a slice of integers 47 // corresponding to version numbers. If it cannot find num level of versions, it returns an error 48 func parseVersion(input string, num int, sep string) ([]int, error) { 49 var version = make([]int, num) 50 components := strings.Split(input, sep) 51 for i, component := range components { 52 components[i] = strings.TrimSpace(component) 53 } 54 if len(components) < num { 55 return nil, errors.New("insufficient information about version") 56 } 57 for i := range version { 58 var err error 59 version[i], err = strconv.Atoi(components[i]) 60 if err != nil { 61 return nil, errors.Wrap(err, "error during conversion") 62 } 63 } 64 return version, nil 65 } 66 67 // meetsMinPlatformReqs returns true if the runtime matches any on the list of supported platforms 68 func meetsMinPlatformReqs(ctx context.Context) (bool, error) { 69 okPlatforms := supportedPlatforms() 70 for _, platform := range okPlatforms { 71 if runtimeOS == platform.os && runtimeArch == platform.arch { 72 // If MacOS we make sure it meets the minimum version cutoff 73 if runtimeOS == "darwin" { 74 versionStr, err := execShellOutput(ctx, "uname", "-r") 75 if err != nil { 76 return false, errors.Wrap(err, "error obtaining MacOS version") 77 } 78 version, err := parseVersion(versionStr, 2, ".") 79 if err != nil { 80 return false, errors.Wrap(err, "error parsing version") 81 } 82 if version[0] != platform.majorVersion { 83 return version[0] > platform.majorVersion, nil 84 } 85 if version[1] < platform.minorVersion { 86 return false, nil 87 } 88 return true, nil 89 } 90 // Otherwise we have a match between runtime and our list of accepted platforms 91 return true, nil 92 } 93 } 94 return false, nil 95 } 96 97 // WarnIfPlatformNotSupported warns if the user's platform is not supported or if it fails to detect user's platform 98 func WarnIfPlatformNotSupported(ctx context.Context) { 99 supported, err := meetsMinPlatformReqs(ctx) 100 if err != nil { 101 log.Warnf("Failed to detect host platform: %v", err) 102 return 103 } 104 if !supported { 105 log.Warn("This platform is not supported. The following platforms are supported: Linux/AMD64," + 106 " Linux/ARM64, Mac OS X/AMD64 (10.14+ only), and Windows/AMD64") 107 } 108 }