From 10beffb30cfb1d042082402b370f1210fa0f889e Mon Sep 17 00:00:00 2001 From: comp500 Date: Thu, 13 Jun 2019 22:54:25 +0100 Subject: [PATCH] Add mod searching --- curseforge/curseforge.go | 72 ++++++++++++++++++++++++++++++++++++---- curseforge/request.go | 29 ++++++++++++++++ go.mod | 12 ++++++- go.sum | 42 ++++++++++------------- 4 files changed, 123 insertions(+), 32 deletions(-) diff --git a/curseforge/curseforge.go b/curseforge/curseforge.go index c58ca38..3d600d1 100644 --- a/curseforge/curseforge.go +++ b/curseforge/curseforge.go @@ -7,9 +7,11 @@ import ( "strconv" "strings" + "github.com/agnivade/levenshtein" "github.com/comp500/packwiz/core" "github.com/mitchellh/mapstructure" "github.com/urfave/cli" + "gopkg.in/dixonwille/wmenu.v4" ) func init() { @@ -154,12 +156,68 @@ func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error { // Handle error later (e.g. lowercase to search instead of as a slug) } + modInfoObtained := false + var modInfoData modInfo + if !done { modArgs := append([]string{mod}, modArgsTail...) searchTerm := strings.Join(modArgs, " ") // TODO: Curse search // TODO: how to do interactive choices? automatically assume version? ask mod from list? choose first? - fmt.Println(searchTerm) + results, err := getSearch(searchTerm) + if err != nil { + return cli.NewExitError(err, 1) + } + + if len(results) == 0 { + return cli.NewExitError(errors.New("no mods found"), 1) + } else if len(results) == 1 { + modInfoData = results[0] + modID = modInfoData.ID + modInfoObtained = true + done = true + } else { + // Find the closest value to the search term + searchIndex := 0 + currDistance := levenshtein.ComputeDistance(searchTerm, results[0].Name) + for i := 1; i < len(results)-1; i++ { + newDist := levenshtein.ComputeDistance(searchTerm, results[i].Name) + if newDist < currDistance { + searchIndex = i + currDistance = newDist + } + } + + menu := wmenu.NewMenu("Choose a number:") + + for i, v := range results { + menu.Option(v.Name, v, i == searchIndex, nil) + } + menu.Option("Cancel", nil, false, nil) + + menu.Action(func(menuRes []wmenu.Opt) error { + if len(menuRes) != 1 || menuRes[0].Value == nil { + fmt.Println("Cancelled!") + return nil + } + modInfoData, ok := menuRes[0].Value.(modInfo) + if !ok { + return errors.New("Error converting interface from wmenu") + } + modID = modInfoData.ID + modInfoObtained = true + done = true + return nil + }) + err = menu.Run() + if err != nil { + return cli.NewExitError(err, 1) + } + + if !done { + return nil + } + } } if !done { @@ -174,12 +232,14 @@ func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error { // TODO: get FileID if it isn't there fmt.Println(mcVersion) - modInfo, err := getModInfo(modID) - if err != nil { - return cli.NewExitError(err, 1) + if !modInfoObtained { + modInfoData, err = getModInfo(modID) + if err != nil { + return cli.NewExitError(err, 1) + } } - fmt.Println(modInfo) + fmt.Println(modInfoData) _ = index if fileID == 0 { @@ -192,7 +252,7 @@ func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error { return cli.NewExitError(err, 1) } - err = createModFile(flags, modInfo, fileInfo) + err = createModFile(flags, modInfoData, fileInfo) if err != nil { return cli.NewExitError(err, 1) } diff --git a/curseforge/request.go b/curseforge/request.go index 8cea222..8d9e659 100644 --- a/curseforge/request.go +++ b/curseforge/request.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/http" + "net/url" "strconv" "strings" "time" @@ -251,3 +252,31 @@ func getFileInfo(modID int, fileID int) (modFileInfo, error) { return infoRes, nil } +// TODO: pass gameVersion? +func getSearch(searchText string) ([]modInfo, error) { + var infoRes []modInfo + client := &http.Client{} + + textEscaped := url.QueryEscape(searchText) + + req, err := http.NewRequest("GET", "https://addons-ecs.forgesvc.net/api/v2/addon/search?gameId=432&pageSize=10&categoryId=0§ionId=6&searchFilter="+textEscaped, nil) + if err != nil { + return []modInfo{}, err + } + + // TODO: make this configurable application-wide + req.Header.Set("User-Agent", "comp500/packwiz client") + req.Header.Set("Accept", "application/json") + + resp, err := client.Do(req) + if err != nil { + return []modInfo{}, err + } + + err = json.NewDecoder(resp.Body).Decode(&infoRes) + if err != nil && err != io.EOF { + return []modInfo{}, err + } + + return infoRes, nil +} diff --git a/go.mod b/go.mod index d96abfa..a334841 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,18 @@ module github.com/comp500/packwiz require ( github.com/BurntSushi/toml v0.3.1 - github.com/manifoldco/promptui v0.3.2 // indirect + github.com/agnivade/levenshtein v1.0.2 + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/daviddengcn/go-colortext v0.0.0-20180409174941-186a3d44e920 // indirect + github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450 // indirect + github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995 // indirect + github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e // indirect + github.com/mattn/go-isatty v0.0.4 // indirect github.com/mitchellh/mapstructure v1.1.2 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.2.2 // indirect github.com/urfave/cli v1.20.0 github.com/vbauerster/mpb/v4 v4.7.0 + gopkg.in/dixonwille/wlog.v2 v2.0.0 // indirect + gopkg.in/dixonwille/wmenu.v4 v4.0.2 ) diff --git a/go.sum b/go.sum index 4bc8942..cc88358 100644 --- a/go.sum +++ b/go.sum @@ -2,34 +2,26 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= -github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/agnivade/levenshtein v1.0.2 h1:xKF7WlEzoa+ZVkzBxy0ukdzI2etYiWGlTPMNTBGncKI= +github.com/agnivade/levenshtein v1.0.2/go.mod h1:JLvzGblJATanj48SD0YhHTEFGkWvw3ASLFWSiMIFXsE= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= -github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= -github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= -github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= -github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/manifoldco/promptui v0.3.2 h1:rir7oByTERac6jhpHUPErHuopoRDvO3jxS+FdadEns8= -github.com/manifoldco/promptui v0.3.2/go.mod h1:8JU+igZ+eeiiRku4T5BjtKh2ms8sziGpSYl1gN8Bazw= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/daviddengcn/go-colortext v0.0.0-20180409174941-186a3d44e920 h1:d/cVoZOrJPJHKH1NdeUjyVAWKp4OpOT+Q+6T1sH7jeU= +github.com/daviddengcn/go-colortext v0.0.0-20180409174941-186a3d44e920/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450 h1:7xqw01UYS+KCI25bMrPxwNYkSns2Db1ziQPpVq99FpE= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995 h1:f5gsjBiF9tRRVomCvrkGMMWI8W1f2OBFar2c5oakAP0= +github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e h1:KhcknUwkWHKZPbFy2P7jH5LKJ3La+0ZeknkkmrSgqb0= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vbauerster/mpb/v4 v4.7.0 h1:Et+zVewxG6qmfBf4Ez+nDhLbCSh6WhZrUPHg9a6e+hw= @@ -37,13 +29,13 @@ github.com/vbauerster/mpb/v4 v4.7.0/go.mod h1:ugxYn2kSUrY10WK5CWDUZvQxjdwKFN9K3J golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 h1:cGjJzUd8RgBw428LXP65YXni0aiGNA4Bl+ls8SmLOm8= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20181122213734-04b5d21e00f1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/dixonwille/wlog.v2 v2.0.0 h1:TbGWtD8ahWVSihKKr+z2Dw7Cv/7IrfN6dwrcrre17pU= +gopkg.in/dixonwille/wlog.v2 v2.0.0/go.mod h1:JYQHRnhGPLno/iATOiGkEXoRanJXqdz9Qo6/QwfARUc= +gopkg.in/dixonwille/wmenu.v4 v4.0.2 h1:QZVHQatLr41TOvVWiNGdwGk2DYtGEljtuxyrEdR0JIQ= +gopkg.in/dixonwille/wmenu.v4 v4.0.2/go.mod h1:qgH60HxGljYu/uXZW8ctlQ8nIf5mhmraJ3Vsksexnqk=