Skip to content

Commit

Permalink
Merge remote-tracking branch 'giteaofficial/main'
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
zjjhot committed Jun 18, 2024
2 parents 54fe6ea + 21783a5 commit b815a27
Show file tree
Hide file tree
Showing 50 changed files with 966 additions and 565 deletions.
2 changes: 1 addition & 1 deletion models/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ func (repo *Repository) LoadUnits(ctx context.Context) (err error) {
if log.IsTrace() {
unitTypeStrings := make([]string, len(repo.Units))
for i, unit := range repo.Units {
unitTypeStrings[i] = unit.Type.String()
unitTypeStrings[i] = unit.Type.LogString()
}
log.Trace("repo.Units, ID=%d, Types: [%s]", repo.ID, strings.Join(unitTypeStrings, ", "))
}
Expand Down
2 changes: 1 addition & 1 deletion models/repo/repo_unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func IsErrUnitTypeNotExist(err error) bool {
}

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

func (err ErrUnitTypeNotExist) Unwrap() error {
Expand Down
37 changes: 8 additions & 29 deletions models/unit/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,39 +33,18 @@ const (
TypeActions // 10 Actions
)

// Value returns integer value for unit type
// Value returns integer value for unit type (used by template)
func (u Type) Value() int {
return int(u)
}

func (u Type) String() string {
switch u {
case TypeCode:
return "TypeCode"
case TypeIssues:
return "TypeIssues"
case TypePullRequests:
return "TypePullRequests"
case TypeReleases:
return "TypeReleases"
case TypeWiki:
return "TypeWiki"
case TypeExternalWiki:
return "TypeExternalWiki"
case TypeExternalTracker:
return "TypeExternalTracker"
case TypeProjects:
return "TypeProjects"
case TypePackages:
return "TypePackages"
case TypeActions:
return "TypeActions"
}
return fmt.Sprintf("Unknown Type %d", u)
}

func (u Type) LogString() string {
return fmt.Sprintf("<UnitType:%d:%s>", u, u.String())
unit, ok := Units[u]
unitName := "unknown"
if ok {
unitName = unit.NameKey
}
return fmt.Sprintf("<UnitType:%d:%s>", u, unitName)
}

var (
Expand Down Expand Up @@ -133,7 +112,7 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
units = make([]Type, 0, len(settingDefaultUnits))
for _, settingUnit := range settingDefaultUnits {
if !settingUnit.CanBeDefault() {
log.Warn("Not allowed as default unit: %s", settingUnit.String())
log.Warn("Not allowed as default unit: %s", settingUnit.LogString())
continue
}
units = append(units, settingUnit)
Expand Down
57 changes: 56 additions & 1 deletion modules/base/natural_sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,67 @@
package base

import (
"unicode/utf8"

"golang.org/x/text/collate"
"golang.org/x/text/language"
)

func naturalSortGetRune(str string, pos int) (r rune, size int, has bool) {
if pos >= len(str) {
return 0, 0, false
}
r, size = utf8.DecodeRuneInString(str[pos:])
if r == utf8.RuneError {
r, size = rune(str[pos]), 1 // if invalid input, treat it as a single byte ascii
}
return r, size, true
}

func naturalSortAdvance(str string, pos int) (end int, isNumber bool) {
end = pos
for {
r, size, has := naturalSortGetRune(str, end)
if !has {
break
}
isCurRuneNum := '0' <= r && r <= '9'
if end == pos {
isNumber = isCurRuneNum
end += size
} else if isCurRuneNum == isNumber {
end += size
} else {
break
}
}
return end, isNumber
}

// NaturalSortLess compares two strings so that they could be sorted in natural order
func NaturalSortLess(s1, s2 string) bool {
// There is a bug in Golang's collate package: https://github.com/golang/go/issues/67997
// text/collate: CompareString(collate.Numeric) returns wrong result for "0.0" vs "1.0" #67997
// So we need to handle the number parts by ourselves
c := collate.New(language.English, collate.Numeric)
return c.CompareString(s1, s2) < 0
pos1, pos2 := 0, 0
for pos1 < len(s1) && pos2 < len(s2) {
end1, isNum1 := naturalSortAdvance(s1, pos1)
end2, isNum2 := naturalSortAdvance(s2, pos2)
part1, part2 := s1[pos1:end1], s2[pos2:end2]
if isNum1 && isNum2 {
if part1 != part2 {
if len(part1) != len(part2) {
return len(part1) < len(part2)
}
return part1 < part2
}
} else {
if cmp := c.CompareString(part1, part2); cmp != 0 {
return cmp < 0
}
}
pos1, pos2 = end1, end2
}
return len(s1) < len(s2)
}
47 changes: 31 additions & 16 deletions modules/base/natural_sort_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,36 @@ import (
)

func TestNaturalSortLess(t *testing.T) {
test := func(s1, s2 string, less bool) {
assert.Equal(t, less, NaturalSortLess(s1, s2), "s1=%q, s2=%q", s1, s2)
testLess := func(s1, s2 string) {
assert.True(t, NaturalSortLess(s1, s2), "s1<s2 should be true: s1=%q, s2=%q", s1, s2)
assert.False(t, NaturalSortLess(s2, s1), "s2<s1 should be false: s1=%q, s2=%q", s1, s2)
}
test("v1.20.0", "v1.2.0", false)
test("v1.20.0", "v1.29.0", true)
test("v1.20.0", "v1.20.0", false)
test("abc", "bcd", true)
test("a-1-a", "a-1-b", true)
test("2", "12", true)
test("a", "ab", true)

test("A", "b", true)
test("a", "B", true)

test("cafe", "café", true)
test("café", "cafe", false)
test("caff", "café", false)
testEqual := func(s1, s2 string) {
assert.False(t, NaturalSortLess(s1, s2), "s1<s2 should be false: s1=%q, s2=%q", s1, s2)
assert.False(t, NaturalSortLess(s2, s1), "s2<s1 should be false: s1=%q, s2=%q", s1, s2)
}

testEqual("", "")
testLess("", "a")
testLess("", "1")

testLess("v1.2", "v1.2.0")
testLess("v1.2.0", "v1.10.0")
testLess("v1.20.0", "v1.29.0")
testEqual("v1.20.0", "v1.20.0")

testLess("a", "A")
testLess("a", "B")
testLess("A", "b")
testLess("A", "ab")

testLess("abc", "bcd")
testLess("a-1-a", "a-1-b")
testLess("2", "12")

testLess("cafe", "café")
testLess("café", "caff")

testLess("A-2", "A-11")
testLess("0.txt", "1.txt")
}
32 changes: 32 additions & 0 deletions modules/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cache

import (
"fmt"
"strconv"
"time"

Expand Down Expand Up @@ -35,6 +36,37 @@ func Init() error {
return nil
}

const (
testCacheKey = "DefaultCache.TestKey"
SlowCacheThreshold = 100 * time.Microsecond
)

func Test() (time.Duration, error) {
if defaultCache == nil {
return 0, fmt.Errorf("default cache not initialized")
}

testData := fmt.Sprintf("%x", make([]byte, 500))

start := time.Now()

if err := defaultCache.Delete(testCacheKey); err != nil {
return 0, fmt.Errorf("expect cache to delete data based on key if exist but got: %w", err)
}
if err := defaultCache.Put(testCacheKey, testData, 10); err != nil {
return 0, fmt.Errorf("expect cache to store data but got: %w", err)
}
testVal, hit := defaultCache.Get(testCacheKey)
if !hit {
return 0, fmt.Errorf("expect cache hit but got none")
}
if testVal != testData {
return 0, fmt.Errorf("expect cache to return same value as stored but got other")
}

return time.Since(start), nil
}

// GetCache returns the currently configured cache
func GetCache() StringCache {
return defaultCache
Expand Down
12 changes: 12 additions & 0 deletions modules/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ func TestNewContext(t *testing.T) {
assert.Nil(t, con)
}

func TestTest(t *testing.T) {
defaultCache = nil
_, err := Test()
assert.Error(t, err)

createTestCache()
elapsed, err := Test()
assert.NoError(t, err)
// mem cache should take from 300ns up to 1ms on modern hardware ...
assert.Less(t, elapsed, SlowCacheThreshold)
}

func TestGetCache(t *testing.T) {
createTestCache()

Expand Down
63 changes: 13 additions & 50 deletions modules/markup/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,20 +144,6 @@ func CustomLinkURLSchemes(schemes []string) {
common.LinkRegex, _ = xurls.StrictMatchingScheme(strings.Join(withAuth, "|"))
}

// IsSameDomain checks if given url string has the same hostname as current Gitea instance
func IsSameDomain(s string) bool {
if strings.HasPrefix(s, "/") {
return true
}
if uapp, err := url.Parse(setting.AppURL); err == nil {
if u, err := url.Parse(s); err == nil {
return u.Host == uapp.Host
}
return false
}
return false
}

type postProcessError struct {
context string
err error
Expand Down Expand Up @@ -429,7 +415,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Nod
// We ignore code and pre.
switch node.Type {
case html.TextNode:
textNode(ctx, procs, node)
processTextNodes(ctx, procs, node)
case html.ElementNode:
if node.Data == "img" {
next := node.NextSibling
Expand Down Expand Up @@ -465,15 +451,16 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Nod
for n := node.FirstChild; n != nil; {
n = visitNode(ctx, procs, n)
}
default:
}
return node.NextSibling
}

// textNode runs the passed node through various processors, in order to handle
// processTextNodes runs the passed node through various processors, in order to handle
// all kinds of special links handled by the post-processing.
func textNode(ctx *RenderContext, procs []processor, node *html.Node) {
for _, processor := range procs {
processor(ctx, node)
func processTextNodes(ctx *RenderContext, procs []processor, node *html.Node) {
for _, p := range procs {
p(ctx, node)
}
}

Expand Down Expand Up @@ -761,10 +748,10 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
if image {
link = strings.ReplaceAll(link, " ", "+")
} else {
link = strings.ReplaceAll(link, " ", "-")
link = strings.ReplaceAll(link, " ", "-") // FIXME: it should support dashes in the link, eg: "the-dash-support.-"
}
if !strings.Contains(link, "/") {
link = url.PathEscape(link)
link = url.PathEscape(link) // FIXME: it doesn't seem right and it might cause double-escaping
}
}
if image {
Expand Down Expand Up @@ -796,28 +783,7 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
childNode.Attr = childNode.Attr[:2]
}
} else {
if !absoluteLink {
var base string
if ctx.IsWiki {
switch ext {
case "":
// no file extension, create a regular wiki link
base = ctx.Links.WikiLink()
default:
// we have a file extension:
// return a regular wiki link if it's a renderable file (extension),
// raw link otherwise
if Type(link) != "" {
base = ctx.Links.WikiLink()
} else {
base = ctx.Links.WikiRawLink()
}
}
} else {
base = ctx.Links.SrcLink()
}
link = util.URLJoin(base, link)
}
link, _ = ResolveLink(ctx, link, "")
childNode.Type = html.TextNode
childNode.Data = name
}
Expand Down Expand Up @@ -939,14 +905,11 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
// 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
// Gitea will redirect on click as appropriate.
path := "issues"
if ref.IsPull {
path = "pulls"
}
issuePath := util.Iif(ref.IsPull, "pulls", "issues")
if ref.Owner == "" {
link = createLink(util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], path, ref.Issue), reftext, "ref-issue")
link = createLink(util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], issuePath, ref.Issue), reftext, "ref-issue")
} else {
link = createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, path, ref.Issue), reftext, "ref-issue")
link = createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, issuePath, ref.Issue), reftext, "ref-issue")
}
}

Expand Down Expand Up @@ -1207,7 +1170,7 @@ func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
return
}
ctx.AddCancel(func() {
closer.Close()
_ = closer.Close()
ctx.GitRepo = nil
})
}
Expand Down
Loading

0 comments on commit b815a27

Please sign in to comment.