gitee.com/mysnapcore/mysnapd@v0.1.0/strutil/version.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2017 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package strutil 21 22 import ( 23 "fmt" 24 "strings" 25 ) 26 27 // golang: seriously? that's sad! 28 func max(a, b int) int { 29 if a < b { 30 return b 31 } 32 return a 33 } 34 35 //go:generate go run $GOINVOKEFLAGS ./chrorder/main.go -package=strutil -output=chrorder.go 36 37 func cmpString(as, bs string) int { 38 for i := 0; i < max(len(as), len(bs)); i++ { 39 var a uint8 40 var b uint8 41 if i < len(as) { 42 a = as[i] 43 } 44 if i < len(bs) { 45 b = bs[i] 46 } 47 if chOrder[a] < chOrder[b] { 48 return -1 49 } 50 if chOrder[a] > chOrder[b] { 51 return +1 52 } 53 } 54 return 0 55 } 56 57 func trimLeadingZeroes(a string) string { 58 for i := 0; i < len(a); i++ { 59 if a[i] != '0' { 60 return a[i:] 61 } 62 } 63 return "" 64 } 65 66 // a and b both match /[0-9]+/ 67 func cmpNumeric(a, b string) int { 68 a = trimLeadingZeroes(a) 69 b = trimLeadingZeroes(b) 70 71 switch d := len(a) - len(b); { 72 case d > 0: 73 return 1 74 case d < 0: 75 return -1 76 } 77 for i := 0; i < len(a); i++ { 78 switch { 79 case a[i] > b[i]: 80 return 1 81 case a[i] < b[i]: 82 return -1 83 } 84 } 85 return 0 86 } 87 88 func matchEpoch(a string) bool { 89 if len(a) == 0 { 90 return false 91 } 92 if a[0] < '0' || a[0] > '9' { 93 return false 94 } 95 var i int 96 for i = 1; i < len(a) && a[i] >= '0' && a[i] <= '9'; i++ { 97 } 98 return i < len(a) && a[i] == ':' 99 } 100 101 // versionIsValid returns true if the given string is a valid 102 // version number according to the debian policy 103 func versionIsValid(a string) bool { 104 if matchEpoch(a) { 105 return false 106 } 107 return true 108 } 109 110 func nextFrag(s string) (frag, rest string, numeric bool) { 111 if len(s) == 0 { 112 return "", "", false 113 } 114 115 var i int 116 if s[0] >= '0' && s[0] <= '9' { 117 // is digit 118 for i = 1; i < len(s) && s[i] >= '0' && s[i] <= '9'; i++ { 119 } 120 numeric = true 121 } else { 122 // not digit 123 for i = 1; i < len(s) && (s[i] < '0' || s[i] > '9'); i++ { 124 } 125 } 126 return s[:i], s[i:], numeric 127 } 128 129 func compareSubversion(va, vb string) int { 130 var a, b string 131 var anum, bnum bool 132 var res int 133 for res == 0 { 134 a, va, anum = nextFrag(va) 135 b, vb, bnum = nextFrag(vb) 136 if a == "" && b == "" { 137 break 138 } 139 if anum && bnum { 140 res = cmpNumeric(a, b) 141 } else { 142 res = cmpString(a, b) 143 } 144 } 145 return res 146 } 147 148 // VersionCompare compare two version strings that follow the debian 149 // version policy and 150 // Returns: 151 // -1 if a is smaller than b 152 // 0 if a equals b 153 // +1 if a is bigger than b 154 func VersionCompare(va, vb string) (res int, err error) { 155 // FIXME: return err here instead 156 if !versionIsValid(va) { 157 return 0, fmt.Errorf("invalid version %q", va) 158 } 159 if !versionIsValid(vb) { 160 return 0, fmt.Errorf("invalid version %q", vb) 161 } 162 163 var sa, sb string 164 if ia := strings.LastIndexByte(va, '-'); ia < 0 { 165 sa = "0" 166 } else { 167 va, sa = va[:ia], va[ia+1:] 168 } 169 if ib := strings.LastIndexByte(vb, '-'); ib < 0 { 170 sb = "0" 171 } else { 172 vb, sb = vb[:ib], vb[ib+1:] 173 } 174 175 // the main version number (before the "-") 176 res = compareSubversion(va, vb) 177 if res != 0 { 178 return res, nil 179 } 180 181 // the subversion revision behind the "-" 182 return compareSubversion(sa, sb), nil 183 }