github.com/undoio/delve@v1.9.0/pkg/goversion/go_version.go (about) 1 package goversion 2 3 import ( 4 "os/exec" 5 "strconv" 6 "strings" 7 ) 8 9 // GoVersion represents the Go version of 10 // the Go compiler version used to compile 11 // the target binary. 12 type GoVersion struct { 13 Major int 14 Minor int 15 Rev int 16 Beta int 17 RC int 18 Proposal string 19 } 20 21 var ( 22 GoVer18Beta = GoVersion{1, 8, -1, 0, 0, ""} 23 ) 24 25 // Parse parses a go version string 26 func Parse(ver string) (GoVersion, bool) { 27 var r GoVersion 28 var err1, err2, err3 error 29 30 if strings.HasPrefix(ver, "devel") { 31 return GoVersion{-1, 0, 0, 0, 0, ""}, true 32 } 33 34 if strings.HasPrefix(ver, "go") { 35 ver := strings.Split(ver, " ")[0] 36 v := strings.SplitN(ver[2:], ".", 4) 37 switch len(v) { 38 case 2: 39 r.Major, err1 = strconv.Atoi(v[0]) 40 var vr []string 41 42 if vr = strings.SplitN(v[1], "beta", 2); len(vr) == 2 { 43 r.Beta, err3 = strconv.Atoi(vr[1]) 44 } else if vr = strings.SplitN(v[1], "b", 2); len(vr) == 2 { 45 if _, err := strconv.Atoi(vr[1]); err != nil { 46 return GoVersion{}, false 47 } 48 } else { 49 vr = strings.SplitN(v[1], "rc", 2) 50 if len(vr) == 2 { 51 r.RC, err3 = strconv.Atoi(vr[1]) 52 } else { 53 r.Minor, err2 = strconv.Atoi(v[1]) 54 if err2 != nil { 55 return GoVersion{}, false 56 } 57 return r, true 58 } 59 } 60 61 r.Minor, err2 = strconv.Atoi(vr[0]) 62 r.Rev = -1 63 r.Proposal = "" 64 65 if err1 != nil || err2 != nil || err3 != nil { 66 return GoVersion{}, false 67 } 68 69 return r, true 70 71 case 3: 72 73 r.Major, err1 = strconv.Atoi(v[0]) 74 r.Minor, err2 = strconv.Atoi(v[1]) 75 76 vr := strings.SplitN(v[2], "b", 2) 77 if len(vr) == 2 { 78 r.Rev, err3 = strconv.Atoi(vr[0]) 79 } else { 80 r.Rev, err3 = strconv.Atoi(v[2]) 81 } 82 83 r.Proposal = "" 84 if err1 != nil || err2 != nil || err3 != nil { 85 return GoVersion{}, false 86 } 87 88 return r, true 89 90 case 4: 91 92 r.Major, err1 = strconv.Atoi(v[0]) 93 r.Minor, err2 = strconv.Atoi(v[1]) 94 r.Rev, err3 = strconv.Atoi(v[2]) 95 r.Proposal = v[3] 96 if err1 != nil || err2 != nil || err3 != nil || r.Proposal == "" { 97 return GoVersion{}, false 98 } 99 100 return r, true 101 102 default: 103 return GoVersion{}, false 104 } 105 } 106 107 return GoVersion{}, false 108 } 109 110 // AfterOrEqual returns whether one GoVersion is after or 111 // equal to the other. 112 func (v *GoVersion) AfterOrEqual(b GoVersion) bool { 113 if v.Major < b.Major { 114 return false 115 } else if v.Major > b.Major { 116 return true 117 } 118 119 if v.Minor < b.Minor { 120 return false 121 } else if v.Minor > b.Minor { 122 return true 123 } 124 125 if v.Rev < b.Rev { 126 return false 127 } else if v.Rev > b.Rev { 128 return true 129 } 130 131 if v.Beta < b.Beta { 132 return false 133 } 134 135 if v.RC < b.RC { 136 return false 137 } 138 139 return true 140 } 141 142 // IsDevel returns whether the GoVersion 143 // is a development version. 144 func (v *GoVersion) IsDevel() bool { 145 return v.Major < 0 146 } 147 148 const goVersionPrefix = "go version " 149 150 // Installed runs "go version" and parses the output 151 func Installed() (GoVersion, bool) { 152 out, err := exec.Command("go", "version").CombinedOutput() 153 if err != nil { 154 return GoVersion{}, false 155 } 156 157 s := string(out) 158 159 if !strings.HasPrefix(s, goVersionPrefix) { 160 return GoVersion{}, false 161 } 162 163 return Parse(s[len(goVersionPrefix):]) 164 } 165 166 // VersionAfterOrEqual checks that version (as returned by runtime.Version() 167 // or go version) is major.minor or a later version, or a development 168 // version. 169 func VersionAfterOrEqual(version string, major, minor int) bool { 170 return VersionAfterOrEqualRev(version, major, minor, -1) 171 } 172 173 // VersionAfterOrEqualRev checks that version (as returned by runtime.Version() 174 // or go version) is major.minor or a later version, or a development 175 // version. 176 func VersionAfterOrEqualRev(version string, major, minor, rev int) bool { 177 ver, _ := Parse(version) 178 if ver.IsDevel() { 179 return true 180 } 181 return ver.AfterOrEqual(GoVersion{major, minor, rev, 0, 0, ""}) 182 } 183 184 const producerVersionPrefix = "Go cmd/compile " 185 186 // ProducerAfterOrEqual checks that the DW_AT_producer version is 187 // major.minor or a later version, or a development version. 188 func ProducerAfterOrEqual(producer string, major, minor int) bool { 189 ver := ParseProducer(producer) 190 if ver.IsDevel() { 191 return true 192 } 193 return ver.AfterOrEqual(GoVersion{major, minor, -1, 0, 0, ""}) 194 } 195 196 func ParseProducer(producer string) GoVersion { 197 producer = strings.TrimPrefix(producer, producerVersionPrefix) 198 ver, _ := Parse(producer) 199 return ver 200 }