func executeCommand(name string, cmd *command, args []string, a *app.App) (err error) { // Parse command flags set := flag.NewFlagSet(name, flag.ContinueOnError) set.Usage = func() { commandHelp(name, -1, os.Stderr) } flags := map[string]interface{}{} for _, arg := range cmd.opts.Flags { switch arg.typ { case typBool: var b bool set.BoolVar(&b, arg.name, arg.def.(bool), arg.help) flags[arg.name] = &b case typInt: var i int set.IntVar(&i, arg.name, arg.def.(int), arg.help) flags[arg.name] = &i case typString: var s string set.StringVar(&s, arg.name, arg.def.(string), arg.help) flags[arg.name] = &s default: panic("invalid arg type") } } // Print error/help messages ourselves set.SetOutput(ioutil.Discard) err = set.Parse(args) if err != nil { if err == flag.ErrHelp { return } if strings.Contains(err.Error(), "provided but not defined") { flagName := strings.TrimSpace(strings.Split(err.Error(), ":")[1]) fmt.Fprintf(os.Stderr, "command %s does not accept flag %s\n", name, flagName) return } return err } var params []string paramValues := make(map[string]string) for _, arg := range cmd.opts.Flags { params = append(params, arg.name) paramValues[arg.name] = fmt.Sprintf("%v", reflect.ValueOf(flags[arg.name]).Elem().Interface()) } provider := &contextProvider{ args: set.Args(), params: params, paramValues: paramValues, } if os.Getenv("GONDOLA_COMMANDS_NO_RECOVER") == "" { defer func() { if r := recover(); r != nil { if e, ok := r.(error); ok { err = e } else { err = fmt.Errorf("%v", r) } if file, line, ok := runtimeutil.PanicLocation(); ok { err = fmt.Errorf("%v (at %s:%d)", err, file, line) } } }() } ctx := a.NewContext(provider) defer a.CloseContext(ctx) cmd.handler(ctx) return }