From fa841ce74769d2bdcd66459f2e4da27aadf6860b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 21 Mar 2022 10:12:29 +0800 Subject: [PATCH 1/6] Use a new vars template implementation --- models/migrations/migrations_test.go | 3 +- modules/cache/cache_redis.go | 8 +- modules/context/csrf.go | 3 +- modules/context/repo.go | 12 ++- modules/markup/html.go | 11 ++- modules/repository/init.go | 9 ++- modules/sync/unique_queue.go | 10 +-- modules/templates/vars/vars.go | 106 +++++++++++++++++++++++++++ modules/templates/vars/vars_test.go | 70 ++++++++++++++++++ modules/util/util.go | 7 ++ routers/web/goget.go | 22 +++++- routers/web/repo/issue.go | 10 ++- 12 files changed, 243 insertions(+), 28 deletions(-) create mode 100644 modules/templates/vars/vars.go create mode 100644 modules/templates/vars/vars_test.go diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go index f798d501179f7..a17eba54e82be 100644 --- a/models/migrations/migrations_test.go +++ b/models/migrations/migrations_test.go @@ -24,7 +24,6 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" - "github.com/unknwon/com" "xorm.io/xorm" "xorm.io/xorm/names" ) @@ -204,7 +203,7 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En deferFn := PrintCurrentTest(t, ourSkip) assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) - assert.NoError(t, com.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), + assert.NoError(t, util.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { diff --git a/modules/cache/cache_redis.go b/modules/cache/cache_redis.go index 148725ae66015..e4b9a70f63f3a 100644 --- a/modules/cache/cache_redis.go +++ b/modules/cache/cache_redis.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/nosql" + "code.gitea.io/gitea/modules/util" "gitea.com/go-chi/cache" "github.com/go-redis/redis/v8" - "github.com/unknwon/com" ) // RedisCacher represents a redis cache adapter implementation. @@ -29,15 +29,15 @@ type RedisCacher struct { func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { key = c.prefix + key if expire == 0 { - if err := c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), 0).Err(); err != nil { + if err := c.c.Set(graceful.GetManager().HammerContext(), key, util.ToStr(val), 0).Err(); err != nil { return err } } else { - dur, err := time.ParseDuration(com.ToStr(expire) + "s") + dur, err := time.ParseDuration(util.ToStr(expire) + "s") if err != nil { return err } - if err = c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), dur).Err(); err != nil { + if err = c.c.Set(graceful.GetManager().HammerContext(), key, util.ToStr(val), dur).Err(); err != nil { return err } } diff --git a/modules/context/csrf.go b/modules/context/csrf.go index 99c223c884da3..f7c9205b72c5e 100644 --- a/modules/context/csrf.go +++ b/modules/context/csrf.go @@ -23,6 +23,7 @@ import ( "time" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "github.com/unknwon/com" @@ -211,7 +212,7 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF { x.ID = "0" uid := ctx.Session.Get(opt.SessionKey) if uid != nil { - x.ID = com.ToStr(uid) + x.ID = util.ToStr(uid) } needsNew := false diff --git a/modules/context/repo.go b/modules/context/repo.go index 5a9e38a1d9197..002fea5de5621 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -25,11 +25,11 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" "github.com/editorconfig/editorconfig-core-go/v2" - "github.com/unknwon/com" ) // IssueTemplateDirCandidates issue templates directory @@ -308,11 +308,17 @@ func EarlyResponseForGoGetMeta(ctx *Context) { ctx.PlainText(http.StatusBadRequest, "invalid repository path") return } - ctx.PlainText(http.StatusOK, com.Expand(``, + res, err := vars.Expand(``, map[string]string{ "GoGetImport": ComposeGoGetImport(username, reponame), "CloneLink": repo_model.ComposeHTTPSCloneURL(username, reponame), - })) + }) + if err != nil { + log.Error(err.Error()) + ctx.PlainText(http.StatusInternalServerError, "expand vars failed") + return + } + ctx.PlainText(http.StatusOK, res) } // RedirectToRepo redirect to a differently-named repository diff --git a/modules/markup/html.go b/modules/markup/html.go index 6673f52bf4d6b..7f83f08093a34 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -21,9 +21,9 @@ import ( "code.gitea.io/gitea/modules/markup/common" "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/util" - "github.com/unknwon/com" "golang.org/x/net/html" "golang.org/x/net/html/atom" "mvdan.cc/xurls/v2" @@ -838,7 +838,14 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { reftext := node.Data[ref.RefLocation.Start:ref.RefLocation.End] if exttrack && !ref.IsPull { ctx.Metas["index"] = ref.Issue - link = createLink(com.Expand(ctx.Metas["format"], ctx.Metas), reftext, "ref-issue ref-external-issue") + + res, err := vars.Expand(ctx.Metas["format"], ctx.Metas) + if err != nil { + log.Error(err.Error()) + return + } + + link = createLink(res, reftext, "ref-issue ref-external-issue") } else { // Path determines the type of link that will be rendered. It's unknown at this point whether // the linked item is actually a PR or an issue. Luckily it's of no real consequence because diff --git a/modules/repository/init.go b/modules/repository/init.go index d5a67df5d150c..958a98da88678 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -22,10 +22,9 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" - - "github.com/unknwon/com" ) var ( @@ -250,8 +249,12 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, "CloneURL.HTTPS": cloneLink.HTTPS, "OwnerName": repo.OwnerName, } + res, err := vars.Expand(string(data), match) + if err != nil { + return fmt.Errorf("expand README.md: %v", err) + } if err = os.WriteFile(filepath.Join(tmpDir, "README.md"), - []byte(com.Expand(string(data), match)), 0o644); err != nil { + []byte(res), 0o644); err != nil { return fmt.Errorf("write README.md: %v", err) } diff --git a/modules/sync/unique_queue.go b/modules/sync/unique_queue.go index d41726b5af930..414cc50f39a76 100644 --- a/modules/sync/unique_queue.go +++ b/modules/sync/unique_queue.go @@ -5,9 +5,7 @@ package sync -import ( - "github.com/unknwon/com" -) +import "code.gitea.io/gitea/modules/util" // UniqueQueue is a queue which guarantees only one instance of same // identity is in the line. Instances with same identity will be @@ -73,13 +71,13 @@ func (q *UniqueQueue) Queue() <-chan string { // Exist returns true if there is an instance with given identity // exists in the queue. func (q *UniqueQueue) Exist(id interface{}) bool { - return q.table.IsRunning(com.ToStr(id)) + return q.table.IsRunning(util.ToStr(id)) } // AddFunc adds new instance to the queue with a custom runnable function, // the queue is blocked until the function exits. func (q *UniqueQueue) AddFunc(id interface{}, fn func()) { - idStr := com.ToStr(id) + idStr := util.ToStr(id) q.table.lock.Lock() if _, ok := q.table.pool[idStr]; ok { q.table.lock.Unlock() @@ -105,5 +103,5 @@ func (q *UniqueQueue) Add(id interface{}) { // Remove removes instance from the queue. func (q *UniqueQueue) Remove(id interface{}) { - q.table.Stop(com.ToStr(id)) + q.table.Stop(util.ToStr(id)) } diff --git a/modules/templates/vars/vars.go b/modules/templates/vars/vars.go new file mode 100644 index 0000000000000..152819c32e553 --- /dev/null +++ b/modules/templates/vars/vars.go @@ -0,0 +1,106 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package vars + +import ( + "fmt" + "strings" +) + +// ErrWrongSyntax represents a wrong syntax with a tempate +type ErrWrongSyntax struct { + Template string +} + +func (err ErrWrongSyntax) Error() string { + return fmt.Sprintf("Wrong syntax found in %s", err.Template) +} + +// IsErrWrongSyntax returns true if the error is ErrWrongSyntax +func IsErrWrongSyntax(err error) bool { + _, ok := err.(ErrWrongSyntax) + return ok +} + +// ErrNoMatchedVar represents an error that no matched vars +type ErrNoMatchedVar struct { + Template string + Var string +} + +func (err ErrNoMatchedVar) Error() string { + return fmt.Sprintf("No matched variable %s found for %s", err.Var, err.Template) +} + +// IsErrNoMatchedVar returns true if the error is ErrNoMatchedVar +func IsErrNoMatchedVar(err error) bool { + _, ok := err.(ErrNoMatchedVar) + return ok +} + +// Expand replaces all variables like {var} to match +func Expand(template string, match map[string]string, subs ...string) (string, error) { + var ( + buf strings.Builder + key strings.Builder + enter bool + ) + for _, c := range template { + switch { + case c == '{': + if enter { + return "", ErrWrongSyntax{ + Template: template, + } + } + enter = true + case c == '}': + if !enter { + return "", ErrWrongSyntax{ + Template: template, + } + } + if key.Len() == 0 { + return "", ErrWrongSyntax{ + Template: template, + } + } + + if len(match) == 0 { + return "", ErrNoMatchedVar{ + Template: template, + Var: key.String(), + } + } + + v, ok := match[key.String()] + if !ok { + if len(subs) == 0 { + return "", ErrNoMatchedVar{ + Template: template, + Var: key.String(), + } + } + v = subs[0] + } + + if _, err := buf.WriteString(v); err != nil { + return "", err + } + key.Reset() + + enter = false + case enter: + if _, err := key.WriteRune(c); err != nil { + return "", err + } + default: + if _, err := buf.WriteRune(c); err != nil { + return "", err + } + } + } + return buf.String(), nil +} diff --git a/modules/templates/vars/vars_test.go b/modules/templates/vars/vars_test.go new file mode 100644 index 0000000000000..1e80ac2b2ff7b --- /dev/null +++ b/modules/templates/vars/vars_test.go @@ -0,0 +1,70 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package vars + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExpandVars(t *testing.T) { + kases := []struct { + template string + maps map[string]string + expected string + fail bool + }{ + { + template: "{a}", + maps: map[string]string{ + "a": "1", + }, + expected: "1", + }, + { + template: "expand {a}, {b} and {c}", + maps: map[string]string{ + "a": "1", + "b": "2", + "c": "3", + }, + expected: "expand 1, 2 and 3", + }, + { + template: "中文内容 {一}, {二} 和 {三} 中文结尾", + maps: map[string]string{ + "一": "11", + "二": "22", + "三": "33", + }, + expected: "中文内容 11, 22 和 33 中文结尾", + }, + { + template: "expand {{a}, {b} and {c}", + fail: true, + }, + { + template: "expand {}, {b} and {c}", + fail: true, + }, + { + template: "expand }, {b} and {c}", + fail: true, + }, + } + + for _, kase := range kases { + t.Run(kase.template, func(t *testing.T) { + res, err := Expand(kase.template, kase.maps) + if kase.fail { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.EqualValues(t, kase.expected, res) + }) + } +} diff --git a/modules/util/util.go b/modules/util/util.go index af6581f7cdbe3..eceb72d57b459 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -11,6 +11,8 @@ import ( "math/big" "strconv" "strings" + + "github.com/unknwon/com" ) // OptionalBool a boolean that can be "null" @@ -181,3 +183,8 @@ func ToUpperASCII(s string) string { } return string(b) } + +// ToStr should be replaced +func ToStr(value interface{}, args ...int) string { + return com.ToStr(value, args...) +} diff --git a/routers/web/goget.go b/routers/web/goget.go index 4a31fcc2c51cc..da7f74e5484c5 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -12,10 +12,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/util" - - "github.com/unknwon/com" ) func goGet(ctx *context.Context) { @@ -67,7 +67,7 @@ func goGet(ctx *context.Context) { } ctx.RespHeader().Set("Content-Type", "text/html") ctx.Status(http.StatusOK) - _, _ = ctx.Write([]byte(com.Expand(` + res, err := vars.Expand(` @@ -83,5 +83,19 @@ func goGet(ctx *context.Context) { "GoDocDirectory": prefix + "{/dir}", "GoDocFile": prefix + "{/dir}/{file}#L{line}", "Insecure": insecure, - }))) + }) + if err != nil { + log.Error(err.Error()) + _, _ = ctx.Write([]byte(` + + + invalid import path + + +`)) + ctx.Status(400) + return + } + + _, _ = ctx.Write([]byte(res)) } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 486a63a9e105f..cc93fdd2808f3 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -35,6 +35,7 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -43,8 +44,6 @@ import ( "code.gitea.io/gitea/services/forms" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" - - "github.com/unknwon/com" ) const ( @@ -1113,7 +1112,12 @@ func ViewIssue(ctx *context.Context) { if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" { metas := ctx.Repo.Repository.ComposeMetas() metas["index"] = ctx.Params(":index") - ctx.Redirect(com.Expand(extIssueUnit.ExternalTrackerConfig().ExternalTrackerFormat, metas)) + res, err := vars.Expand(extIssueUnit.ExternalTrackerConfig().ExternalTrackerFormat, metas) + if err != nil { + ctx.ServerError("Expand", err) + return + } + ctx.Redirect(res) return } } else if err != nil && !repo_model.IsErrUnitTypeNotExist(err) { From 9ef65b3c16ea618827486ea3d80c747ef0e356a5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 21 Mar 2022 20:23:16 +0800 Subject: [PATCH 2/6] Improve vars Expand --- modules/templates/vars/vars.go | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/modules/templates/vars/vars.go b/modules/templates/vars/vars.go index 152819c32e553..edde41d708e42 100644 --- a/modules/templates/vars/vars.go +++ b/modules/templates/vars/vars.go @@ -43,26 +43,25 @@ func IsErrNoMatchedVar(err error) bool { // Expand replaces all variables like {var} to match func Expand(template string, match map[string]string, subs ...string) (string, error) { var ( - buf strings.Builder - key strings.Builder - enter bool + buf strings.Builder + keyStartPos = -1 ) - for _, c := range template { + for i, c := range template { switch { case c == '{': - if enter { + if keyStartPos > -1 { return "", ErrWrongSyntax{ Template: template, } } - enter = true + keyStartPos = i case c == '}': - if !enter { + if keyStartPos == -1 { return "", ErrWrongSyntax{ Template: template, } } - if key.Len() == 0 { + if i-keyStartPos <= 1 { return "", ErrWrongSyntax{ Template: template, } @@ -71,16 +70,16 @@ func Expand(template string, match map[string]string, subs ...string) (string, e if len(match) == 0 { return "", ErrNoMatchedVar{ Template: template, - Var: key.String(), + Var: template[keyStartPos+1 : i], } } - v, ok := match[key.String()] + v, ok := match[template[keyStartPos+1:i]] if !ok { if len(subs) == 0 { return "", ErrNoMatchedVar{ Template: template, - Var: key.String(), + Var: template[keyStartPos+1 : i], } } v = subs[0] @@ -89,13 +88,9 @@ func Expand(template string, match map[string]string, subs ...string) (string, e if _, err := buf.WriteString(v); err != nil { return "", err } - key.Reset() - enter = false - case enter: - if _, err := key.WriteRune(c); err != nil { - return "", err - } + keyStartPos = -1 + case keyStartPos > -1: default: if _, err := buf.WriteRune(c); err != nil { return "", err From b8370d07e4dffd22984211f59402f5b166fe472b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 21 Mar 2022 21:00:49 +0800 Subject: [PATCH 3/6] Remove unrelated changes --- models/migrations/migrations_test.go | 3 ++- modules/cache/cache_redis.go | 8 ++++---- modules/context/csrf.go | 3 +-- modules/sync/unique_queue.go | 10 ++++++---- modules/util/util.go | 7 ------- routers/web/repo/issue.go | 1 + 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go index a17eba54e82be..f798d501179f7 100644 --- a/models/migrations/migrations_test.go +++ b/models/migrations/migrations_test.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" + "github.com/unknwon/com" "xorm.io/xorm" "xorm.io/xorm/names" ) @@ -203,7 +204,7 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En deferFn := PrintCurrentTest(t, ourSkip) assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) - assert.NoError(t, util.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), + assert.NoError(t, com.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { diff --git a/modules/cache/cache_redis.go b/modules/cache/cache_redis.go index e4b9a70f63f3a..148725ae66015 100644 --- a/modules/cache/cache_redis.go +++ b/modules/cache/cache_redis.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/nosql" - "code.gitea.io/gitea/modules/util" "gitea.com/go-chi/cache" "github.com/go-redis/redis/v8" + "github.com/unknwon/com" ) // RedisCacher represents a redis cache adapter implementation. @@ -29,15 +29,15 @@ type RedisCacher struct { func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { key = c.prefix + key if expire == 0 { - if err := c.c.Set(graceful.GetManager().HammerContext(), key, util.ToStr(val), 0).Err(); err != nil { + if err := c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), 0).Err(); err != nil { return err } } else { - dur, err := time.ParseDuration(util.ToStr(expire) + "s") + dur, err := time.ParseDuration(com.ToStr(expire) + "s") if err != nil { return err } - if err = c.c.Set(graceful.GetManager().HammerContext(), key, util.ToStr(val), dur).Err(); err != nil { + if err = c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), dur).Err(); err != nil { return err } } diff --git a/modules/context/csrf.go b/modules/context/csrf.go index f7c9205b72c5e..99c223c884da3 100644 --- a/modules/context/csrf.go +++ b/modules/context/csrf.go @@ -23,7 +23,6 @@ import ( "time" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "github.com/unknwon/com" @@ -212,7 +211,7 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF { x.ID = "0" uid := ctx.Session.Get(opt.SessionKey) if uid != nil { - x.ID = util.ToStr(uid) + x.ID = com.ToStr(uid) } needsNew := false diff --git a/modules/sync/unique_queue.go b/modules/sync/unique_queue.go index 414cc50f39a76..d41726b5af930 100644 --- a/modules/sync/unique_queue.go +++ b/modules/sync/unique_queue.go @@ -5,7 +5,9 @@ package sync -import "code.gitea.io/gitea/modules/util" +import ( + "github.com/unknwon/com" +) // UniqueQueue is a queue which guarantees only one instance of same // identity is in the line. Instances with same identity will be @@ -71,13 +73,13 @@ func (q *UniqueQueue) Queue() <-chan string { // Exist returns true if there is an instance with given identity // exists in the queue. func (q *UniqueQueue) Exist(id interface{}) bool { - return q.table.IsRunning(util.ToStr(id)) + return q.table.IsRunning(com.ToStr(id)) } // AddFunc adds new instance to the queue with a custom runnable function, // the queue is blocked until the function exits. func (q *UniqueQueue) AddFunc(id interface{}, fn func()) { - idStr := util.ToStr(id) + idStr := com.ToStr(id) q.table.lock.Lock() if _, ok := q.table.pool[idStr]; ok { q.table.lock.Unlock() @@ -103,5 +105,5 @@ func (q *UniqueQueue) Add(id interface{}) { // Remove removes instance from the queue. func (q *UniqueQueue) Remove(id interface{}) { - q.table.Stop(util.ToStr(id)) + q.table.Stop(com.ToStr(id)) } diff --git a/modules/util/util.go b/modules/util/util.go index eceb72d57b459..af6581f7cdbe3 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -11,8 +11,6 @@ import ( "math/big" "strconv" "strings" - - "github.com/unknwon/com" ) // OptionalBool a boolean that can be "null" @@ -183,8 +181,3 @@ func ToUpperASCII(s string) string { } return string(b) } - -// ToStr should be replaced -func ToStr(value interface{}, args ...int) string { - return com.ToStr(value, args...) -} diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index cc93fdd2808f3..8b9c513872b8a 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1114,6 +1114,7 @@ func ViewIssue(ctx *context.Context) { metas["index"] = ctx.Params(":index") res, err := vars.Expand(extIssueUnit.ExternalTrackerConfig().ExternalTrackerFormat, metas) if err != nil { + log.Error("unable to expand template vars for issue url. issue: %s, err: %s", metas["index"], err.Error()) ctx.ServerError("Expand", err) return } From bbd6767da8e4d100d05160c91ded02de9ae7471c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 1 Apr 2022 13:45:33 +0800 Subject: [PATCH 4/6] Use fmt.Sprintf but vars.Expand when possible --- modules/context/repo.go | 17 ++++---------- routers/web/goget.go | 51 +++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/modules/context/repo.go b/modules/context/repo.go index 002fea5de5621..407bc99be807c 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -25,7 +25,6 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" @@ -308,17 +307,11 @@ func EarlyResponseForGoGetMeta(ctx *Context) { ctx.PlainText(http.StatusBadRequest, "invalid repository path") return } - res, err := vars.Expand(``, - map[string]string{ - "GoGetImport": ComposeGoGetImport(username, reponame), - "CloneLink": repo_model.ComposeHTTPSCloneURL(username, reponame), - }) - if err != nil { - log.Error(err.Error()) - ctx.PlainText(http.StatusInternalServerError, "expand vars failed") - return - } - ctx.PlainText(http.StatusOK, res) + + ctx.PlainText(http.StatusOK, fmt.Sprintf(``, + ComposeGoGetImport(username, reponame), + repo_model.ComposeHTTPSCloneURL(username, reponame), + )) } // RedirectToRepo redirect to a differently-named repository diff --git a/routers/web/goget.go b/routers/web/goget.go index da7f74e5484c5..98d357d5a335d 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -7,14 +7,13 @@ package web import ( "net/http" "net/url" + "os" "path" "strings" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/util" ) @@ -67,35 +66,37 @@ func goGet(ctx *context.Context) { } ctx.RespHeader().Set("Content-Type", "text/html") ctx.Status(http.StatusOK) - res, err := vars.Expand(` + res := os.Expand(` - - + + - go get {Insecure}{GoGetImport} + go get ${Insecure}${GoGetImport} -`, map[string]string{ - "GoGetImport": context.ComposeGoGetImport(ownerName, trimmedRepoName), - "CloneLink": repo_model.ComposeHTTPSCloneURL(ownerName, repoName), - "GoDocDirectory": prefix + "{/dir}", - "GoDocFile": prefix + "{/dir}/{file}#L{line}", - "Insecure": insecure, +`, func(key string) string { + switch key { + case "GoGetImport": + return context.ComposeGoGetImport(ownerName, trimmedRepoName) + case "CloneLink": + return repo_model.ComposeHTTPSCloneURL(ownerName, repoName) + case "GoDocDirectory": + return prefix + "{/dir}" + case "GoDocFile": + return prefix + "{/dir}/{file}#L{line}" + case "Insecure": + return insecure + default: + return ` + + + invalid import path + + + ` + } }) - if err != nil { - log.Error(err.Error()) - _, _ = ctx.Write([]byte(` - - - invalid import path - - -`)) - ctx.Status(400) - return - } - _, _ = ctx.Write([]byte(res)) } From 3a4d22a8b89ad774eaca993e61080e15bc7147e4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 1 Apr 2022 13:50:06 +0800 Subject: [PATCH 5/6] fix bug --- routers/web/repo/issue.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 8b9c513872b8a..b27f97d242e49 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1114,8 +1114,7 @@ func ViewIssue(ctx *context.Context) { metas["index"] = ctx.Params(":index") res, err := vars.Expand(extIssueUnit.ExternalTrackerConfig().ExternalTrackerFormat, metas) if err != nil { - log.Error("unable to expand template vars for issue url. issue: %s, err: %s", metas["index"], err.Error()) - ctx.ServerError("Expand", err) + ctx.ServerError("Expand", fmt.Errorf("unable to expand template vars for issue url. issue: %s, err: %s", metas["index"], err.Error())) return } ctx.Redirect(res) From b540046107e0e5bf5f61de85c79688a9cb05c870 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 1 Apr 2022 14:20:49 +0800 Subject: [PATCH 6/6] detail error --- modules/templates/vars/vars.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/templates/vars/vars.go b/modules/templates/vars/vars.go index edde41d708e42..f87fb842c5f9b 100644 --- a/modules/templates/vars/vars.go +++ b/modules/templates/vars/vars.go @@ -9,13 +9,14 @@ import ( "strings" ) -// ErrWrongSyntax represents a wrong syntax with a tempate +// ErrWrongSyntax represents a syntax error within a template type ErrWrongSyntax struct { Template string + Reason string } func (err ErrWrongSyntax) Error() string { - return fmt.Sprintf("Wrong syntax found in %s", err.Template) + return fmt.Sprintf("Wrong syntax found in %s: %s", err.Template, err.Reason) } // IsErrWrongSyntax returns true if the error is ErrWrongSyntax @@ -52,6 +53,7 @@ func Expand(template string, match map[string]string, subs ...string) (string, e if keyStartPos > -1 { return "", ErrWrongSyntax{ Template: template, + Reason: "\"{\" is not allowed to occur again before closing the variable", } } keyStartPos = i @@ -59,11 +61,13 @@ func Expand(template string, match map[string]string, subs ...string) (string, e if keyStartPos == -1 { return "", ErrWrongSyntax{ Template: template, + Reason: "\"}\" can only occur after an opening \"{\"", } } if i-keyStartPos <= 1 { return "", ErrWrongSyntax{ Template: template, + Reason: "the empty variable (\"{}\") is not allowed", } }