package fairwind import ( "encoding/json" "fmt" "os" "reflect" "strings" ) type CommandHandler func(Parameters) error type Parameter struct { Kind reflect.Kind Required bool Value reflect.Value `json:"-"` } type Parameters map[string]*Parameter type Command struct { Name string Documentation string Parameters Parameters Handler CommandHandler `json:"-"` Commands []Command } func (this *Command) Execute() { parts := os.Args[1:] if len(parts) == 0 { this.manual() return } currentCommand := this index := -1 for i, part := range parts { if strings.Contains(part, "--") { index = i break } found := false for _, iteratedCommand := range currentCommand.Commands { if iteratedCommand.Name != part { continue } currentCommand = &iteratedCommand found = true break } if !found { fmt.Println("Command not found") os.Exit(1) } } parameters := Parameters{} fail := false if index >= 0 { for i := index; i < len(parts); i++ { part := parts[i] keyValue := strings.Split(part, "=") if len(keyValue) != 2 { fmt.Printf("Invalid argument: %s\n", part) os.Exit(1) } key := keyValue[0] value := keyValue[1] parameter, ok := currentCommand.Parameters[key] if !ok { fmt.Printf("Invalid argument: %s=%s\n", key, value) fail = true continue } switch parameter.Kind { case reflect.String: parameters[key[2:]] = &Parameter{ Value: reflect.ValueOf(value), } } } } if fail { os.Exit(1) } for key, parameter := range currentCommand.Parameters { if !parameter.Required { continue } _, ok := parameters[key[2:]] if !ok { fmt.Printf("Argument required: %s\n", key) fail = true } } if fail { os.Exit(1) } if currentCommand.Handler == nil { fmt.Println("Handler for command not set") os.Exit(1) } err := currentCommand.Handler(parameters) if err != nil { fmt.Printf("Execution error: %v\n", err) os.Exit(1) } } func (this *Command) manual() { buffer, err := json.Marshal(this) if err != nil { fmt.Printf("Execution error: %v\n", err) os.Exit(1) } fmt.Println(string(buffer)) }