gopkg.in/essentialkaos/ek.v3@v3.5.1/version/version.go (about) 1 // Package version provides methods for parsing semver version info 2 package version 3 4 // ////////////////////////////////////////////////////////////////////////////////// // 5 // // 6 // Copyright (c) 2009-2016 Essential Kaos // 7 // Essential Kaos Open Source License <http://essentialkaos.com/ekol?en> // 8 // // 9 // ////////////////////////////////////////////////////////////////////////////////// // 10 11 import ( 12 "regexp" 13 "strconv" 14 "strings" 15 ) 16 17 // ////////////////////////////////////////////////////////////////////////////////// // 18 19 // Version contains version data 20 type Version struct { 21 raw string 22 versionSlice []int 23 preRelease string 24 build string 25 } 26 27 // ////////////////////////////////////////////////////////////////////////////////// // 28 29 var preRegExp = regexp.MustCompile(`([a-zA-Z-.]{1,})([0-9]{0,})`) 30 31 // ////////////////////////////////////////////////////////////////////////////////// // 32 33 // Parse parse version string and return version struct 34 func Parse(v string) *Version { 35 if v == "" { 36 return &Version{} 37 } 38 39 result := &Version{raw: v} 40 41 if strings.Contains(v, "+") { 42 bs := strings.Split(v, "+") 43 44 if bs[1] == "" { 45 v = bs[0] 46 } else { 47 v = bs[0] 48 result.build = bs[1] 49 } 50 } 51 52 if strings.Contains(v, "-") { 53 ps := strings.Split(v, "-") 54 55 if ps[1] == "" { 56 v = ps[0] 57 } else { 58 v = ps[0] 59 result.preRelease = ps[1] 60 } 61 } 62 63 for _, version := range strings.Split(v, ".") { 64 iv, err := strconv.Atoi(version) 65 66 if err != nil { 67 break 68 } 69 70 result.versionSlice = append(result.versionSlice, iv) 71 } 72 73 return result 74 } 75 76 // ////////////////////////////////////////////////////////////////////////////////// // 77 78 // Major return major version 79 func (v *Version) Major() int { 80 if v == nil || v.raw == "" || len(v.versionSlice) == 0 { 81 return -1 82 } 83 84 return v.versionSlice[0] 85 } 86 87 // Minor return minor version 88 func (v *Version) Minor() int { 89 if v == nil || v.raw == "" || len(v.versionSlice) == 0 { 90 return -1 91 } 92 93 if len(v.versionSlice) == 1 { 94 return 0 95 } 96 97 return v.versionSlice[1] 98 } 99 100 // Patch return patch version 101 func (v *Version) Patch() int { 102 if v == nil || v.raw == "" || len(v.versionSlice) == 0 { 103 return -1 104 } 105 106 if len(v.versionSlice) <= 2 { 107 return 0 108 } 109 110 return v.versionSlice[2] 111 } 112 113 // PreRelease return prerelease version 114 func (v *Version) PreRelease() string { 115 if v == nil || v.raw == "" { 116 return "" 117 } 118 119 return v.preRelease 120 } 121 122 // Build return build 123 func (v *Version) Build() string { 124 if v == nil || v.raw == "" { 125 return "" 126 } 127 128 return v.build 129 } 130 131 // Equal return true if version are equal to given 132 func (v *Version) Equal(version *Version) bool { 133 if v.Major() != version.Major() { 134 return false 135 } 136 137 if v.Minor() != version.Minor() { 138 return false 139 } 140 141 if v.Patch() != version.Patch() { 142 return false 143 } 144 145 if v.PreRelease() != version.PreRelease() { 146 return false 147 } 148 149 if v.Build() != version.Build() { 150 return false 151 } 152 153 return true 154 } 155 156 // Less return true if given version is greater 157 func (v *Version) Less(version *Version) bool { 158 if v.Major() < version.Major() { 159 return true 160 } 161 162 if v.Minor() < version.Minor() { 163 return true 164 } 165 166 if v.Patch() < version.Patch() { 167 return true 168 } 169 170 pr1, pr2 := v.PreRelease(), version.PreRelease() 171 172 if pr1 != pr2 { 173 return prereleaseLess(pr1, pr2) 174 } 175 176 return false 177 } 178 179 // Greater return true if given version is less 180 func (v *Version) Greater(version *Version) bool { 181 if v.Major() > version.Major() { 182 return true 183 } 184 185 if v.Minor() > version.Minor() { 186 return true 187 } 188 189 if v.Patch() > version.Patch() { 190 return true 191 } 192 193 pr1, pr2 := v.PreRelease(), version.PreRelease() 194 195 if pr1 != pr2 { 196 return !prereleaseLess(pr1, pr2) 197 } 198 199 return false 200 } 201 202 // Contains check is current version contains given version 203 func (v *Version) Contains(version *Version) bool { 204 if v.Major() != version.Major() { 205 return false 206 } 207 208 if len(v.versionSlice) == 1 { 209 return true 210 } 211 212 if v.Minor() != version.Minor() { 213 return false 214 } 215 216 if len(v.versionSlice) == 2 { 217 return true 218 } 219 220 if v.Patch() != version.Patch() { 221 return false 222 } 223 224 return false 225 } 226 227 // Valid return true if version struct is valid 228 func (v *Version) Valid() bool { 229 if v == nil { 230 return false 231 } 232 233 return len(v.versionSlice) != 0 234 } 235 236 // String return version as string 237 func (v *Version) String() string { 238 if v == nil { 239 return "" 240 } 241 242 return v.raw 243 } 244 245 // ////////////////////////////////////////////////////////////////////////////////// // 246 247 // prereleaseLess 248 func prereleaseLess(pr1, pr2 string) bool { 249 // Current version is release and given is prerelease 250 if pr1 == "" && pr2 != "" { 251 return false 252 } 253 254 // Current version is prerelease and given is release 255 if pr1 != "" && pr2 == "" { 256 return true 257 } 258 259 // Parse prerelease 260 pr1Re := preRegExp.FindStringSubmatch(pr1) 261 pr2Re := preRegExp.FindStringSubmatch(pr2) 262 263 pr1Name := pr1Re[1] 264 pr2Name := pr2Re[1] 265 266 if pr1Name > pr2Name { 267 return false 268 } 269 270 if pr1Name < pr2Name { 271 return true 272 } 273 274 // Errors not important, because if subver is empty 275 // Atoi return 0 276 pr1Ver, _ := strconv.Atoi(pr1Re[2]) 277 pr2Ver, _ := strconv.Atoi(pr2Re[2]) 278 279 return pr1Ver < pr2Ver 280 }