package main import ( "encoding/json" "fmt" "os" "strings" "gopkg.in/yaml.v3" ) type Command struct { Name string Description string Action CommandAction Arguments []string IsVarargs bool } type CommandAction func([]string, []string) (string, error) var commands = []Command{ { Name: "install", Description: "Install one or more mod archives into modman", Arguments: []string{"game name", "archive path"}, IsVarargs: true, Action: func(requiredArguments []string, providedArguments []string) (string, error) { var argumentCount = len(providedArguments) if argumentCount < len(requiredArguments) { return "", fmt.Errorf("expected %s folowed by at least one %ss", requiredArguments[0], requiredArguments[1]) } if gameError := WithGame(providedArguments[0], func(game *Game) error { for _, archivePath := range providedArguments[1:] { if installError := game.InstallMod(archivePath); installError != nil { return installError } } return nil }); gameError != nil { return "", gameError } return "mods installed", nil }, }, { Name: "remove", Description: "Remove one or more mods from modman", Arguments: []string{"game name", "mod name"}, IsVarargs: true, Action: func(requiredArguments []string, providedArguments []string) (string, error) { if len(providedArguments) < len(requiredArguments) { return "", fmt.Errorf("expected %s followed by one or more %ss", requiredArguments[0], requiredArguments[1]) } if gameError := WithGame(providedArguments[0], func(game *Game) error { return game.RemoveMods(providedArguments[1:]) }); gameError != nil { return "", gameError } return "removed mods", nil }, }, { Name: "rename", Description: "Rename a mod within modman", Arguments: []string{"game name", "mod name", "new name"}, IsVarargs: false, Action: func(requiredArguments []string, providedArguments []string) (string, error) { if len(providedArguments) != len(requiredArguments) { return "", fmt.Errorf("expected %s followed by %s and %s", requiredArguments[0], requiredArguments[1], requiredArguments[2]) } if gameError := WithGame(providedArguments[0], func(game *Game) error { if removeError := game.RenameMod(providedArguments[1], providedArguments[2]); removeError != nil { return removeError } return nil }); gameError != nil { return "", gameError } return "", nil }, }, { Name: "manifest", Description: "Retrieve a manifest of all installed mods", Arguments: []string{"game name", "format"}, IsVarargs: false, Action: func(requiredArguments []string, providedArguments []string) (string, error) { if len(providedArguments) != len(requiredArguments) { return "", fmt.Errorf("expected %s followed by %s", requiredArguments[0], requiredArguments[1]) } var modManifest = "" if gameError := WithGame(providedArguments[0], func(game *Game) error { var format = providedArguments[1] var formatter, formatterExists = formatters[format] if !(formatterExists) { return fmt.Errorf("unsupported format: `%s`", format) } var manifestBuilder = strings.Builder{} if formatError := formatter(&manifestBuilder, game.Mods); formatError != nil { return formatError } modManifest = manifestBuilder.String() return nil }); gameError != nil { return "", gameError } return modManifest, nil }, }, { Name: "deploy", Description: "Deploy all specified mods in order of listing", Arguments: []string{"game name", "mod name"}, IsVarargs: true, Action: func(requiredArguments []string, arguments []string) (string, error) { if len(arguments) != len(requiredArguments) { return "", fmt.Errorf("expected %s followed by one or more %ss", requiredArguments[0], requiredArguments[1]) } if gameError := WithGame(arguments[0], func(game *Game) error { if cleanError := game.CleanDeployedMods(); cleanError != nil { return cleanError } for _, modName := range arguments[1:] { if deployError := game.DeployMod(modName); deployError != nil { return deployError } } return nil }); gameError != nil { return "", gameError } return "deployed", nil }, }, { Name: "clean", Description: "Clean all deployed mods", Arguments: []string{"game name"}, IsVarargs: false, Action: func(requiredArguments []string, arguments []string) (string, error) { if len(arguments) != len(requiredArguments) { return "", fmt.Errorf("expected %s", requiredArguments[0]) } if gameError := WithGame(arguments[0], func(game *Game) error { return game.CleanDeployedMods() }); gameError != nil { return "", gameError } return "cleaned", nil }, }, } var formatters = map[string]func(*strings.Builder, any) error{ "json": func(builder *strings.Builder, data any) error { var encoder = json.NewEncoder(builder) if encodeError := encoder.Encode(data); encodeError != nil { return encodeError } return nil }, "yaml": func(builder *strings.Builder, data any) error { var encoder = yaml.NewEncoder(builder) encoder.SetIndent(2) if encodeError := encoder.Encode(data); encodeError != nil { return encodeError } return nil }, } func main() { var argCount = len(os.Args) if argCount == 1 { fmt.Println("Modman v0.1") fmt.Println("Enter one of the following commands following modman:") for i := range commands { var command = commands[i] fmt.Print("\t", command.Name) for j := range command.Arguments { fmt.Print(" [", command.Arguments[j], "]") } if command.IsVarargs { fmt.Println("...") } else { fmt.Println() } } return } var commandName = os.Args[1] for i := range commands { var command = commands[i] if command.Name == commandName { var response, actionError = command.Action(command.Arguments, os.Args[2:]) if actionError != nil { fmt.Fprintln(os.Stderr, actionError.Error()) os.Exit(1) } if len(response) != 0 { fmt.Println(response) } return } } fmt.Fprintf(os.Stderr, "unknown command: `%s`\n", commandName) }