func (app *App) errorPage(ctx *Context, elapsed time.Duration, skip int, stackSkip int, req string, err interface{}) { t := newInternalTemplate(app) if terr := t.parse("panic.html", devserver.TemplateVars(&Context{})); terr != nil { panic(terr) } if devserver.IsActive() { t.tmpl.AddPlugin(devserver.ReloadPlugin()) } if terr := t.prepare(); terr != nil { panic(terr) } stack := runtimeutil.FormatStackHTML(stackSkip + 1) location, code := runtimeutil.FormatCallerHTML(skip+1, 5, true, true) ctx.statusCode = -http.StatusInternalServerError data := map[string]interface{}{ "Error": fmt.Sprintf("%v", err), "Subtitle": fmt.Sprintf("(after %s)", elapsed), "Location": location, "Code": code, "Stack": stack, "Request": req, "Name": filepath.Base(os.Args[0]), "IsDevServer": devserver.IsDevServer(app), } if err := t.Execute(ctx, data); err != nil { var msg string if file, line, ok := runtimeutil.PanicLocation(); ok { msg = fmt.Sprintf("error rendering error page: %v @ %s:%d)", err, file, line) } else { msg = fmt.Sprintf("error rendering error page: %v", err) } ctx.WriteString(msg) } }
func (s *State) recover(pc *int, tmpl *string, err *error) { if r := recover(); r != nil { e, ok := r.(error) if !ok { e = fmt.Errorf("%v", r) } if file, line, ok := runtimeutil.PanicLocation(); ok { e = fmt.Errorf("%v (at %s:%d)", e, file, line) } *err = s.formatErr(*pc, *tmpl, e) } }
func (ns *namespace) eval(ctx *Context) (m map[string]interface{}, err error) { defer func() { if r := recover(); r != nil { var pe error if e, ok := r.(error); ok { pe = e } else { pe = fmt.Errorf("%v", r) } err = pe if file, line, ok := runtimeutil.PanicLocation(); ok { err = fmt.Errorf("%v (at %s:%d)", pe, file, line) } } }() m = make(map[string]interface{}, len(ns.vars)+len(ns.funcs)+len(ns.namespaces)+2) for k, v := range ns.vars { m[k] = v } in := []reflect.Value{reflect.ValueOf(ctx)} for k, v := range ns.funcs { var out []reflect.Value if v.Type().NumIn() == 0 { out = v.Call(nil) } else { if ctx == nil { m[k] = nil continue } out = v.Call(in) } if len(out) == 2 && !out[1].IsNil() { return nil, out[1].Interface().(error) } m[k] = out[0].Interface() } m["Ctx"] = ctx if ctx != nil { m["Request"] = ctx.R } for k, v := range ns.namespaces { if m[k], err = v.eval(ctx); err != nil { return nil, err } } return m, nil }
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 }