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  }