diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2023-04-08 14:21:50 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-08 14:21:50 +0800 |
commit | 8f00979f732c976b75086f75ab7e776d2ee18771 (patch) | |
tree | 2f8490f87912e1f5bdd3fa55fa01ed9589e1add5 /modules/templates | |
parent | 7ee2c1336cddeb4c966d1d6f0dbe1e7680c1ee9a (diff) | |
download | gitea-8f00979f732c976b75086f75ab7e776d2ee18771.tar.gz gitea-8f00979f732c976b75086f75ab7e776d2ee18771.zip |
Drop "unrolled/render" package (#23965)
None of the features of `unrolled/render` package is used.
The Golang builtin "html/template" just works well. Then we can improve
our HTML render to resolve the "$.root.locale.Tr" problem as much as
possible.
Next step: we can have a template render pool (by Clone), then we can
inject global functions with dynamic context to every `Execute` calls.
Then we can use `{{Locale.Tr ....}}` directly in all templates , no need
to pass the `$.root.locale` again and again.
Diffstat (limited to 'modules/templates')
-rw-r--r-- | modules/templates/htmlrenderer.go | 102 |
1 files changed, 56 insertions, 46 deletions
diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index 96dc010796..fd985edc64 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -7,15 +7,18 @@ import ( "bytes" "context" "fmt" + "html/template" + "io" + "net/http" + "path/filepath" "regexp" "strconv" "strings" + "sync/atomic" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/watcher" - - "github.com/unrolled/render" ) var ( @@ -27,14 +30,50 @@ var ( expectedEndError = regexp.MustCompile(`^template: (.*):([0-9]+): expected end; found (.*)`) ) -// HTMLRenderer returns the current html renderer for the context or creates and stores one within the context for future use -func HTMLRenderer(ctx context.Context) (context.Context, *render.Render) { - rendererInterface := ctx.Value(rendererKey) - if rendererInterface != nil { - renderer, ok := rendererInterface.(*render.Render) - if ok { - return ctx, renderer +type HTMLRender struct { + templates atomic.Pointer[template.Template] +} + +func (h *HTMLRender) HTML(w io.Writer, status int, name string, data interface{}) error { + if respWriter, ok := w.(http.ResponseWriter); ok { + if respWriter.Header().Get("Content-Type") == "" { + respWriter.Header().Set("Content-Type", "text/html; charset=utf-8") + } + respWriter.WriteHeader(status) + } + return h.templates.Load().ExecuteTemplate(w, name, data) +} + +func (h *HTMLRender) TemplateLookup(t string) *template.Template { + return h.templates.Load().Lookup(t) +} + +func (h *HTMLRender) CompileTemplates() error { + dirPrefix := "templates/" + tmpls := template.New("") + for _, path := range GetTemplateAssetNames() { + name := path[len(dirPrefix):] + name = strings.TrimSuffix(name, ".tmpl") + tmpl := tmpls.New(filepath.ToSlash(name)) + for _, fm := range NewFuncMap() { + tmpl.Funcs(fm) + } + buf, err := GetAsset(path) + if err != nil { + return err } + if _, err = tmpl.Parse(string(buf)); err != nil { + return err + } + } + h.templates.Store(tmpls) + return nil +} + +// HTMLRenderer returns the current html renderer for the context or creates and stores one within the context for future use +func HTMLRenderer(ctx context.Context) (context.Context, *HTMLRender) { + if renderer, ok := ctx.Value(rendererKey).(*HTMLRender); ok { + return ctx, renderer } rendererType := "static" @@ -43,53 +82,24 @@ func HTMLRenderer(ctx context.Context) (context.Context, *render.Render) { } log.Log(1, log.DEBUG, "Creating "+rendererType+" HTML Renderer") - compilingTemplates := true - defer func() { - if !compilingTemplates { - return - } - - panicked := recover() - if panicked == nil { - return - } - - // OK try to handle the panic... - err, ok := panicked.(error) - if ok { - handlePanicError(err) - } - log.Fatal("PANIC: Unable to compile templates!\n%v\n\nStacktrace:\n%s", panicked, log.Stack(2)) - }() - - renderer := render.New(render.Options{ - Extensions: []string{".tmpl"}, - Directory: "templates", - Funcs: NewFuncMap(), - Asset: GetAsset, - AssetNames: GetTemplateAssetNames, - UseMutexLock: !setting.IsProd, - IsDevelopment: false, - DisableHTTPErrorRendering: true, - }) - compilingTemplates = false + renderer := &HTMLRender{} + if err := renderer.CompileTemplates(); err != nil { + handleFatalError(err) + } if !setting.IsProd { watcher.CreateWatcher(ctx, "HTML Templates", &watcher.CreateWatcherOpts{ PathsCallback: walkTemplateFiles, BetweenCallback: func() { - defer func() { - if err := recover(); err != nil { - log.Error("PANIC: %v\n%s", err, log.Stack(2)) - } - }() - renderer.CompileTemplates() + if err := renderer.CompileTemplates(); err != nil { + log.Error("Template error: %v\n%s", err, log.Stack(2)) + } }, }) } return context.WithValue(ctx, rendererKey, renderer), renderer } -func handlePanicError(err error) { +func handleFatalError(err error) { wrapFatal(handleNotDefinedPanicError(err)) wrapFatal(handleUnexpected(err)) wrapFatal(handleExpectedEnd(err)) |