Skip to content

Commit ae0af8e

Browse files
lunnywxiaoguangyp05327
authored
Refactor Git Attribute & performance optimization (#34154)
This PR moved git attributes related code to `modules/git/attribute` sub package and moved language stats related code to `modules/git/languagestats` sub package to make it easier to maintain. And it also introduced a performance improvement which use the `git check-attr --source` which can be run in a bare git repository so that we don't need to create a git index file. The new parameter need a git version >= 2.40 . If git version less than 2.40, it will fall back to previous implementation. --------- Co-authored-by: wxiaoguang <[email protected]> Co-authored-by: yp05327 <[email protected]>
1 parent d725b78 commit ae0af8e

28 files changed

+867
-579
lines changed

modules/git/attribute.go

Lines changed: 0 additions & 35 deletions
This file was deleted.

modules/git/attribute/attribute.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package attribute
5+
6+
import (
7+
"strings"
8+
9+
"code.gitea.io/gitea/modules/optional"
10+
)
11+
12+
type Attribute string
13+
14+
const (
15+
LinguistVendored = "linguist-vendored"
16+
LinguistGenerated = "linguist-generated"
17+
LinguistDocumentation = "linguist-documentation"
18+
LinguistDetectable = "linguist-detectable"
19+
LinguistLanguage = "linguist-language"
20+
GitlabLanguage = "gitlab-language"
21+
Lockable = "lockable"
22+
Filter = "filter"
23+
)
24+
25+
var LinguistAttributes = []string{
26+
LinguistVendored,
27+
LinguistGenerated,
28+
LinguistDocumentation,
29+
LinguistDetectable,
30+
LinguistLanguage,
31+
GitlabLanguage,
32+
}
33+
34+
func (a Attribute) IsUnspecified() bool {
35+
return a == "" || a == "unspecified"
36+
}
37+
38+
func (a Attribute) ToString() optional.Option[string] {
39+
if !a.IsUnspecified() {
40+
return optional.Some(string(a))
41+
}
42+
return optional.None[string]()
43+
}
44+
45+
// ToBool converts the attribute value to optional boolean: true if "set"/"true", false if "unset"/"false", none otherwise
46+
func (a Attribute) ToBool() optional.Option[bool] {
47+
switch a {
48+
case "set", "true":
49+
return optional.Some(true)
50+
case "unset", "false":
51+
return optional.Some(false)
52+
}
53+
return optional.None[bool]()
54+
}
55+
56+
type Attributes struct {
57+
m map[string]Attribute
58+
}
59+
60+
func NewAttributes() *Attributes {
61+
return &Attributes{m: make(map[string]Attribute)}
62+
}
63+
64+
func (attrs *Attributes) Get(name string) Attribute {
65+
if value, has := attrs.m[name]; has {
66+
return value
67+
}
68+
return ""
69+
}
70+
71+
func (attrs *Attributes) GetVendored() optional.Option[bool] {
72+
return attrs.Get(LinguistVendored).ToBool()
73+
}
74+
75+
func (attrs *Attributes) GetGenerated() optional.Option[bool] {
76+
return attrs.Get(LinguistGenerated).ToBool()
77+
}
78+
79+
func (attrs *Attributes) GetDocumentation() optional.Option[bool] {
80+
return attrs.Get(LinguistDocumentation).ToBool()
81+
}
82+
83+
func (attrs *Attributes) GetDetectable() optional.Option[bool] {
84+
return attrs.Get(LinguistDetectable).ToBool()
85+
}
86+
87+
func (attrs *Attributes) GetLinguistLanguage() optional.Option[string] {
88+
return attrs.Get(LinguistLanguage).ToString()
89+
}
90+
91+
func (attrs *Attributes) GetGitlabLanguage() optional.Option[string] {
92+
attrStr := attrs.Get(GitlabLanguage).ToString()
93+
if attrStr.Has() {
94+
raw := attrStr.Value()
95+
// gitlab-language may have additional parameters after the language
96+
// ignore them and just use the main language
97+
// https://docs.gitlab.com/ee/user/project/highlighting.html#override-syntax-highlighting-for-a-file-type
98+
if idx := strings.IndexByte(raw, '?'); idx >= 0 {
99+
return optional.Some(raw[:idx])
100+
}
101+
}
102+
return attrStr
103+
}
104+
105+
func (attrs *Attributes) GetLanguage() optional.Option[string] {
106+
// prefer linguist-language over gitlab-language
107+
// if linguist-language is not set, use gitlab-language
108+
// if both are not set, return none
109+
language := attrs.GetLinguistLanguage()
110+
if language.Value() == "" {
111+
language = attrs.GetGitlabLanguage()
112+
}
113+
return language
114+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package attribute
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func Test_Attribute(t *testing.T) {
13+
assert.Empty(t, Attribute("").ToString().Value())
14+
assert.Empty(t, Attribute("unspecified").ToString().Value())
15+
assert.Equal(t, "python", Attribute("python").ToString().Value())
16+
assert.Equal(t, "Java", Attribute("Java").ToString().Value())
17+
18+
attributes := Attributes{
19+
m: map[string]Attribute{
20+
LinguistGenerated: "true",
21+
LinguistDocumentation: "false",
22+
LinguistDetectable: "set",
23+
LinguistLanguage: "Python",
24+
GitlabLanguage: "Java",
25+
"filter": "unspecified",
26+
"test": "",
27+
},
28+
}
29+
30+
assert.Empty(t, attributes.Get("test").ToString().Value())
31+
assert.Empty(t, attributes.Get("filter").ToString().Value())
32+
assert.Equal(t, "Python", attributes.Get(LinguistLanguage).ToString().Value())
33+
assert.Equal(t, "Java", attributes.Get(GitlabLanguage).ToString().Value())
34+
assert.True(t, attributes.Get(LinguistGenerated).ToBool().Value())
35+
assert.False(t, attributes.Get(LinguistDocumentation).ToBool().Value())
36+
assert.True(t, attributes.Get(LinguistDetectable).ToBool().Value())
37+
}

0 commit comments

Comments
 (0)