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.
			
			
This commit is contained in:
		
							parent
							
								
									7ee2c1336c
								
							
						
					
					
						commit
						8f00979f73
					
				
					 9 changed files with 77 additions and 73 deletions
				
			
		
							
								
								
									
										5
									
								
								assets/go-licenses.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								assets/go-licenses.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -7,9 +7,10 @@ package main
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
	"os"
 | 
			
		||||
	goPath "path"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sort"
 | 
			
		||||
| 
						 | 
				
			
			@ -27,9 +28,14 @@ type LicenseEntry struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	if len(os.Args) != 3 {
 | 
			
		||||
		fmt.Println("usage: go run generate-go-licenses.go <base-dir> <out-json-file>")
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base, out := os.Args[1], os.Args[2]
 | 
			
		||||
 | 
			
		||||
	paths := []string{}
 | 
			
		||||
	var paths []string
 | 
			
		||||
	err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
| 
						 | 
				
			
			@ -46,28 +52,27 @@ func main() {
 | 
			
		|||
 | 
			
		||||
	sort.Strings(paths)
 | 
			
		||||
 | 
			
		||||
	entries := []LicenseEntry{}
 | 
			
		||||
	for _, path := range paths {
 | 
			
		||||
		path := filepath.ToSlash(path)
 | 
			
		||||
 | 
			
		||||
		licenseText, err := os.ReadFile(path)
 | 
			
		||||
	var entries []LicenseEntry
 | 
			
		||||
	for _, filePath := range paths {
 | 
			
		||||
		licenseText, err := os.ReadFile(filePath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = strings.Replace(path, base+"/", "", 1)
 | 
			
		||||
		name := goPath.Dir(path)
 | 
			
		||||
		pkgPath := filepath.ToSlash(filePath)
 | 
			
		||||
		pkgPath = strings.TrimPrefix(pkgPath, base+"/")
 | 
			
		||||
		pkgName := path.Dir(pkgPath)
 | 
			
		||||
 | 
			
		||||
		// There might be a bug somewhere in go-licenses that sometimes interprets the
 | 
			
		||||
		// root package as "." and sometimes as "code.gitea.io/gitea". Workaround by
 | 
			
		||||
		// removing both of them for the sake of stable output.
 | 
			
		||||
		if name == "." || name == "code.gitea.io/gitea" {
 | 
			
		||||
		if pkgName == "." || pkgName == "code.gitea.io/gitea" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		entries = append(entries, LicenseEntry{
 | 
			
		||||
			Name:        name,
 | 
			
		||||
			Path:        path,
 | 
			
		||||
			Name:        pkgName,
 | 
			
		||||
			Path:        pkgPath,
 | 
			
		||||
			LicenseText: string(licenseText),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -96,7 +96,6 @@ require (
 | 
			
		|||
	github.com/stretchr/testify v1.8.1
 | 
			
		||||
	github.com/syndtr/goleveldb v1.0.0
 | 
			
		||||
	github.com/tstranex/u2f v1.0.0
 | 
			
		||||
	github.com/unrolled/render v1.5.0
 | 
			
		||||
	github.com/urfave/cli v1.22.12
 | 
			
		||||
	github.com/xanzy/go-gitlab v0.80.2
 | 
			
		||||
	github.com/xeipuuv/gojsonschema v1.2.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1182,8 +1182,6 @@ github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o
 | 
			
		|||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
 | 
			
		||||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
 | 
			
		||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
 | 
			
		||||
github.com/unrolled/render v1.5.0 h1:uNTHMvVoI9pyyXfgoDHHycIqFONNY2p4eQR9ty+NsxM=
 | 
			
		||||
github.com/unrolled/render v1.5.0/go.mod h1:eLTosBkQqEPEk7pRfkCRApXd++lm++nCsVlFOHpeedw=
 | 
			
		||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 | 
			
		||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 | 
			
		||||
github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,14 +42,13 @@ import (
 | 
			
		|||
	"gitea.com/go-chi/session"
 | 
			
		||||
	chi "github.com/go-chi/chi/v5"
 | 
			
		||||
	"github.com/minio/sha256-simd"
 | 
			
		||||
	"github.com/unrolled/render"
 | 
			
		||||
	"golang.org/x/crypto/pbkdf2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Render represents a template render
 | 
			
		||||
type Render interface {
 | 
			
		||||
	TemplateLookup(tmpl string) *template.Template
 | 
			
		||||
	HTML(w io.Writer, status int, name string, binding interface{}, htmlOpt ...render.HTMLOptions) error
 | 
			
		||||
	HTML(w io.Writer, status int, name string, data interface{}) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Context represents context of a request.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ import (
 | 
			
		|||
 | 
			
		||||
	chi "github.com/go-chi/chi/v5"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"github.com/unrolled/render"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MockContext mock context for unit tests
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +137,7 @@ func (tr *mockRender) TemplateLookup(tmpl string) *template.Template {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ interface{}, _ ...render.HTMLOptions) error {
 | 
			
		||||
func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ interface{}) error {
 | 
			
		||||
	if resp, ok := w.(http.ResponseWriter); ok {
 | 
			
		||||
		resp.WriteHeader(status)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,6 @@ import (
 | 
			
		|||
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
	"github.com/quasoft/websspi"
 | 
			
		||||
	"github.com/unrolled/render"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +47,7 @@ var (
 | 
			
		|||
// On successful authentication returns a valid user object.
 | 
			
		||||
// Returns nil if authentication fails.
 | 
			
		||||
type SSPI struct {
 | 
			
		||||
	rnd *render.Render
 | 
			
		||||
	rnd *templates.HTMLRender
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Init creates a new global websspi.Authenticator object
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ func TestExternalMarkupRenderer(t *testing.T) {
 | 
			
		|||
	const repoURL = "user30/renderer"
 | 
			
		||||
	req := NewRequest(t, "GET", repoURL+"/src/branch/master/README.html")
 | 
			
		||||
	resp := MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	assert.EqualValues(t, "text/html; charset=UTF-8", resp.Header()["Content-Type"][0])
 | 
			
		||||
	assert.EqualValues(t, "text/html; charset=utf-8", resp.Header()["Content-Type"][0])
 | 
			
		||||
 | 
			
		||||
	bs, err := io.ReadAll(resp.Body)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue