| package version |
| |
| import ( |
| "regexp" |
| "strconv" |
| "strings" |
| ) |
| |
| var regexpSigns = regexp.MustCompile(`[_\-+]`) |
| var regexpDotBeforeDigit = regexp.MustCompile(`([^.\d]+)`) |
| var regexpMultipleDots = regexp.MustCompile(`\.{2,}`) |
| |
| var specialForms = map[string]int{ |
| "dev": -6, |
| "alpha": -5, |
| "a": -5, |
| "beta": -4, |
| "b": -4, |
| "RC": -3, |
| "rc": -3, |
| "#": -2, |
| "p": 1, |
| "pl": 1, |
| } |
| |
| // Compares two version number strings, for a particular relationship |
| // |
| // Usage |
| // version.Compare("2.3.4", "v3.1.2", "<") |
| // Returns: true |
| // |
| // version.Compare("1.0rc1", "1.0", ">=") |
| // Returns: false |
| func Compare(version1, version2, operator string) bool { |
| version1N := Normalize(version1) |
| version2N := Normalize(version2) |
| |
| return CompareNormalized(version1N, version2N, operator) |
| } |
| |
| // Compares two normalizated version number strings, for a particular relationship |
| // |
| // The function first replaces _, - and + with a dot . in the version strings |
| // and also inserts dots . before and after any non number so that for example |
| // '4.3.2RC1' becomes '4.3.2.RC.1'. |
| // |
| // Then it splits the results like if you were using Split(version, '.'). |
| // Then it compares the parts starting from left to right. If a part contains |
| // special version strings these are handled in the following order: any string |
| // not found in this list: |
| // < dev < alpha = a < beta = b < RC = rc < # < pl = p. |
| // |
| // Usage |
| // version.CompareNormalized("1.0-dev", "1.0", "<") |
| // Returns: true |
| // |
| // version.CompareNormalized("1.0rc1", "1.0", ">=") |
| // Returns: false |
| // |
| // version.CompareNormalized("1.0", "1.0b1", "ge") |
| // Returns: true |
| func CompareNormalized(version1, version2, operator string) bool { |
| compare := CompareSimple(version1, version2) |
| |
| switch { |
| case operator == ">" || operator == "gt": |
| return compare > 0 |
| case operator == ">=" || operator == "ge": |
| return compare >= 0 |
| case operator == "<=" || operator == "le": |
| return compare <= 0 |
| case operator == "==" || operator == "=" || operator == "eq": |
| return compare == 0 |
| case operator == "<>" || operator == "!=" || operator == "ne": |
| return compare != 0 |
| case operator == "" || operator == "<" || operator == "lt": |
| return compare < 0 |
| } |
| |
| return false |
| } |
| |
| // Compares two normalizated version number strings |
| // |
| // Just the same of CompareVersion but return a int result, 0 if both version |
| // are equal, 1 if the right side is bigger and -1 if the right side is lower |
| // |
| // Usage |
| // version.CompareSimple("1.2", "1.0.1") |
| // Returns: 1 |
| // |
| // version.CompareSimple("1.0rc1", "1.0") |
| // Returns: -1 |
| func CompareSimple(version1, version2 string) int { |
| var x, r, l int = 0, 0, 0 |
| |
| v1, v2 := prepVersion(version1), prepVersion(version2) |
| len1, len2 := len(v1), len(v2) |
| |
| if len1 > len2 { |
| x = len1 |
| } else { |
| x = len2 |
| } |
| |
| for i := 0; i < x; i++ { |
| if i < len1 && i < len2 { |
| if v1[i] == v2[i] { |
| continue |
| } |
| } |
| |
| r = 0 |
| if i < len1 { |
| r = numVersion(v1[i]) |
| } |
| |
| l = 0 |
| if i < len2 { |
| l = numVersion(v2[i]) |
| } |
| |
| if r < l { |
| return -1 |
| } else if r > l { |
| return 1 |
| } |
| } |
| |
| return 0 |
| } |
| |
| func prepVersion(version string) []string { |
| if len(version) == 0 { |
| return []string{""} |
| } |
| |
| version = regexpSigns.ReplaceAllString(version, ".") |
| version = regexpDotBeforeDigit.ReplaceAllString(version, ".$1.") |
| version = regexpMultipleDots.ReplaceAllString(version, ".") |
| |
| return strings.Split(version, ".") |
| } |
| |
| func numVersion(value string) int { |
| if value == "" { |
| return 0 |
| } |
| |
| if number, err := strconv.Atoi(value); err == nil { |
| return number |
| } |
| |
| if special, ok := specialForms[value]; ok { |
| return special |
| } |
| |
| return -7 |
| } |