Skip to content

Commit b815a27

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Fix rendered wiki page link (go-gitea#31398) Refactor repo unit "disabled" check (go-gitea#31389) Refactor route path normalization (go-gitea#31381) Refactor markup code (go-gitea#31399) Add cache test for admins (go-gitea#31265) Fix double border in system status table (go-gitea#31363) Improve rubygems package registry (go-gitea#31357) Fix natural sort (go-gitea#31384) Fix missing images in editor preview due to wrong links (go-gitea#31299) Add a simple test for AdoptRepository (go-gitea#31391) [skip ci] Updated licenses and gitignores
2 parents 54fe6ea + 21783a5 commit b815a27

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+966
-565
lines changed

models/repo/repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ func (repo *Repository) LoadUnits(ctx context.Context) (err error) {
362362
if log.IsTrace() {
363363
unitTypeStrings := make([]string, len(repo.Units))
364364
for i, unit := range repo.Units {
365-
unitTypeStrings[i] = unit.Type.String()
365+
unitTypeStrings[i] = unit.Type.LogString()
366366
}
367367
log.Trace("repo.Units, ID=%d, Types: [%s]", repo.ID, strings.Join(unitTypeStrings, ", "))
368368
}

models/repo/repo_unit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func IsErrUnitTypeNotExist(err error) bool {
3333
}
3434

3535
func (err ErrUnitTypeNotExist) Error() string {
36-
return fmt.Sprintf("Unit type does not exist: %s", err.UT.String())
36+
return fmt.Sprintf("Unit type does not exist: %s", err.UT.LogString())
3737
}
3838

3939
func (err ErrUnitTypeNotExist) Unwrap() error {

models/unit/unit.go

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,39 +33,18 @@ const (
3333
TypeActions // 10 Actions
3434
)
3535

36-
// Value returns integer value for unit type
36+
// Value returns integer value for unit type (used by template)
3737
func (u Type) Value() int {
3838
return int(u)
3939
}
4040

41-
func (u Type) String() string {
42-
switch u {
43-
case TypeCode:
44-
return "TypeCode"
45-
case TypeIssues:
46-
return "TypeIssues"
47-
case TypePullRequests:
48-
return "TypePullRequests"
49-
case TypeReleases:
50-
return "TypeReleases"
51-
case TypeWiki:
52-
return "TypeWiki"
53-
case TypeExternalWiki:
54-
return "TypeExternalWiki"
55-
case TypeExternalTracker:
56-
return "TypeExternalTracker"
57-
case TypeProjects:
58-
return "TypeProjects"
59-
case TypePackages:
60-
return "TypePackages"
61-
case TypeActions:
62-
return "TypeActions"
63-
}
64-
return fmt.Sprintf("Unknown Type %d", u)
65-
}
66-
6741
func (u Type) LogString() string {
68-
return fmt.Sprintf("<UnitType:%d:%s>", u, u.String())
42+
unit, ok := Units[u]
43+
unitName := "unknown"
44+
if ok {
45+
unitName = unit.NameKey
46+
}
47+
return fmt.Sprintf("<UnitType:%d:%s>", u, unitName)
6948
}
7049

7150
var (
@@ -133,7 +112,7 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
133112
units = make([]Type, 0, len(settingDefaultUnits))
134113
for _, settingUnit := range settingDefaultUnits {
135114
if !settingUnit.CanBeDefault() {
136-
log.Warn("Not allowed as default unit: %s", settingUnit.String())
115+
log.Warn("Not allowed as default unit: %s", settingUnit.LogString())
137116
continue
138117
}
139118
units = append(units, settingUnit)

modules/base/natural_sort.go

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,67 @@
44
package base
55

66
import (
7+
"unicode/utf8"
8+
79
"golang.org/x/text/collate"
810
"golang.org/x/text/language"
911
)
1012

13+
func naturalSortGetRune(str string, pos int) (r rune, size int, has bool) {
14+
if pos >= len(str) {
15+
return 0, 0, false
16+
}
17+
r, size = utf8.DecodeRuneInString(str[pos:])
18+
if r == utf8.RuneError {
19+
r, size = rune(str[pos]), 1 // if invalid input, treat it as a single byte ascii
20+
}
21+
return r, size, true
22+
}
23+
24+
func naturalSortAdvance(str string, pos int) (end int, isNumber bool) {
25+
end = pos
26+
for {
27+
r, size, has := naturalSortGetRune(str, end)
28+
if !has {
29+
break
30+
}
31+
isCurRuneNum := '0' <= r && r <= '9'
32+
if end == pos {
33+
isNumber = isCurRuneNum
34+
end += size
35+
} else if isCurRuneNum == isNumber {
36+
end += size
37+
} else {
38+
break
39+
}
40+
}
41+
return end, isNumber
42+
}
43+
1144
// NaturalSortLess compares two strings so that they could be sorted in natural order
1245
func NaturalSortLess(s1, s2 string) bool {
46+
// There is a bug in Golang's collate package: https://github.com/golang/go/issues/67997
47+
// text/collate: CompareString(collate.Numeric) returns wrong result for "0.0" vs "1.0" #67997
48+
// So we need to handle the number parts by ourselves
1349
c := collate.New(language.English, collate.Numeric)
14-
return c.CompareString(s1, s2) < 0
50+
pos1, pos2 := 0, 0
51+
for pos1 < len(s1) && pos2 < len(s2) {
52+
end1, isNum1 := naturalSortAdvance(s1, pos1)
53+
end2, isNum2 := naturalSortAdvance(s2, pos2)
54+
part1, part2 := s1[pos1:end1], s2[pos2:end2]
55+
if isNum1 && isNum2 {
56+
if part1 != part2 {
57+
if len(part1) != len(part2) {
58+
return len(part1) < len(part2)
59+
}
60+
return part1 < part2
61+
}
62+
} else {
63+
if cmp := c.CompareString(part1, part2); cmp != 0 {
64+
return cmp < 0
65+
}
66+
}
67+
pos1, pos2 = end1, end2
68+
}
69+
return len(s1) < len(s2)
1570
}

modules/base/natural_sort_test.go

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,36 @@ import (
1010
)
1111

1212
func TestNaturalSortLess(t *testing.T) {
13-
test := func(s1, s2 string, less bool) {
14-
assert.Equal(t, less, NaturalSortLess(s1, s2), "s1=%q, s2=%q", s1, s2)
13+
testLess := func(s1, s2 string) {
14+
assert.True(t, NaturalSortLess(s1, s2), "s1<s2 should be true: s1=%q, s2=%q", s1, s2)
15+
assert.False(t, NaturalSortLess(s2, s1), "s2<s1 should be false: s1=%q, s2=%q", s1, s2)
1516
}
16-
test("v1.20.0", "v1.2.0", false)
17-
test("v1.20.0", "v1.29.0", true)
18-
test("v1.20.0", "v1.20.0", false)
19-
test("abc", "bcd", true)
20-
test("a-1-a", "a-1-b", true)
21-
test("2", "12", true)
22-
test("a", "ab", true)
23-
24-
test("A", "b", true)
25-
test("a", "B", true)
26-
27-
test("cafe", "café", true)
28-
test("café", "cafe", false)
29-
test("caff", "café", false)
17+
testEqual := func(s1, s2 string) {
18+
assert.False(t, NaturalSortLess(s1, s2), "s1<s2 should be false: s1=%q, s2=%q", s1, s2)
19+
assert.False(t, NaturalSortLess(s2, s1), "s2<s1 should be false: s1=%q, s2=%q", s1, s2)
20+
}
21+
22+
testEqual("", "")
23+
testLess("", "a")
24+
testLess("", "1")
25+
26+
testLess("v1.2", "v1.2.0")
27+
testLess("v1.2.0", "v1.10.0")
28+
testLess("v1.20.0", "v1.29.0")
29+
testEqual("v1.20.0", "v1.20.0")
30+
31+
testLess("a", "A")
32+
testLess("a", "B")
33+
testLess("A", "b")
34+
testLess("A", "ab")
35+
36+
testLess("abc", "bcd")
37+
testLess("a-1-a", "a-1-b")
38+
testLess("2", "12")
39+
40+
testLess("cafe", "café")
41+
testLess("café", "caff")
42+
43+
testLess("A-2", "A-11")
44+
testLess("0.txt", "1.txt")
3045
}

modules/cache/cache.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package cache
55

66
import (
7+
"fmt"
78
"strconv"
89
"time"
910

@@ -35,6 +36,37 @@ func Init() error {
3536
return nil
3637
}
3738

39+
const (
40+
testCacheKey = "DefaultCache.TestKey"
41+
SlowCacheThreshold = 100 * time.Microsecond
42+
)
43+
44+
func Test() (time.Duration, error) {
45+
if defaultCache == nil {
46+
return 0, fmt.Errorf("default cache not initialized")
47+
}
48+
49+
testData := fmt.Sprintf("%x", make([]byte, 500))
50+
51+
start := time.Now()
52+
53+
if err := defaultCache.Delete(testCacheKey); err != nil {
54+
return 0, fmt.Errorf("expect cache to delete data based on key if exist but got: %w", err)
55+
}
56+
if err := defaultCache.Put(testCacheKey, testData, 10); err != nil {
57+
return 0, fmt.Errorf("expect cache to store data but got: %w", err)
58+
}
59+
testVal, hit := defaultCache.Get(testCacheKey)
60+
if !hit {
61+
return 0, fmt.Errorf("expect cache hit but got none")
62+
}
63+
if testVal != testData {
64+
return 0, fmt.Errorf("expect cache to return same value as stored but got other")
65+
}
66+
67+
return time.Since(start), nil
68+
}
69+
3870
// GetCache returns the currently configured cache
3971
func GetCache() StringCache {
4072
return defaultCache

modules/cache/cache_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ func TestNewContext(t *testing.T) {
3434
assert.Nil(t, con)
3535
}
3636

37+
func TestTest(t *testing.T) {
38+
defaultCache = nil
39+
_, err := Test()
40+
assert.Error(t, err)
41+
42+
createTestCache()
43+
elapsed, err := Test()
44+
assert.NoError(t, err)
45+
// mem cache should take from 300ns up to 1ms on modern hardware ...
46+
assert.Less(t, elapsed, SlowCacheThreshold)
47+
}
48+
3749
func TestGetCache(t *testing.T) {
3850
createTestCache()
3951

modules/markup/html.go

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -144,20 +144,6 @@ func CustomLinkURLSchemes(schemes []string) {
144144
common.LinkRegex, _ = xurls.StrictMatchingScheme(strings.Join(withAuth, "|"))
145145
}
146146

147-
// IsSameDomain checks if given url string has the same hostname as current Gitea instance
148-
func IsSameDomain(s string) bool {
149-
if strings.HasPrefix(s, "/") {
150-
return true
151-
}
152-
if uapp, err := url.Parse(setting.AppURL); err == nil {
153-
if u, err := url.Parse(s); err == nil {
154-
return u.Host == uapp.Host
155-
}
156-
return false
157-
}
158-
return false
159-
}
160-
161147
type postProcessError struct {
162148
context string
163149
err error
@@ -429,7 +415,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Nod
429415
// We ignore code and pre.
430416
switch node.Type {
431417
case html.TextNode:
432-
textNode(ctx, procs, node)
418+
processTextNodes(ctx, procs, node)
433419
case html.ElementNode:
434420
if node.Data == "img" {
435421
next := node.NextSibling
@@ -465,15 +451,16 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Nod
465451
for n := node.FirstChild; n != nil; {
466452
n = visitNode(ctx, procs, n)
467453
}
454+
default:
468455
}
469456
return node.NextSibling
470457
}
471458

472-
// textNode runs the passed node through various processors, in order to handle
459+
// processTextNodes runs the passed node through various processors, in order to handle
473460
// all kinds of special links handled by the post-processing.
474-
func textNode(ctx *RenderContext, procs []processor, node *html.Node) {
475-
for _, processor := range procs {
476-
processor(ctx, node)
461+
func processTextNodes(ctx *RenderContext, procs []processor, node *html.Node) {
462+
for _, p := range procs {
463+
p(ctx, node)
477464
}
478465
}
479466

@@ -761,10 +748,10 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
761748
if image {
762749
link = strings.ReplaceAll(link, " ", "+")
763750
} else {
764-
link = strings.ReplaceAll(link, " ", "-")
751+
link = strings.ReplaceAll(link, " ", "-") // FIXME: it should support dashes in the link, eg: "the-dash-support.-"
765752
}
766753
if !strings.Contains(link, "/") {
767-
link = url.PathEscape(link)
754+
link = url.PathEscape(link) // FIXME: it doesn't seem right and it might cause double-escaping
768755
}
769756
}
770757
if image {
@@ -796,28 +783,7 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
796783
childNode.Attr = childNode.Attr[:2]
797784
}
798785
} else {
799-
if !absoluteLink {
800-
var base string
801-
if ctx.IsWiki {
802-
switch ext {
803-
case "":
804-
// no file extension, create a regular wiki link
805-
base = ctx.Links.WikiLink()
806-
default:
807-
// we have a file extension:
808-
// return a regular wiki link if it's a renderable file (extension),
809-
// raw link otherwise
810-
if Type(link) != "" {
811-
base = ctx.Links.WikiLink()
812-
} else {
813-
base = ctx.Links.WikiRawLink()
814-
}
815-
}
816-
} else {
817-
base = ctx.Links.SrcLink()
818-
}
819-
link = util.URLJoin(base, link)
820-
}
786+
link, _ = ResolveLink(ctx, link, "")
821787
childNode.Type = html.TextNode
822788
childNode.Data = name
823789
}
@@ -939,14 +905,11 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
939905
// Path determines the type of link that will be rendered. It's unknown at this point whether
940906
// the linked item is actually a PR or an issue. Luckily it's of no real consequence because
941907
// Gitea will redirect on click as appropriate.
942-
path := "issues"
943-
if ref.IsPull {
944-
path = "pulls"
945-
}
908+
issuePath := util.Iif(ref.IsPull, "pulls", "issues")
946909
if ref.Owner == "" {
947-
link = createLink(util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], path, ref.Issue), reftext, "ref-issue")
910+
link = createLink(util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], issuePath, ref.Issue), reftext, "ref-issue")
948911
} else {
949-
link = createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, path, ref.Issue), reftext, "ref-issue")
912+
link = createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, issuePath, ref.Issue), reftext, "ref-issue")
950913
}
951914
}
952915

@@ -1207,7 +1170,7 @@ func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
12071170
return
12081171
}
12091172
ctx.AddCancel(func() {
1210-
closer.Close()
1173+
_ = closer.Close()
12111174
ctx.GitRepo = nil
12121175
})
12131176
}

0 commit comments

Comments
 (0)