diff --git a/cmd/install.go b/cmd/install.go index 21ae1d7..acd4399 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -5,12 +5,11 @@ import ( "os" "os/exec" "path" - "runtime" "strings" "github.com/spf13/cobra" - utils "betterdiscord/cli/utils" + utils "github.com/betterdiscord/cli/utils" ) func init() { @@ -25,7 +24,7 @@ var installCmd = &cobra.Command{ Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Run: func(cmd *cobra.Command, args []string) { var releaseChannel = args[0] - var targetExe = "s" + var targetExe = "" switch releaseChannel { case "stable": targetExe = "Discord.exe" @@ -92,67 +91,17 @@ var installCmd = &cobra.Command{ } // Inject shim loader - var discordPath = utils.DiscordPath(releaseChannel) - var appPath = path.Join(discordPath, "app") - if err := os.MkdirAll(appPath, 0755); err != nil { - fmt.Println("Could not create app folder") - return - } + var corePath = utils.DiscordPath(releaseChannel) - var pkgPath = path.Join(appPath, "package.json") - var indPath = path.Join(appPath, "index.js") - const adpString = `{"name":"betterdiscord","main":"index.js"}` - const ddcString = `{"name":"discord_desktop_core","version":"0.0.0","private":"true","main":"index.js"}` - var pkgString = adpString var indString = `require("` + asarPath + `");` indString = strings.ReplaceAll(indString, `\`, "/") + indString = indString + "\nmodule.exports = require(\"./core.asar\");" - if runtime.GOOS == "linux" { - pkgString = ddcString - indString = indString + `\nmodule.exports = require("./core.asar")` - } - - if err := os.WriteFile(pkgPath, []byte(pkgString), 0755); err != nil { - fmt.Println("Could not write package.json") + if err := os.WriteFile(path.Join(corePath, "index.js"), []byte(indString), 0755); err != nil { + fmt.Println("Could not write index.js in discord_desktop_core!") return } - if err := os.WriteFile(indPath, []byte(indString), 0755); err != nil { - fmt.Println("Could not write index.js") - return - } - - // Rename Asar - if runtime.GOOS != "linux" { - var appAsarPath = path.Join(discordPath, "app.asar") - var disAsarPath = path.Join(discordPath, "discord.asar") - var appAsarExists = utils.Exists(appAsarPath) - var disAsarExists = utils.Exists(disAsarPath) - - // If neither exists, something is really wrong - if !appAsarExists && !disAsarExists { - fmt.Println("Discord installation corrupt") - return - } - - // If both exist, get rid of previously renamed asar as outdated - if appAsarExists && disAsarExists { - if err := os.Remove(disAsarPath); err != nil { - fmt.Println("Could not delete discord.asar, is Discord running?") - return - } - } - - // If the app asar exists, rename it. This will also handle cases from - // above where both existed so do not make this an else or !disAsarExists - if appAsarExists { - if err := os.Rename(appAsarPath, disAsarPath); err != nil { - fmt.Println("Could not rename app.asar, is Discord running?") - return - } - } - } - // Launch Discord if we killed it if len(exe) > 0 { var cmd = exec.Command(exe) diff --git a/cmd/root.go b/cmd/root.go index cd47750..57d70c6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,9 +14,7 @@ func init() { var rootCmd = &cobra.Command{ Use: "bdcli", Short: "CLI for managing BetterDiscord", - Long: `A Fast and Flexible Static Site Generator built with - love by spf13 and friends in Go. - Complete documentation is available at http://hugo.spf13.com`, + Long: `A cross-platform CLI for installing, updating, and managing BetterDiscord.`, Run: func(cmd *cobra.Command, args []string) { // Do Stuff Here }, diff --git a/cmd/uninstall.go b/cmd/uninstall.go new file mode 100644 index 0000000..e3084dc --- /dev/null +++ b/cmd/uninstall.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "path" + + "github.com/spf13/cobra" + + utils "github.com/betterdiscord/cli/utils" +) + +func init() { + rootCmd.AddCommand(uninstallCmd) +} + +var uninstallCmd = &cobra.Command{ + Use: "uninstall ", + Short: "Uninstalls BetterDiscord from your Discord", + Long: "This can uninstall BetterDiscord to multiple versions and paths of Discord at once. Options for channel are: stable, canary, ptb", + ValidArgs: []string{"canary", "stable", "ptb"}, + Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), + Run: func(cmd *cobra.Command, args []string) { + var releaseChannel = args[0] + var corePath = utils.DiscordPath(releaseChannel) + var indString = "module.exports = require(\"./core.asar\");" + + if err := os.WriteFile(path.Join(corePath, "index.js"), []byte(indString), 0755); err != nil { + fmt.Println("Could not write index.js in discord_desktop_core!") + return + } + + var targetExe = "" + switch releaseChannel { + case "stable": + targetExe = "Discord.exe" + break + case "canary": + targetExe = "DiscordCanary.exe" + break + case "ptb": + targetExe = "DiscordPTB.exe" + break + default: + targetExe = "" + } + + // Kill Discord if it's running + var exe = utils.GetProcessExe(targetExe) + if len(exe) > 0 { + if err := utils.KillProcess(targetExe); err != nil { + fmt.Println("Could not kill Discord") + return + } + } + + // Launch Discord if we killed it + if len(exe) > 0 { + var cmd = exec.Command(exe) + cmd.Start() + } + }, +} diff --git a/go.mod b/go.mod index 0b5e92d..35487de 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module betterdiscord/cli +module github.com/betterdiscord/cli go 1.19 diff --git a/main.go b/main.go index 6aebd9b..fd486d0 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main import ( - "betterdiscord/cli/cmd" + "github.com/betterdiscord/cli/cmd" ) func main() { diff --git a/package-lock.json b/package-lock.json index 18d3147..6d86453 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@betterdiscord/cli", - "version": "0.0.1-alpha", + "version": "0.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@betterdiscord/cli", - "version": "0.0.1-alpha", + "version": "0.1.0", "license": "Apache-2.0", "dependencies": { "@go-task/go-npm": "^0.1.17" diff --git a/package.json b/package.json index 6fb5961..208bf56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@betterdiscord/cli", - "version": "0.0.1-beta", + "version": "0.1.0", "description": "A cross-platform CLI for managing BetterDiscord", "main": "index.js", "publishConfig": { diff --git a/utils/paths.go b/utils/paths.go index 818bd9b..590a5c7 100644 --- a/utils/paths.go +++ b/utils/paths.go @@ -1,9 +1,11 @@ package utils import ( + "io/fs" "os" "path" "runtime" + "sort" "strings" ) @@ -49,74 +51,76 @@ func ValidatePath(proposed string) string { switch op := runtime.GOOS; op { case "windows": return validateWindows(proposed) - case "darwin": - return validateMac(proposed) - case "linux": - return validateLinux(proposed) + case "darwin","linux": + return validateMacLinux(proposed) default: return "" } } + +func Filter[T any](source []T, filterFunc func(T) bool) (ret []T) { + var returnArray = []T{} + for _, s := range source { + if filterFunc(s) { + returnArray = append(ret, s) + } + } + return returnArray +} + + func validateWindows(proposed string) string { var finalPath = "" var selected = path.Base(proposed) if strings.HasPrefix(selected, "Discord") { + + // Get version dir like 1.0.9002 var dFiles, err = os.ReadDir(proposed) if err != nil { return "" } - var appDir = "" - for _, file := range dFiles { - if !file.IsDir() || !strings.HasPrefix(file.Name(), "app-") { - continue - } - if file.Name() > appDir { - appDir = file.Name() - } + + var candidates = Filter(dFiles, func(file fs.DirEntry) bool { return file.IsDir() && len(strings.Split(file.Name(), ".")) == 3 }) + sort.Slice(candidates, func(i, j int) bool { return candidates[i].Name() < candidates[j].Name() }) + var versionDir = candidates[len(candidates)-1].Name() + + // Get core wrap like discord_desktop_core-1 + dFiles, err = os.ReadDir(path.Join(proposed, versionDir, "modules")) + if err != nil { + return "" } - finalPath = path.Join(proposed, appDir, "resources") + candidates = Filter(dFiles, func(file fs.DirEntry) bool { return file.IsDir() && strings.HasPrefix(file.Name(), "discord_desktop_core") }) + var coreWrap = candidates[len(candidates)-1].Name() + + finalPath = path.Join(proposed, versionDir, "modules", coreWrap, "discord_desktop_core") } // Use a separate if statement because forcing same-line } else if { is gross if strings.HasPrefix(proposed, "app-") { - finalPath = path.Join(proposed, "resources") + var dFiles, err = os.ReadDir(path.Join(proposed, "modules")) + if err != nil { + return "" + } + var candidates = Filter(dFiles, func(file fs.DirEntry) bool { return file.IsDir() && strings.HasPrefix(file.Name(), "discord_desktop_core") }) + var coreWrap = candidates[len(candidates)-1].Name() + finalPath = path.Join(proposed, coreWrap, "discord_desktop_core") } - if selected == "resources" { + if selected == "discord_desktop_core" { finalPath = proposed } - if Exists(finalPath) { + // If the path and the asar exist, all good + if Exists(finalPath) && Exists(path.Join(finalPath, "core.asar")) { return finalPath } return "" } -func validateMac(proposed string) string { - var finalPath = "" - var selected = path.Base(proposed) - if strings.HasPrefix(selected, "Discord") && strings.HasSuffix(selected, ".app") { - finalPath = path.Join(proposed, "Contents", "Resources") - } - - if selected == "Contents" { - finalPath = path.Join(proposed, "Resources") - } - - if selected == "Resources" { - finalPath = proposed - } - - if Exists(finalPath) { - return finalPath - } - - return "" -} -func validateLinux(proposed string) string { +func validateMacLinux(proposed string) string { if strings.Contains(proposed, "/snap") { return "" } @@ -124,23 +128,19 @@ func validateLinux(proposed string) string { var finalPath = "" var selected = path.Base(proposed) if strings.HasPrefix(selected, "discord") { + // Get version dir like 1.0.9002 var dFiles, err = os.ReadDir(proposed) if err != nil { return "" } - var versionDir = "" - for _, file := range dFiles { - if split := strings.Split(file.Name(), "."); !file.IsDir() || len(split) != 3 { - continue - } - if file.Name() > versionDir { - versionDir = file.Name() - } - } + + var candidates = Filter(dFiles, func(file fs.DirEntry) bool { return file.IsDir() && len(strings.Split(file.Name(), ".")) == 3 }) + sort.Slice(candidates, func(i, j int) bool { return candidates[i].Name() < candidates[j].Name() }) + var versionDir = candidates[len(candidates)-1].Name() finalPath = path.Join(proposed, versionDir, "modules", "discord_desktop_core") } - if split := strings.Split(selected, "."); len(split) == 3 { + if len(strings.Split(selected, ".")) == 3 { finalPath = path.Join(proposed, "modules", "discord_desktop_core") } @@ -152,7 +152,7 @@ func validateLinux(proposed string) string { finalPath = proposed } - if Exists(finalPath) { + if Exists(finalPath) && Exists(path.Join(finalPath, "core.asar")) { return finalPath }