From 92f4d9f9c96541fac6f10d0a603d9229622360ab Mon Sep 17 00:00:00 2001 From: Masatoshi Fukunaga Date: Wed, 1 Mar 2023 16:42:49 +0900 Subject: [PATCH] Fix bug in the order of versions --- README.md | 2 ++ fetch.go | 3 +- list.go | 3 +- vers.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++- vers_test.go | 71 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 vers_test.go diff --git a/README.md b/README.md index 7dc74ed..16df4a3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ lenv ========= +[![test](https://github.com/mah0x211/lenv/actions/workflows/test.yml/badge.svg)](https://github.com/mah0x211/lenv/actions/workflows/test.yml) + Lua Version Manager. --- diff --git a/fetch.go b/fetch.go index c1edefa..c12bf97 100644 --- a/fetch.go +++ b/fetch.go @@ -7,7 +7,6 @@ import ( "net/http" "path/filepath" "regexp" - "sort" ) type ParseFunc func(body []byte) List @@ -121,7 +120,7 @@ func cmdFetch() { } vers = append(vers, ver) } - sort.Sort(sort.Reverse(sort.StringSlice(vers))) + sortVersions(vers) format := fmt.Sprintf("%%-%ds %%s", maxlen) for _, ver := range vers { diff --git a/list.go b/list.go index 8a09fc1..bf24da0 100644 --- a/list.go +++ b/list.go @@ -6,7 +6,6 @@ import ( "io/ioutil" "os" "path/filepath" - "sort" "strings" ) @@ -56,7 +55,7 @@ func listRocks(luadir string) { } } } - sort.Sort(sort.Reverse(sort.StringSlice(vers))) + sortVersions(vers) if len(vers) > 0 { format := fmt.Sprintf(" %%s %%-%ds", maxlen) diff --git a/vers.go b/vers.go index a34fb10..c5f546c 100644 --- a/vers.go +++ b/vers.go @@ -2,10 +2,93 @@ package main import ( "fmt" + "regexp" "sort" + "strconv" "strings" ) +type version struct { + major int + minor int + patch int + tag string +} + +var reVersionNum = regexp.MustCompile(`^\d+$`) +var reVersionTag = regexp.MustCompile(`^(\d+)[.+-]?(.*)$`) + +func toInt(s string) int { + if reVersionNum.MatchString(s) { + n, err := strconv.Atoi(s) + if err != nil { + fatalf("failed to strconv.Atoi(%#v): %v", s, err) + } + return n + } + return 0 +} + +func newVersion(s string) *version { + list := strings.SplitN(s, ".", 3) + for i, s := range list { + if !reVersionNum.MatchString(s) { + list[i] = strings.Join(list[i:], ".") + break + } + } + tail := len(list) - 1 + if tail >= 0 { + matches := reVersionTag.FindStringSubmatch(list[tail]) + if len(matches) == 3 { + list[tail] = matches[1] + list = append(list, matches[2]) + } + } + + ver := &version{} + switch len(list) { + case 4: + ver.tag = list[3] + fallthrough + case 3: + ver.patch = toInt(list[2]) + fallthrough + case 2: + ver.minor = toInt(list[1]) + fallthrough + case 1: + ver.major = toInt(list[0]) + } + + return ver +} + +func sortVersions(vers []string) { + sort.Slice(vers, func(i, j int) bool { + a := newVersion(vers[i]) + b := newVersion(vers[j]) + if a.major > b.major { + return true + } else if a.major < b.major { + return false + } else if a.minor > b.minor { + return true + } else if a.minor < b.minor { + return false + } else if a.patch > b.patch { + return true + } else if a.patch < b.patch { + return false + } else if len(a.tag) == 0 && len(b.tag) > 0 { + return true + } else if len(b.tag) == 0 && len(a.tag) > 0 { + return false + } + return a.tag > b.tag + }) +} + func cmdVers() { for _, cfg := range []*TargetConfig{ LuaCfg, LuaJitCfg, LuaRocksCfg, @@ -22,7 +105,7 @@ func cmdVers() { maxlen = len(v) } } - sort.Sort(sort.Reverse(sort.StringSlice(vers))) + sortVersions(vers) format := fmt.Sprintf("%%-%ds", maxlen) arr := []string{} diff --git a/vers_test.go b/vers_test.go new file mode 100644 index 0000000..2d3deeb --- /dev/null +++ b/vers_test.go @@ -0,0 +1,71 @@ +package main + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_sortVersion(t *testing.T) { + lua := []string{ + "5.4.4", "5.4.3", "5.4.2", "5.4.1", "5.4.0", + "5.3.6", "5.3.5", "5.3.4", "5.3.3", "5.3.2", "5.3.1", "5.3.0", + "5.2.4", "5.2.3", "5.2.2", "5.2.1", "5.2.0", + "5.1.5", "5.1.4", "5.1.3", "5.1.2", "5.1.1", "5.1", + "5.0.3", "5.0.2", "5.0.1", "5.0", + "4.0.1", "4.0", + "3.2.2", "3.2.1", "3.2", + "3.1", "3.0", + "2.5", "2.4", "2.2", "2.1", + "1.1", "1.0", + } + luajit := []string{ + "2.1.0-beta3", + "2.0.5", + "1.1.8", + "1.0.3", + } + luarocks := []string{ + "3.9.1", "3.9.0", + "3.8.0", "3.7.0", "3.6.0", "3.5.0", "3.4.0", + "3.3.1", "3.3.0", + "3.2.1", "3.2.0", + "3.1.3", "3.1.2", "3.1.1", "3.1.0", + "3.0.4", "3.0.3", "3.0.2", "3.0.1", "3.0.1-rc2", "3.0.1-rc1", + "3.0.0", "3.0.0-rc2", "3.0.0-rc1", "3.0.0beta2", "3.0.0beta1", + "2.4.4", "2.4.3", "2.4.2", "2.4.1", "2.4.0", + "2.3.0", "2.3.0-rc2", "2.3.0-rc1", + "2.2.3-rc2", "2.2.3-rc1", "2.2.2", "2.2.1", "2.2.0", "2.2.0beta1", + "2.1.2", "2.1.1", "2.1.0", "2.1.0-rc3", "2.1.0-rc2", "2.1.0-rc1", + "2.0.13", "2.0.12", "2.0.11", "2.0.10", + "2.0.9", "2.0.9-rc2", "2.0.9-rc1", "2.0.9.1", + "2.0.8", "2.0.8-rc2", "2.0.8-rc1", + "2.0.7", "2.0.7.1", + "2.0.6", "2.0.6-rc1", + "2.0.5", "2.0.5-rc1", + "2.0.4", "2.0.4-rc3", "2.0.4-rc2", "2.0.4-rc1", "2.0.4.1", + "2.0.3", "2.0.3-rc2", "2.0.3-rc1", + "2.0.2", "2.0.1", "2.0", + "1.0.1", "1.0", + "0.6.0.2", + "0.5.2", "0.5.1", "0.5", + "0.4.3", "0.4.2", "0.4.1", "0.4", + "0.3.2", "0.3.1", "0.3", + "0.2", "0.1", + } + + rand.Seed(time.Now().UnixNano()) + for _, list := range [][]string{ + lua, luajit, luarocks, + } { + arr := make([]string, len(list)) + copy(arr, list) + rand.Shuffle(len(arr), func(i, j int) { + arr[i], arr[j] = arr[j], arr[i] + }) + sortVersions(arr) + assert.Equal(t, list, arr) + } +}