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  }