diff --git a/curseforge/install.go b/curseforge/install.go index 4c5bf55..b9a292b 100644 --- a/curseforge/install.go +++ b/curseforge/install.go @@ -417,7 +417,7 @@ func getLatestFile(modInfoData modInfo, mcVersions []string, fileID uint32, pack // Possible to reach this point without obtaining file info; particularly from GameVersionLatestFiles if fileID == 0 { - return modFileInfo{}, errors.New("mod not available for the configured Minecraft version(s) (use the acceptable-game-versions option to accept more) or loader") + return modFileInfo{}, errors.New("mod not available for the configured Minecraft version(s) (use the 'packwiz settings acceptable-versions' command to accept more) or loader") } } diff --git a/main.go b/main.go index 0a94e1d..33cc24c 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "github.com/packwiz/packwiz/cmd" _ "github.com/packwiz/packwiz/curseforge" _ "github.com/packwiz/packwiz/modrinth" + _ "github.com/packwiz/packwiz/settings" _ "github.com/packwiz/packwiz/url" _ "github.com/packwiz/packwiz/utils" ) diff --git a/modrinth/install.go b/modrinth/install.go index ffac0df..7dac2a5 100644 --- a/modrinth/install.go +++ b/modrinth/install.go @@ -205,7 +205,7 @@ func installProject(project *modrinthApi.Project, versionFilename string, pack c return fmt.Errorf("failed to get latest version: %v", err) } if latestVersion.ID == nil { - return errors.New("mod not available for the configured Minecraft version(s) (use the acceptable-game-versions option to accept more) or loader") + return errors.New("mod not available for the configured Minecraft version(s) (use the 'packwiz settings acceptable-versions' command to accept more) or loader") } return installVersion(project, latestVersion, versionFilename, pack, index) diff --git a/modrinth/modrinth.go b/modrinth/modrinth.go index 4ff74ec..7239c3c 100644 --- a/modrinth/modrinth.go +++ b/modrinth/modrinth.go @@ -287,7 +287,7 @@ func getLatestVersion(projectID string, name string, pack core.Pack) (*modrinthA } if len(result) == 0 { // TODO: retry with datapack specified, to determine what the issue is? or just request all and filter afterwards - return nil, errors.New("no valid versions found\n\tUse the acceptable-game-versions option to accept more game versions\n\tTo use datapacks, add a datapack loader mod and specify the datapack-folder option with the folder this mod loads datapacks from") + return nil, errors.New("no valid versions found\n\tUse the 'packwiz settings acceptable-versions' command to accept more game versions\n\tTo use datapacks, add a datapack loader mod and specify the datapack-folder option with the folder this mod loads datapacks from") } // TODO: option to always compare using flexver? diff --git a/settings/acceptable_versions.go b/settings/acceptable_versions.go new file mode 100644 index 0000000..c4da35f --- /dev/null +++ b/settings/acceptable_versions.go @@ -0,0 +1,147 @@ +package settings + +import ( + "fmt" + "github.com/packwiz/packwiz/cmdshared" + "github.com/packwiz/packwiz/core" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/unascribed/FlexVer/go/flexver" + "golang.org/x/exp/slices" + "os" + "strings" +) + +var acceptableVersionsCommand = &cobra.Command{ + Use: "acceptable-versions", + Short: "Manage your pack's acceptable Minecraft versions. This must be a comma seperated list of Minecraft versions, e.g. 1.16.3,1.16.4,1.16.5", + Aliases: []string{"av"}, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + modpack, err := core.LoadPack() + if err != nil { + // Check if it's a no such file or directory error + if os.IsNotExist(err) { + fmt.Println("No pack.toml file found, run 'packwiz init' to create one!") + os.Exit(1) + } + fmt.Printf("Error loading pack: %s\n", err) + os.Exit(1) + } + var currentVersions []string + // Check if they have no options whatsoever + if modpack.Options == nil { + // Initialize the options + modpack.Options = make(map[string]interface{}) + } + // Check if the acceptable-game-versions is nil, which would mean their pack.toml doesn't have it set yet + if modpack.Options["acceptable-game-versions"] != nil { + // Convert the interface{} to a string slice + for _, v := range modpack.Options["acceptable-game-versions"].([]interface{}) { + currentVersions = append(currentVersions, v.(string)) + } + } + // Check our flags to see if we're adding or removing + if viper.GetBool("settings.acceptable-versions.add") { + // Adding + acceptableVersion := args[0] + // Check if the version is already in the list + if slices.Contains(currentVersions, acceptableVersion) { + fmt.Printf("Version %s is already in your acceptable versions list!\n", acceptableVersion) + os.Exit(1) + } + // Add the version to the list and re-sort it + currentVersions = append(currentVersions, acceptableVersion) + flexver.VersionSlice(currentVersions).Sort() + // Set the new list + modpack.Options["acceptable-game-versions"] = currentVersions + // Save the pack + err = modpack.Write() + if err != nil { + fmt.Printf("Error writing pack: %s\n", err) + os.Exit(1) + } + // Print success message + prettyList := strings.Join(currentVersions, ", ") + fmt.Printf("Added %s to acceptable versions list, now %s\n", acceptableVersion, prettyList) + } else if viper.GetBool("settings.acceptable-versions.remove") { + // Removing + acceptableVersion := args[0] + // Check if the version is in the list + if !slices.Contains(currentVersions, acceptableVersion) { + fmt.Printf("Version %s is not in your acceptable versions list!\n", acceptableVersion) + os.Exit(1) + } + // Remove the version from the list + i := slices.Index(currentVersions, acceptableVersion) + currentVersions = slices.Delete(currentVersions, i, i+1) + // Sort it just in case it's out of order + flexver.VersionSlice(currentVersions).Sort() + // Set the new list + modpack.Options["acceptable-game-versions"] = currentVersions + // Save the pack + err = modpack.Write() + if err != nil { + fmt.Printf("Error writing pack: %s\n", err) + os.Exit(1) + } + // Print success message + prettyList := strings.Join(currentVersions, ", ") + fmt.Printf("Removed %s from acceptable versions list, now %s\n", acceptableVersion, prettyList) + } else { + // Overwriting + acceptableVersions := args[0] + acceptableVersionsList := strings.Split(acceptableVersions, ",") + // Dedupe the list + acceptableVersionsDeduped := []string(nil) + for i, v := range acceptableVersionsList { + if !slices.Contains(acceptableVersionsList[i+1:], v) { + acceptableVersionsDeduped = append(acceptableVersionsDeduped, v) + } + } + // Check if the list of versions is out of order, lowest to highest, and inform the user if it is + // Compare the versions one by one to the next one, if the next one is lower, then it's out of order + // If it's only 1 element long, then it's already sorted + if len(acceptableVersionsDeduped) > 1 { + for i, v := range acceptableVersionsDeduped { + if flexver.Less(acceptableVersionsDeduped[i+1], v) { + fmt.Printf("Warning: Your acceptable versions list is out of order. ") + // Give a do you mean example + // Clone the list + acceptableVersionsDedupedClone := make([]string, len(acceptableVersionsDeduped)) + copy(acceptableVersionsDedupedClone, acceptableVersionsDeduped) + flexver.VersionSlice(acceptableVersionsDedupedClone).Sort() + fmt.Printf("Did you mean %s?\n", strings.Join(acceptableVersionsDedupedClone, ", ")) + if cmdshared.PromptYesNo("Would you like to fix this automatically? [Y/n] ") { + // If yes we'll just set the list to the sorted one + acceptableVersionsDeduped = acceptableVersionsDedupedClone + break + } else { + // If no we'll just continue + break + } + } + } + } + modpack.Options["acceptable-game-versions"] = acceptableVersionsDeduped + err = modpack.Write() + if err != nil { + fmt.Printf("Error writing pack: %s\n", err) + os.Exit(1) + } + // Print success message + prettyList := strings.Join(acceptableVersionsDeduped, ", ") + fmt.Printf("Set acceptable versions to %s\n", prettyList) + } + }, +} + +func init() { + settingsCmd.AddCommand(acceptableVersionsCommand) + + // Add and remove flags for adding or removing specific versions + acceptableVersionsCommand.Flags().BoolP("add", "a", false, "Add a version to the list") + acceptableVersionsCommand.Flags().BoolP("remove", "r", false, "Remove a version from the list") + _ = viper.BindPFlag("settings.acceptable-versions.add", acceptableVersionsCommand.Flags().Lookup("add")) + _ = viper.BindPFlag("settings.acceptable-versions.remove", acceptableVersionsCommand.Flags().Lookup("remove")) +} diff --git a/settings/settings.go b/settings/settings.go new file mode 100644 index 0000000..1238726 --- /dev/null +++ b/settings/settings.go @@ -0,0 +1,16 @@ +package settings + +import ( + "github.com/packwiz/packwiz/cmd" + "github.com/spf13/cobra" +) + +// settingsCmd represents the base command when called without any subcommands +var settingsCmd = &cobra.Command{ + Use: "settings", + Short: "Manage pack settings", +} + +func init() { + cmd.Add(settingsCmd) +}