diff --git a/.gitignore b/.gitignore index 830b2d9..aea2951 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ *.so *.dylib -r2mod-go +r2go main # Test binary, built with `go test -c` diff --git a/api/api.go b/api/api.go index b1b8256..5b6ef40 100644 --- a/api/api.go +++ b/api/api.go @@ -4,10 +4,15 @@ import ( "encoding/json" "io/ioutil" "os" - "r2mod-go/utils" + "r2go/utils" "time" + + "github.com/lithammer/fuzzysearch/fuzzy" ) +// PkgList contains all mods in current package cache +var PkgList []Mod + // Mod contains info about a mod from thunderstore API type Mod struct { Name string `json:"name"` @@ -40,6 +45,11 @@ type Version struct { UUID4 string `json:"uuid4"` } +// InitAPI stores the API in an object when needed. +func InitAPI() { + PkgList = UnpackAPI() +} + // CheckAPICache checks if the cached json is expired func CheckAPICache() int { if !utils.PathExists(utils.SystemInfo.TmpDir + "/pkg.json") { @@ -67,7 +77,8 @@ func UpdateAPICache() { utils.CheckErr(err) } -func unpackAPI() []Mod { +// UnpackAPI stores the API cache as an object for later use. +func UnpackAPI() []Mod { pkgFile, err := os.Open(utils.SystemInfo.TmpDir + "/pkg.json") utils.CheckErr(err) @@ -84,8 +95,18 @@ func unpackAPI() []Mod { return mods } -// PkgList contains all mods in current package cache -var PkgList []Mod = unpackAPI() +// SearchMods finds mods that match a fuzzy search +func SearchMods(inp string) fuzzy.Ranks { + var pkgNames []string + + for _, mod := range PkgList { + pkgNames = append(pkgNames, mod.FullName) + } + + results := fuzzy.RankFindFold(inp, pkgNames) + + return results +} // GetModData gets object of mod by depString func GetModData(depString string) Mod { @@ -93,12 +114,11 @@ func GetModData(depString string) Mod { depString = "tristanmcpherson-R2API" } - var selectedMod Mod for i := 0; i < len(PkgList); i++ { if PkgList[i].FullName == depString { - selectedMod = PkgList[i] + return PkgList[i] } } - return selectedMod + panic("Mod not found") } diff --git a/go.mod b/go.mod index adba380..d3618d7 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,8 @@ -module r2mod-go +module r2go go 1.15 -require github.com/fatih/color v1.10.0 +require ( + github.com/fatih/color v1.10.0 + github.com/lithammer/fuzzysearch v1.1.1 +) diff --git a/go.sum b/go.sum index 9ee68f3..23bbdbe 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/lithammer/fuzzysearch v1.1.1 h1:8F9OAV2xPuYblToVohjanztdnPjbtA0MLgMvDKQ0Z08= +github.com/lithammer/fuzzysearch v1.1.1/go.mod h1:H2bng+w5gsR7NlfIJM8ElGZI0sX6C/9uzGqicVXGU6c= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= @@ -7,3 +9,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/main.go b/main.go index fcc7917..ebbd2fe 100644 --- a/main.go +++ b/main.go @@ -5,13 +5,50 @@ import ( "io/ioutil" "log" "os" - "r2mod-go/api" - "r2mod-go/tools" - "r2mod-go/utils" + "r2go/api" + "r2go/tools" + "r2go/utils" + "strings" "github.com/fatih/color" ) +var version string = "0.0.1" + +func downloadMod(pkg string) { + buffer := fmt.Sprint(" > ", tools.ExposeModString(pkg), "... ") + stat, ov := tools.DownloadMod(tools.ExposeModString(pkg)) + + green := color.New(color.FgGreen).SprintFunc() + magenta := color.New(color.FgMagenta).SprintFunc() + blue := color.New(color.FgBlue).SprintFunc() + + if stat == 1 { + buffer += green("up to date!") + } else if stat == 2 { + buffer += fmt.Sprintf("%s %s", magenta("updating to version"), ov) + } else { + buffer += blue("downloaded") + } + + fmt.Println(buffer) +} + +func removeMod(pkg string) { + blue := color.New(color.FgBlue).SprintFunc() + red := color.New(color.FgRed).SprintFunc() + + buffer := fmt.Sprint(" > ", tools.ExposeModString(pkg), "... ") + + if tools.RemoveMod(tools.ExposeModString(pkg)) == 1 { + buffer += red("not installed") + } else { + buffer += blue("uninstalled") + } + + fmt.Println(buffer) +} + func main() { logFile, err := os.OpenFile(utils.SystemInfo.TmpDir+"/r2mod-go.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) @@ -36,19 +73,21 @@ func main() { switch operation { case "help": - fmt.Println(`Commands: - > info -- get info about a mod - > install, ins, i -- install mod(s) - > remove, rem, r -- remove mod(s) - > list, ls, li -- list mods - > update, upgrade, up -- update mods and API cache - > toggle, tm, togglemods -- toggle mods - > pull -- forcefully update API cache, not mods - > filter -- remove version numbers using regex from stdin - `) + fmt.Println("> Commands:") + fmt.Println(" > info -- get info about a mod") + fmt.Println(" > install, ins, i -- install mod(s)") + fmt.Println(" > remove, rm, r -- remove mod(s)") + fmt.Println(" > list, ls, li -- list mods") + fmt.Println(" > search, s, find -- search mods") + fmt.Println(" > update, upgrade, up -- update mods and API cache") + fmt.Println(" > toggle, tm, togglemods -- toggle mods") + fmt.Println(" > pull -- forcefully update API cache, not mods") + fmt.Println(" > filter -- remove version numbers using regex from stdin") + fmt.Println(" > version, ver, v -- print information about the program") case "info": + api.InitAPI() if len(os.Args) <= 2 { - fmt.Println("Usage: r2mod-go info ") + fmt.Println("Usage: r2go info ") } else { var selectedmod api.Mod = api.GetModData(os.Args[2]) color.Cyan("Mod Info: %s", os.Args[2]) @@ -59,27 +98,15 @@ func main() { } case "install", "ins", "i": api.CheckAPICache() + api.InitAPI() + fmt.Println("> Downloading mods...") for _, m := range os.Args[2:] { - - fmt.Println(" >", tools.ExposeModString(m)) - stat, ov := tools.DownloadMod(tools.ExposeModString(m)) - if stat == 0 { - color.Green(" > Already installed and up to date") - } else if stat == 1 { - color.Magenta(" > Updating to version %s", ov) - } else { - color.Blue(" > Downloaded") - } + downloadMod(m) } - case "remove", "rem", "r": + color.Green("> Complete!") + case "remove", "rm", "r": for _, m := range os.Args[2:] { - fmt.Println(" >", tools.ExposeModString(m)) - - if tools.RemoveMod(tools.ExposeModString(m)) == 1 { - color.Red(" > Not installed") - } else { - color.Blue(" > Uninstalled") - } + removeMod(m) } case "list", "ls", "li": files, err := ioutil.ReadDir(utils.SystemInfo.PluginDir) @@ -92,6 +119,7 @@ func main() { } case "update", "upgrade", "up": color.Cyan("> Checking API Cache") + api.InitAPI() if api.CheckAPICache() == 0 { color.Green("> API Cache is up to date!") } else { @@ -105,20 +133,12 @@ func main() { } for _, f := range files { - fmt.Println(" >", tools.ExposeModString(f.Name())) - stat, ov := tools.DownloadMod(tools.ExposeModString(f.Name())) - if stat == 0 { - color.Green(" > Already installed and up to date") - } else if stat == 1 { - color.Magenta(" > Updating to version %s", ov) - } else { - color.Blue(" > Downloaded") - } - + downloadMod(f.Name()) } - // color.Green("> Complete!") + color.Green("> Complete!") case "pull": + api.InitAPI() color.Cyan("> Checking API Cache") if api.CheckAPICache() == 0 { color.Green("> API Cache is up to date!") @@ -134,6 +154,21 @@ func main() { } case "filter": fmt.Println(tools.ExposeModString(os.Args[2])) + case "version", "ver", "v": + color.Magenta("> r2go", version) + fmt.Println(" > github.com/endigma442") + case "search", "s", "find": + api.InitAPI() + + query := strings.Join(os.Args[2:], "-") + + blue := color.New(color.FgBlue).SprintFunc() + + fmt.Printf("%s %s\n", "Querying API for mods matching:", blue(query)) + + for _, mod := range api.SearchMods(query) { + fmt.Println(" -", mod.Target) + } default: fmt.Println("Unknown command, use 'r2go help' for a list of commands.") } diff --git a/tools/tools.go b/tools/tools.go index a02de51..0271239 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -4,8 +4,8 @@ import ( "io/ioutil" "log" "os" - "r2mod-go/api" - "r2mod-go/utils" + "r2go/api" + "r2go/utils" "regexp" "strings" ) @@ -19,29 +19,36 @@ func ExposeModString(input string) string { // DownloadMod gets the download URL and installs the mod in the correct folder func DownloadMod(depString string) (int, string) { + var status int + var modver string + if depString == "R2API" { depString = "tristanmcpherson-R2API" } sysinfo := utils.GetSysInfo() - downloadURL := api.GetModData(depString).Versions[0].DownloadURL + mod := api.GetModData(depString) + downloadURL := mod.Versions[0].DownloadURL modName := sysinfo.TmpDir + "/dl/" + depString + ".zip" - modVersion := api.GetModData(depString).Versions[0].VersionNumber + modVersion := mod.Versions[0].VersionNumber modFolder := sysinfo.PluginDir + "/" + depString + "-" + modVersion if utils.PathExists(modFolder) { - return 0, "" + return 1, modver } if len(api.GetModData(depString).Versions) >= 2 { - modVersionOld := api.GetModData(depString).Versions[1].VersionNumber + modVersionOld := mod.Versions[1].VersionNumber modFolderOld := sysinfo.PluginDir + "/" + depString + "-" + modVersionOld if utils.PathExists(modFolderOld) { defer os.RemoveAll(modFolderOld) - return 1, modVersion + status = 2 + modver = modVersion + } else { + status = 3 } } @@ -52,7 +59,12 @@ func DownloadMod(depString string) (int, string) { log.Println(unzip) utils.CheckErr(err) - return 2, modVersion + // TODO: Dependencies! + // for i, dep := range { + + // } + + return status, modver } // RemoveMod uninstalls a mod diff --git a/utils/utils.go b/utils/utils.go index bf7aa7e..463321e 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -11,6 +11,9 @@ import ( "strings" ) +// SystemInfo contains information about the user's computer. +var SystemInfo SysInfo = GetSysInfo() + // SysInfo holds information about the user's installation type SysInfo struct { SteamDir string @@ -115,9 +118,6 @@ func GetSysInfo() SysInfo { return SystemInfo } -// SystemInfo contains information about the user's computer. -var SystemInfo SysInfo = GetSysInfo() - // Unzip takes input src and dest, unzips file. func Unzip(src string, dest string) ([]string, error) { var filenames []string