Command to open page in browser; refactoring

This commit is contained in:
comp500
2019-06-14 22:35:34 +01:00
parent ebc2115b41
commit 91693cd3eb
6 changed files with 208 additions and 159 deletions

View File

@@ -1,18 +1,14 @@
package curseforge
import (
"errors"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"github.com/agnivade/levenshtein"
"github.com/comp500/packwiz/core"
"github.com/mitchellh/mapstructure"
"github.com/skratchdot/open-golang/open"
"github.com/urfave/cli"
"gopkg.in/dixonwille/wmenu.v4"
)
func init() {
@@ -32,6 +28,13 @@ func init() {
Action: func(c *cli.Context) error {
return cmdImport(core.FlagsFromContext(c), c.Args().Get(0))
},
}, {
Name: "open",
Usage: "Open the project page for a curseforge mod in your browser",
Aliases: []string{"doc"},
Action: func(c *cli.Context) error {
return cmdDoc(core.FlagsFromContext(c), c.Args().Get(0))
},
}},
})
core.UpdateParsers["curseforge"] = cfUpdateParser{}
@@ -135,167 +138,26 @@ func createModFile(flags core.Flags, modInfo modInfo, fileInfo modFileInfo, inde
return index.RefreshFileWithHash(path, format, hash, true)
}
func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error {
func cmdDoc(flags core.Flags, mod string) error {
if len(mod) == 0 {
return cli.NewExitError("You must specify a mod.", 1)
}
pack, err := core.LoadPack(flags)
modData, err := core.LoadMod(core.ResolveMod(mod, flags))
if err != nil {
return cli.NewExitError(err, 1)
}
index, err := pack.LoadIndex()
updateData, ok := modData.GetParsedUpdater("curseforge")
if !ok {
return cli.NewExitError("This mod doesn't seem to be a curseforge mod!", 1)
}
cfUpdateData := updateData.(cfUpdater)
url := "https://minecraft.curseforge.com/projects/" + strconv.Itoa(cfUpdateData.ProjectID)
err = open.Start(url)
if err != nil {
return cli.NewExitError(err, 1)
fmt.Println("Opening page failed, direct link:")
fmt.Println(url)
}
mcVersion, err := pack.GetMCVersion()
if err != nil {
return cli.NewExitError(err, 1)
}
var done bool
var modID, fileID int
// If modArgsTail has anything, go straight to searching - URLs/Slugs should not have spaces!
if len(modArgsTail) == 0 {
done, modID, fileID, err = getFileIDsFromString(mod)
if err != nil {
return cli.NewExitError(err, 1)
}
if !done {
done, modID, err = getModIDFromString(mod)
// Ignore error, go to search instead (e.g. lowercase to search instead of as a slug)
if err != nil {
done = false
}
}
}
modInfoObtained := false
var modInfoData modInfo
if !done {
fmt.Println("Searching CurseForge...")
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?
results, err := getSearch(searchTerm, mcVersion)
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
sort.Slice(results, func(i, j int) bool {
return levenshtein.ComputeDistance(searchTerm, results[i].Name) < levenshtein.ComputeDistance(searchTerm, results[j].Name)
})
menu := wmenu.NewMenu("Choose a number:")
for i, v := range results {
menu.Option(v.Name, v, i == 0, 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
}
// Why is variable shadowing a thing!!!!
var ok bool
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 {
if err == nil {
err = errors.New("Mod not found")
}
return cli.NewExitError(err, 1)
}
if !modInfoObtained {
modInfoData, err = getModInfo(modID)
if err != nil {
return cli.NewExitError(err, 1)
}
}
fileInfoObtained := false
var fileInfoData modFileInfo
if fileID == 0 {
// TODO: how do we decide which version to use?
for _, v := range modInfoData.GameVersionLatestFiles {
// Choose "newest" version by largest ID
if v.GameVersion == mcVersion && v.ID > fileID {
fileID = v.ID
}
}
if fileID == 0 {
return cli.NewExitError(errors.New("no files available for current Minecraft version"), 1)
}
// The API also provides some files inline, because that's efficient!
for _, v := range modInfoData.LatestFiles {
if v.ID == fileID {
fileInfoObtained = true
fileInfoData = v
}
}
}
if !fileInfoObtained {
fileInfoData, err = getFileInfo(modID, fileID)
if err != nil {
return cli.NewExitError(err, 1)
}
}
err = createModFile(flags, modInfoData, fileInfoData, &index)
if err != nil {
return cli.NewExitError(err, 1)
}
err = index.Write()
if err != nil {
return cli.NewExitError(err, 1)
}
err = pack.UpdateIndexHash()
if err != nil {
return cli.NewExitError(err, 1)
}
err = pack.Write()
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Printf("Mod \"%s\" successfully installed! (%s)\n", modInfoData.Name, fileInfoData.FileName)
return nil
}

177
curseforge/install.go Normal file
View File

@@ -0,0 +1,177 @@
package curseforge
import (
"fmt"
"sort"
"strings"
"github.com/agnivade/levenshtein"
"github.com/comp500/packwiz/core"
"github.com/urfave/cli"
"gopkg.in/dixonwille/wmenu.v4"
)
func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error {
if len(mod) == 0 {
return cli.NewExitError("You must specify a mod.", 1)
}
pack, err := core.LoadPack(flags)
if err != nil {
return cli.NewExitError(err, 1)
}
index, err := pack.LoadIndex()
if err != nil {
return cli.NewExitError(err, 1)
}
mcVersion, err := pack.GetMCVersion()
if err != nil {
return cli.NewExitError(err, 1)
}
var done bool
var modID, fileID int
// If modArgsTail has anything, go straight to searching - URLs/Slugs should not have spaces!
if len(modArgsTail) == 0 {
done, modID, fileID, err = getFileIDsFromString(mod)
if err != nil {
return cli.NewExitError(err, 1)
}
if !done {
done, modID, err = getModIDFromString(mod)
// Ignore error, go to search instead (e.g. lowercase to search instead of as a slug)
if err != nil {
done = false
}
}
}
modInfoObtained := false
var modInfoData modInfo
if !done {
fmt.Println("Searching CurseForge...")
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?
results, err := getSearch(searchTerm, mcVersion)
if err != nil {
return cli.NewExitError(err, 1)
}
if len(results) == 0 {
return cli.NewExitError("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
sort.Slice(results, func(i, j int) bool {
return levenshtein.ComputeDistance(searchTerm, results[i].Name) < levenshtein.ComputeDistance(searchTerm, results[j].Name)
})
menu := wmenu.NewMenu("Choose a number:")
for i, v := range results {
menu.Option(v.Name, v, i == 0, 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
}
// Why is variable shadowing a thing!!!!
var ok bool
modInfoData, ok = menuRes[0].Value.(modInfo)
if !ok {
return cli.NewExitError("Error converting interface from wmenu", 1)
}
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 {
if err == nil {
return cli.NewExitError("No mods found!", 1)
}
return cli.NewExitError(err, 1)
}
if !modInfoObtained {
modInfoData, err = getModInfo(modID)
if err != nil {
return cli.NewExitError(err, 1)
}
}
fileInfoObtained := false
var fileInfoData modFileInfo
if fileID == 0 {
// TODO: how do we decide which version to use?
for _, v := range modInfoData.GameVersionLatestFiles {
// Choose "newest" version by largest ID
if v.GameVersion == mcVersion && v.ID > fileID {
fileID = v.ID
}
}
if fileID == 0 {
return cli.NewExitError("No files available for current Minecraft version!", 1)
}
// The API also provides some files inline, because that's efficient!
for _, v := range modInfoData.LatestFiles {
if v.ID == fileID {
fileInfoObtained = true
fileInfoData = v
}
}
}
if !fileInfoObtained {
fileInfoData, err = getFileInfo(modID, fileID)
if err != nil {
return cli.NewExitError(err, 1)
}
}
err = createModFile(flags, modInfoData, fileInfoData, &index)
if err != nil {
return cli.NewExitError(err, 1)
}
err = index.Write()
if err != nil {
return cli.NewExitError(err, 1)
}
err = pack.UpdateIndexHash()
if err != nil {
return cli.NewExitError(err, 1)
}
err = pack.Write()
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Printf("Mod \"%s\" successfully installed! (%s)\n", modInfoData.Name, fileInfoData.FileName)
return nil
}