github.com/orangebees/go-oneutils@v0.0.10/Semver/version.go (about) 1 package Semver 2 3 import ( 4 "errors" 5 "github.com/orangebees/go-oneutils/Convert" 6 "strconv" 7 ) 8 9 type VersionString string 10 type Version struct { 11 Major int `json:"major"` 12 Minor int `json:"minor"` 13 Patch int `json:"patch"` 14 PreRelease int `json:"pre_release"` 15 PreReleaseCount int `json:"pre_release_count"` 16 BuildMetadata string `json:"build_metadata"` 17 } 18 19 const ( 20 Alpha = iota 21 Beta 22 RC 23 Release 24 ) 25 26 var PreReleaseNames = []string{"alpha", "beta", "rc", "release"} 27 28 // 语义化版本号string 29 func (v *Version) String() string { 30 vs := make([]byte, 64) 31 vs = vs[:0] 32 vs = append(vs, strconv.Itoa(v.Major)...) 33 vs = append(vs, '.') 34 vs = append(vs, strconv.Itoa(v.Minor)...) 35 vs = append(vs, '.') 36 vs = append(vs, strconv.Itoa(v.Patch)...) 37 if v.PreRelease != Release { 38 vs = append(vs, '-') 39 vs = append(vs, PreReleaseNames[v.PreRelease]...) 40 if v.PreReleaseCount != 0 { 41 vs = append(vs, '.') 42 vs = append(vs, strconv.Itoa(v.PreReleaseCount)...) 43 } 44 } 45 if v.BuildMetadata != "" { 46 vs = append(vs, '+') 47 vs = append(vs, v.BuildMetadata...) 48 } 49 return string(vs) 50 } 51 52 // TagString 语义化版本标签 53 func (v *Version) TagString() string { 54 vs := make([]byte, 64) 55 vs = vs[:0] 56 vs = append(vs, 'v') 57 vs = append(vs, strconv.Itoa(v.Major)...) 58 vs = append(vs, '.') 59 vs = append(vs, strconv.Itoa(v.Minor)...) 60 vs = append(vs, '.') 61 vs = append(vs, strconv.Itoa(v.Patch)...) 62 if v.PreRelease != Release { 63 vs = append(vs, '-') 64 vs = append(vs, PreReleaseNames[v.PreRelease]...) 65 if v.PreReleaseCount != 0 { 66 vs = append(vs, '.') 67 vs = append(vs, strconv.Itoa(v.PreReleaseCount)...) 68 } 69 } 70 if v.BuildMetadata != "" { 71 vs = append(vs, '+') 72 vs = append(vs, v.BuildMetadata...) 73 } 74 return string(vs) 75 } 76 func NewFromString(str string) (*Version, error) { 77 v := Version{} 78 tmp := make([]byte, 8) 79 tmp = tmp[:0] 80 status := 0 81 v.PreRelease = 3 82 83 for i := 0; i < len(str); i++ { 84 s := str[i] 85 switch status { 86 case 0: 87 if s == 'v' || s == 'V' { 88 continue 89 } else { 90 if !isNum(s) { 91 92 return nil, errors.New("faulty data") 93 } 94 } 95 status++ 96 fallthrough 97 case 1: 98 if isNum(s) { 99 tmp = append(tmp, s) 100 } else { 101 if s == '.' { 102 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 103 if err != nil { 104 return nil, err 105 } 106 v.Major = atoi 107 tmp = tmp[:0] 108 status++ 109 } else { 110 return nil, errors.New("faulty data") 111 } 112 } 113 case 2: 114 if isNum(s) { 115 tmp = append(tmp, s) 116 } else { 117 if s == '.' { 118 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 119 if err != nil { 120 return nil, err 121 } 122 v.Minor = atoi 123 tmp = tmp[:0] 124 status++ 125 } else { 126 return nil, errors.New("faulty data") 127 } 128 } 129 case 3: 130 if isNum(s) { 131 tmp = append(tmp, s) 132 } else { 133 if s == '-' { 134 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 135 if err != nil { 136 return nil, err 137 } 138 v.Patch = atoi 139 tmp = tmp[:0] 140 status++ 141 } else if s == '+' { 142 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 143 if err != nil { 144 return nil, err 145 } 146 v.Patch = atoi 147 tmp = tmp[:0] 148 status += 3 149 } else { 150 return nil, errors.New("faulty data") 151 } 152 } 153 case 4: 154 //处理先行版字段 155 if s != '.' && s != '+' { 156 tmp = append(tmp, s) 157 } else { 158 //println(Convert.B2S(tmp)) 159 for k := 0; k < len(tmp); k++ { 160 tembyte := tmp[k] 161 if tembyte >= 'A' && tembyte <= 'Z' { 162 tmp[k] += 32 163 } 164 } 165 for j := 0; j < len(PreReleaseNames); j++ { 166 if PreReleaseNames[j] == Convert.B2S(tmp) { 167 v.PreRelease = j 168 break 169 } else if j == len(PreReleaseNames)-1 { 170 return nil, errors.New("faulty data") 171 } 172 } 173 tmp = tmp[:0] 174 status++ 175 if s == '+' { 176 status++ 177 } 178 } 179 case 5: 180 //处理先行版版本号 181 if isNum(s) { 182 tmp = append(tmp, s) 183 } else { 184 if s == '+' { 185 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 186 if err != nil { 187 return nil, err 188 } 189 v.PreReleaseCount = atoi 190 tmp = tmp[:0] 191 status++ 192 } else { 193 return nil, errors.New("faulty data") 194 } 195 } 196 case 6: 197 //编译元信息 198 tmp = append(tmp, s) 199 } 200 } 201 202 switch status { 203 case 3: 204 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 205 if err != nil { 206 return nil, err 207 } 208 v.Patch = atoi 209 case 4: 210 for k := 0; k < len(tmp); k++ { 211 tembyte := tmp[k] 212 if tembyte >= 'A' && tembyte <= 'Z' { 213 tmp[k] += 32 214 } 215 } 216 for j := 0; j < len(PreReleaseNames); j++ { 217 if PreReleaseNames[j] == Convert.B2S(tmp) { 218 v.PreRelease = j 219 break 220 } else if j == len(PreReleaseNames)-1 { 221 return nil, errors.New("faulty data") 222 } 223 } 224 case 5: 225 atoi, err := strconv.Atoi(Convert.B2S(tmp)) 226 if err != nil { 227 return nil, err 228 } 229 v.PreReleaseCount = atoi 230 case 6: 231 v.BuildMetadata = Convert.B2S(tmp) 232 } 233 234 return &v, nil 235 } 236 func (v *Version) Cmp(nv *Version) int { 237 if v.Major != nv.Major { 238 if v.Major > nv.Major { 239 return 1 240 } else { 241 return -1 242 } 243 } 244 if v.Minor != nv.Minor { 245 if v.Minor > nv.Minor { 246 return 1 247 } else { 248 return -1 249 } 250 } 251 if v.Patch != nv.Patch { 252 if v.Patch > nv.Patch { 253 return 1 254 } else { 255 return -1 256 } 257 } 258 if v.PreRelease != nv.PreRelease { 259 if v.PreRelease > nv.PreRelease { 260 return 1 261 } else { 262 return -1 263 } 264 } 265 if v.PreReleaseCount != nv.PreReleaseCount { 266 if v.PreReleaseCount > nv.PreReleaseCount { 267 return 1 268 } else { 269 return -1 270 } 271 } 272 return 0 273 } 274 275 func isNum(s uint8) bool { 276 if s >= 48 && s <= 57 { 277 return true 278 } 279 return false 280 }