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) { if len(providedArguments) < len(requiredArguments) { return "", fmt.Errorf("expected %s folowed by at least one %ss", requiredArguments[0], requiredArguments[1]) } var archivePaths = providedArguments[1:] if game, openGameError := LoadGame(providedArguments[0]); openGameError == nil { if installError := game.InstallMods(archivePaths); installError != nil { return "", installError } } if len(archivePaths) > 1 { return "mods installed", nil } return "mod installed", nil }, }, { Name: "register", Description: "Registers the data directory path of game for management under the given name", Arguments: []string{"data path", "game name"}, IsVarargs: false, Action: func(requiredArguments []string, providedArguments []string) (string, error) { if len(providedArguments) < len(requiredArguments) { return "", fmt.Errorf("expected %s folowed by at least one %ss", requiredArguments[0], requiredArguments[1]) } var dataPath = providedArguments[0] var gameName = providedArguments[1] if registerGameError := RegisterGame(gameName, dataPath); registerGameError != nil { return "", registerGameError } return fmt.Sprintf("Registered %s at %s", gameName, dataPath), 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]) } var modNames = providedArguments[1:] if game, openGameError := LoadGame(providedArguments[0]); openGameError == nil { for _, name := range modNames { if removeError := game.RemoveMod(name); removeError != nil { return "", removeError } } } else { return "", openGameError } if len(modNames) > 1 { return "removed mods", nil } return "removed mod", 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 game, openGameError := LoadGame(providedArguments[0]); openGameError == nil { if renameError := game.RenameMod(providedArguments[1], providedArguments[2]); renameError != nil { return "", renameError } } else { return "", openGameError } return "renamed", 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 manifestBuilder = strings.Builder{} if game, openGameError := LoadGame(providedArguments[0]); openGameError == nil { var format = providedArguments[1] if formatter, exists := formatters[format]; exists { if formatError := formatter(&manifestBuilder, game.Mods); formatError != nil { return "", formatError } } else { return "", fmt.Errorf("unsupported format: `%s`", format) } } else { return "", openGameError } return manifestBuilder.String(), nil }, }, { Name: "deploy", Description: "Deploy all specified mods in order of listing", 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 game, openGameError := LoadGame(providedArguments[0]); openGameError != nil { if deployError := game.Deploy(providedArguments[1:]); deployError != nil { return "", deployError } } else { return "", openGameError } 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 game, openGameError := LoadGame(arguments[0]); openGameError == nil { if cleanError := game.Clean(); cleanError != nil { return "", cleanError } } else { return "", openGameError } 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) }