Skip to content

Commit 3c7718b

Browse files
committed
Merge branch 'main' into link-to-symlink
2 parents 59edd90 + a94e472 commit 3c7718b

Some content is hidden

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

83 files changed

+960
-757
lines changed

models/db/context.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,15 @@ func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error
178178
return txWithNoCheck(parentCtx, f)
179179
}
180180

181+
// WithTx2 is similar to WithTx, but it has two return values: result and error.
182+
func WithTx2[T any](parentCtx context.Context, f func(ctx context.Context) (T, error)) (ret T, errRet error) {
183+
errRet = WithTx(parentCtx, func(ctx context.Context) (errInner error) {
184+
ret, errInner = f(ctx)
185+
return errInner
186+
})
187+
return ret, errRet
188+
}
189+
181190
func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error {
182191
sess := xormEngine.NewSession()
183192
defer sess.Close()

modules/git/blob.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,22 @@ func (b *Blob) Name() string {
2222
return b.name
2323
}
2424

25-
// GetBlobContent Gets the limited content of the blob as raw text
26-
func (b *Blob) GetBlobContent(limit int64) (string, error) {
25+
// GetBlobBytes Gets the limited content of the blob
26+
func (b *Blob) GetBlobBytes(limit int64) ([]byte, error) {
2727
if limit <= 0 {
28-
return "", nil
28+
return nil, nil
2929
}
3030
dataRc, err := b.DataAsync()
3131
if err != nil {
32-
return "", err
32+
return nil, err
3333
}
3434
defer dataRc.Close()
35-
buf, err := util.ReadWithLimit(dataRc, int(limit))
35+
return util.ReadWithLimit(dataRc, int(limit))
36+
}
37+
38+
// GetBlobContent Gets the limited content of the blob as raw text
39+
func (b *Blob) GetBlobContent(limit int64) (string, error) {
40+
buf, err := b.GetBlobBytes(limit)
3641
return string(buf), err
3742
}
3843

@@ -99,11 +104,9 @@ loop:
99104

100105
// GuessContentType guesses the content type of the blob.
101106
func (b *Blob) GuessContentType() (typesniffer.SniffedType, error) {
102-
r, err := b.DataAsync()
107+
buf, err := b.GetBlobBytes(typesniffer.SniffContentSize)
103108
if err != nil {
104109
return typesniffer.SniffedType{}, err
105110
}
106-
defer r.Close()
107-
108-
return typesniffer.DetectContentTypeFromReader(r)
111+
return typesniffer.DetectContentType(buf), nil
109112
}

modules/markup/console/console.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ package console
66
import (
77
"bytes"
88
"io"
9-
"path"
9+
"unicode/utf8"
1010

1111
"code.gitea.io/gitea/modules/markup"
1212
"code.gitea.io/gitea/modules/setting"
13+
"code.gitea.io/gitea/modules/typesniffer"
14+
"code.gitea.io/gitea/modules/util"
1315

1416
trend "github.com/buildkite/terminal-to-html/v3"
15-
"github.com/go-enry/go-enry/v2"
1617
)
1718

1819
func init() {
@@ -22,6 +23,8 @@ func init() {
2223
// Renderer implements markup.Renderer
2324
type Renderer struct{}
2425

26+
var _ markup.RendererContentDetector = (*Renderer)(nil)
27+
2528
// Name implements markup.Renderer
2629
func (Renderer) Name() string {
2730
return "console"
@@ -40,15 +43,36 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
4043
}
4144

4245
// CanRender implements markup.RendererContentDetector
43-
func (Renderer) CanRender(filename string, input io.Reader) bool {
44-
buf, err := io.ReadAll(input)
45-
if err != nil {
46+
func (Renderer) CanRender(filename string, sniffedType typesniffer.SniffedType, prefetchBuf []byte) bool {
47+
if !sniffedType.IsTextPlain() {
4648
return false
4749
}
48-
if enry.GetLanguage(path.Base(filename), buf) != enry.OtherLanguage {
50+
51+
s := util.UnsafeBytesToString(prefetchBuf)
52+
rs := []rune(s)
53+
cnt := 0
54+
firstErrPos := -1
55+
isCtrlSep := func(p int) bool {
56+
return p < len(rs) && (rs[p] == ';' || rs[p] == 'm')
57+
}
58+
for i, c := range rs {
59+
if c == 0 {
60+
return false
61+
}
62+
if c == '\x1b' {
63+
match := i+1 < len(rs) && rs[i+1] == '['
64+
if match && (isCtrlSep(i+2) || isCtrlSep(i+3) || isCtrlSep(i+4) || isCtrlSep(i+5)) {
65+
cnt++
66+
}
67+
}
68+
if c == utf8.RuneError && firstErrPos == -1 {
69+
firstErrPos = i
70+
}
71+
}
72+
if firstErrPos != -1 && firstErrPos != len(rs)-1 {
4973
return false
5074
}
51-
return bytes.ContainsRune(buf, '\x1b')
75+
return cnt >= 2 // only render it as console output if there are at least two escape sequences
5276
}
5377

5478
// Render renders terminal colors to HTML with all specific handling stuff.

modules/markup/console/console_test.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,39 @@ import (
88
"testing"
99

1010
"code.gitea.io/gitea/modules/markup"
11+
"code.gitea.io/gitea/modules/typesniffer"
1112

1213
"github.com/stretchr/testify/assert"
1314
)
1415

1516
func TestRenderConsole(t *testing.T) {
16-
var render Renderer
17-
kases := map[string]string{
18-
"\x1b[37m\x1b[40mnpm\x1b[0m \x1b[0m\x1b[32minfo\x1b[0m \x1b[0m\x1b[35mit worked if it ends with\x1b[0m ok": "<span class=\"term-fg37 term-bg40\">npm</span> <span class=\"term-fg32\">info</span> <span class=\"term-fg35\">it worked if it ends with</span> ok",
17+
cases := []struct {
18+
input string
19+
expected string
20+
}{
21+
{"\x1b[37m\x1b[40mnpm\x1b[0m \x1b[0m\x1b[32minfo\x1b[0m \x1b[0m\x1b[35mit worked if it ends with\x1b[0m ok", `<span class="term-fg37 term-bg40">npm</span> <span class="term-fg32">info</span> <span class="term-fg35">it worked if it ends with</span> ok`},
22+
{"\x1b[1;2m \x1b[123m 啊", `<span class="term-fg2"> 啊</span>`},
23+
{"\x1b[1;2m \x1b[123m \xef", `<span class="term-fg2"> �</span>`},
24+
{"\x1b[1;2m \x1b[123m \xef \xef", ``},
25+
{"\x1b[12", ``},
26+
{"\x1b[1", ``},
27+
{"\x1b[FOO\x1b[", ``},
28+
{"\x1b[mFOO\x1b[m", `FOO`},
1929
}
2030

21-
for k, v := range kases {
31+
var render Renderer
32+
for i, c := range cases {
2233
var buf strings.Builder
23-
canRender := render.CanRender("test", strings.NewReader(k))
24-
assert.True(t, canRender)
34+
st := typesniffer.DetectContentType([]byte(c.input))
35+
canRender := render.CanRender("test", st, []byte(c.input))
36+
if c.expected == "" {
37+
assert.False(t, canRender, "case %d: expected not to render", i)
38+
continue
39+
}
2540

26-
err := render.Render(markup.NewRenderContext(t.Context()), strings.NewReader(k), &buf)
41+
assert.True(t, canRender)
42+
err := render.Render(markup.NewRenderContext(t.Context()), strings.NewReader(c.input), &buf)
2743
assert.NoError(t, err)
28-
assert.Equal(t, v, buf.String())
44+
assert.Equal(t, c.expected, buf.String())
2945
}
3046
}

modules/markup/renderer.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
package markup
55

66
import (
7-
"bytes"
87
"io"
98
"path"
109
"strings"
1110

1211
"code.gitea.io/gitea/modules/setting"
12+
"code.gitea.io/gitea/modules/typesniffer"
1313
)
1414

1515
// Renderer defines an interface for rendering markup file to HTML
@@ -37,7 +37,7 @@ type ExternalRenderer interface {
3737
// RendererContentDetector detects if the content can be rendered
3838
// by specified renderer
3939
type RendererContentDetector interface {
40-
CanRender(filename string, input io.Reader) bool
40+
CanRender(filename string, sniffedType typesniffer.SniffedType, prefetchBuf []byte) bool
4141
}
4242

4343
var (
@@ -60,13 +60,9 @@ func GetRendererByFileName(filename string) Renderer {
6060
}
6161

6262
// DetectRendererType detects the markup type of the content
63-
func DetectRendererType(filename string, input io.Reader) string {
64-
buf, err := io.ReadAll(input)
65-
if err != nil {
66-
return ""
67-
}
63+
func DetectRendererType(filename string, sniffedType typesniffer.SniffedType, prefetchBuf []byte) string {
6864
for _, renderer := range renderers {
69-
if detector, ok := renderer.(RendererContentDetector); ok && detector.CanRender(filename, bytes.NewReader(buf)) {
65+
if detector, ok := renderer.(RendererContentDetector); ok && detector.CanRender(filename, sniffedType, prefetchBuf) {
7066
return renderer.Name()
7167
}
7268
}

modules/structs/admin_user.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ import "time"
88

99
// CreateUserOption create user options
1010
type CreateUserOption struct {
11-
SourceID int64 `json:"source_id"`
11+
SourceID int64 `json:"source_id"`
12+
// identifier of the user, provided by the external authenticator (if configured)
13+
// default: empty
1214
LoginName string `json:"login_name"`
15+
// username of the user
1316
// required: true
1417
Username string `json:"username" binding:"Required;Username;MaxSize(40)"`
1518
FullName string `json:"full_name" binding:"MaxSize(100)"`
@@ -32,6 +35,8 @@ type CreateUserOption struct {
3235
type EditUserOption struct {
3336
// required: true
3437
SourceID int64 `json:"source_id"`
38+
// identifier of the user, provided by the external authenticator (if configured)
39+
// default: empty
3540
// required: true
3641
LoginName string `json:"login_name" binding:"Required"`
3742
// swagger:strfmt email

modules/structs/hook.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ type PayloadUser struct {
7171
// Full name of the commit author
7272
Name string `json:"name"`
7373
// swagger:strfmt email
74-
Email string `json:"email"`
74+
Email string `json:"email"`
75+
// username of the user
7576
UserName string `json:"username"`
7677
}
7778

modules/structs/issue_tracked_time.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type AddTimeOption struct {
1414
Time int64 `json:"time" binding:"Required"`
1515
// swagger:strfmt date-time
1616
Created time.Time `json:"created"`
17-
// User who spent the time (optional)
17+
// username of the user who spent the time working on the issue (optional)
1818
User string `json:"user_name"`
1919
}
2020

@@ -26,7 +26,8 @@ type TrackedTime struct {
2626
// Time in seconds
2727
Time int64 `json:"time"`
2828
// deprecated (only for backwards compatibility)
29-
UserID int64 `json:"user_id"`
29+
UserID int64 `json:"user_id"`
30+
// username of the user
3031
UserName string `json:"user_name"`
3132
// deprecated (only for backwards compatibility)
3233
IssueID int64 `json:"issue_id"`

modules/structs/org.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type Organization struct {
1515
Location string `json:"location"`
1616
Visibility string `json:"visibility"`
1717
RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"`
18+
// username of the organization
1819
// deprecated
1920
UserName string `json:"username"`
2021
}
@@ -30,6 +31,7 @@ type OrganizationPermissions struct {
3031

3132
// CreateOrgOption options for creating an organization
3233
type CreateOrgOption struct {
34+
// username of the organization
3335
// required: true
3436
UserName string `json:"username" binding:"Required;Username;MaxSize(40)"`
3537
FullName string `json:"full_name" binding:"MaxSize(100)"`

modules/structs/user.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import (
1515
type User struct {
1616
// the user's id
1717
ID int64 `json:"id"`
18-
// the user's username
18+
// login of the user, same as `username`
1919
UserName string `json:"login"`
20-
// the user's authentication sign-in name.
20+
// identifier of the user, provided by the external authenticator (if configured)
2121
// default: empty
2222
LoginName string `json:"login_name"`
2323
// The ID of the user's Authentication Source

0 commit comments

Comments
 (0)